2 * $Id: directory.c,v 1.128 2010-01-18 11:45:37 franklahm Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
7 * 19 jan 2000 implemented red-black trees for directory lookups
13 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
25 #define memcpy(d,s,n) bcopy ((s), (d), (n))
26 #define memmove(d,s,n) bcopy ((s), (d), (n))
27 #endif /* ! HAVE_MEMCPY */
28 #endif /* STDC_HEADERS */
37 #include <sys/param.h>
41 #include <atalk/adouble.h>
42 #include <atalk/vfs.h>
43 #include <atalk/afp.h>
44 #include <atalk/util.h>
45 #include <atalk/cnid.h>
46 #include <atalk/logger.h>
47 #include <atalk/uuid.h>
48 #include <atalk/unix.h>
50 #include "directory.h"
61 #ifdef HAVE_NFSv4_ACLS
62 extern void addir_inherit_acl(const struct vol *vol);
69 * There are currently two cache structures where afpd caches directory information
70 * a) a DID/dirname cache in a hashtable
71 * b) a (red-black) tree with CNIDs as key
73 * a) is for searching by DID/dirname
74 * b) is for searching by CNID
76 * Through additional parent, child, previous and next pointers, b) is also used to
77 * represent the on-disk layout of the filesystem. parent and child point to parent
78 * and child directory respectively, linking 2 or more subdirectories in one
79 * directory with previous and next pointers.
81 * Usage examples, highlighting the main functions:
83 * a) is eg used in enumerate():
85 * dir = dirsearch_byname() // search in cache
86 * if (dir == NULL) // not found
87 * dir = adddir() // add to cache
90 * b) is eg used in afp_getfildirparams()
91 * dirlookup() // wrapper for cache and db search
92 * => dir = dirsearch() // search in cache
96 * cnid_resolve() // resolve with CNID database
97 * cname() // add to cache
103 #define SENTINEL (&sentinel)
104 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
105 DIRTREE_COLOR_BLACK, /* color */
106 NULL, NULL, /* parent, child */
107 NULL, NULL, /* previous, next */
108 NULL, 0, 0, /* oforks, did, flags */
109 0, 0, /* ctime, offcnt */
110 NULL, NULL, NULL}; /* mname, uname, ucs2-name */
111 static struct dir rootpar = { SENTINEL, SENTINEL, NULL,
119 /* (from IM: Toolbox Essentials)
120 * dirFinderInfo (DInfo) fields:
122 * frRect 8 folder's window rectangle
124 * frLocation 4 folder's location in window
125 * frView 2 folder's view (default == closedView (256))
127 * extended dirFinderInfo (DXInfo) fields:
128 * frScroll 4 scroll position
129 * frOpenChain: 4 directory ID chain of open folders
130 * frScript: 1 script flag and code
131 * frXFlags: 1 reserved
132 * frComment: 2 comment ID
133 * frPutAway: 4 home directory ID
137 vol_tree_root(const struct vol *vol, u_int32_t did)
141 if (vol->v_curdir && vol->v_curdir->d_did == did) {
151 * redid did assignment for directories. now we use red-black trees.
155 dirsearch(const struct vol *vol, u_int32_t did)
160 /* check for 0 did */
162 afp_errno = AFPERR_PARAM;
165 if ( did == DIRDID_ROOT_PARENT ) {
167 rootpar.d_did = DIRDID_ROOT_PARENT;
168 rootpar.d_child = vol->v_dir;
172 dir = vol_tree_root(vol, did);
174 afp_errno = AFPERR_NOOBJ;
175 while ( dir != SENTINEL ) {
176 if (dir->d_did == did)
177 return dir->d_m_name ? dir : NULL;
178 dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
183 /* ------------------- */
184 int get_afp_errno(const int param)
186 if (afp_errno != AFPERR_DID1)
191 /* ------------------- */
193 dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
195 struct dir *dir = NULL;
197 if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
203 hn = hash_lookup(vol->v_hash, &key);
211 /* -----------------------------------------
212 * if did is not in the cache resolve it with cnid
215 * OSX call it with bogus id, ie file ID not folder ID,
216 * and we are really bad in this case.
219 dirlookup( struct vol *vol, u_int32_t did)
224 static char path[MAXPATHLEN + 1];
227 static char buffer[12 + MAXPATHLEN + 1];
228 int buflen = 12 + MAXPATHLEN + 1;
233 ret = dirsearch(vol, did);
234 if (ret != NULL || afp_errno == AFPERR_PARAM)
237 utf8 = utf8_encoding();
238 maxpath = (utf8)?MAXPATHLEN -7:255;
240 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
241 afp_errno = AFPERR_NOOBJ;
244 ptr = path + MAXPATHLEN;
245 if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
246 afp_errno = AFPERR_NOOBJ;
250 pathlen = len; /* no 0 in the last part */
252 strcpy(ptr - len, mpath);
255 ret = dirsearch(vol,id);
260 if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
262 NULL == (mpath = utompath(vol, upath, cnid, utf8))
264 afp_errno = AFPERR_NOOBJ;
268 len = strlen(mpath) + 1;
270 if (pathlen > maxpath) {
271 afp_errno = AFPERR_PARAM;
274 strcpy(ptr - len, mpath);
278 /* fill the cache, another place where we know about the path type */
284 temp16 = htons(pathlen);
285 memcpy(ptr, &temp16, sizeof(temp16));
287 temp = htonl(kTextEncodingUTF8);
289 memcpy(ptr, &temp, sizeof(temp));
295 *ptr = (unsigned char)pathlen;
299 /* cname is not efficient */
300 if (cname( vol, ret, &ptr ) == NULL )
303 return dirsearch(vol, did);
306 /* child addition/removal */
307 static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
312 b->d_next = a->d_child;
313 b->d_prev = b->d_next->d_prev;
314 b->d_next->d_prev = b;
315 b->d_prev->d_next = b;
317 if (!hash_alloc_insert(vol->v_hash, b, b)) {
318 LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
322 static void dirchildremove(struct dir *a,struct dir *b)
325 a->d_child = (b == b->d_next) ? NULL : b->d_next;
326 b->d_next->d_prev = b->d_prev;
327 b->d_prev->d_next = b->d_next;
328 b->d_next = b->d_prev = b;
331 /* --------------------------- */
332 /* rotate the tree to the left */
333 static void dir_leftrotate(struct vol *vol, struct dir *dir)
335 struct dir *right = dir->d_right;
337 /* whee. move the right's left tree into dir's right tree */
338 dir->d_right = right->d_left;
339 if (right->d_left != SENTINEL)
340 right->d_left->d_back = dir;
342 if (right != SENTINEL) {
343 right->d_back = dir->d_back;
347 if (!dir->d_back) /* no parent. move the right tree to the top. */
349 else if (dir == dir->d_back->d_left) /* we were on the left */
350 dir->d_back->d_left = right;
352 dir->d_back->d_right = right; /* we were on the right */
354 /* re-insert dir on the left tree */
361 /* rotate the tree to the right */
362 static void dir_rightrotate(struct vol *vol, struct dir *dir)
364 struct dir *left = dir->d_left;
366 /* whee. move the left's right tree into dir's left tree */
367 dir->d_left = left->d_right;
368 if (left->d_right != SENTINEL)
369 left->d_right->d_back = dir;
371 if (left != SENTINEL) {
372 left->d_back = dir->d_back;
376 if (!dir->d_back) /* no parent. move the left tree to the top. */
378 else if (dir == dir->d_back->d_right) /* we were on the right */
379 dir->d_back->d_right = left;
381 dir->d_back->d_left = left; /* we were on the left */
383 /* re-insert dir on the right tree */
389 /* recolor after a removal */
390 static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
394 while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
395 /* are we on the left tree? */
396 if (dir == dir->d_back->d_left) {
397 leaf = dir->d_back->d_right; /* get right side */
398 if (leaf->d_color == DIRTREE_COLOR_RED) {
399 /* we're red. we need to change to black. */
400 leaf->d_color = DIRTREE_COLOR_BLACK;
401 dir->d_back->d_color = DIRTREE_COLOR_RED;
402 dir_leftrotate(vol, dir->d_back);
403 leaf = dir->d_back->d_right;
406 /* right leaf has black end nodes */
407 if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
408 (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
409 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
410 dir = dir->d_back; /* ascend */
412 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
413 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
414 leaf->d_color = DIRTREE_COLOR_RED;
415 dir_rightrotate(vol, leaf);
416 leaf = dir->d_back->d_right;
418 leaf->d_color = dir->d_back->d_color;
419 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
420 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
421 dir_leftrotate(vol, dir->d_back);
424 } else { /* right tree */
425 leaf = dir->d_back->d_left; /* left tree */
426 if (leaf->d_color == DIRTREE_COLOR_RED) {
427 leaf->d_color = DIRTREE_COLOR_BLACK;
428 dir->d_back->d_color = DIRTREE_COLOR_RED;
429 dir_rightrotate(vol, dir->d_back);
430 leaf = dir->d_back->d_left;
433 /* left leaf has black end nodes */
434 if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
435 (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
436 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
437 dir = dir->d_back; /* ascend */
439 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
440 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
441 leaf->d_color = DIRTREE_COLOR_RED;
442 dir_leftrotate(vol, leaf);
443 leaf = dir->d_back->d_left;
445 leaf->d_color = dir->d_back->d_color;
446 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
447 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
448 dir_rightrotate(vol, dir->d_back);
453 dir->d_color = DIRTREE_COLOR_BLACK;
459 /* --------------------- */
460 static void dir_hash_del(const struct vol *vol, struct dir *dir)
464 hn = hash_lookup(vol->v_hash, dir);
466 LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
469 hash_delete(vol->v_hash, hn);
473 /* remove the node from the tree. this is just like insertion, but
474 * different. actually, it has to worry about a bunch of things that
475 * insertion doesn't care about. */
477 static void dir_remove( struct vol *vol, struct dir *dir)
480 struct ofork *of, *last;
481 struct dir *node, *leaf;
482 #endif /* REMOVE_NODES */
484 if (!dir || (dir == SENTINEL))
487 /* i'm not sure if it really helps to delete stuff. */
488 dir_hash_del(vol, dir);
489 vol->v_curdir = NULL;
492 dir->d_m_name = NULL;
493 dir->d_u_name = NULL;
494 dir->d_m_name_ucs2 = NULL;
495 #else /* ! REMOVE_NODES */
497 /* go searching for a node with at most one child */
498 if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
502 while (node->d_left != SENTINEL)
507 leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
510 leaf->d_back = node->d_back;
513 } else if (node == node->d_back->d_left) { /* left tree */
514 node->d_back->d_left = leaf;
516 node->d_back->d_right = leaf;
519 /* we want to free node, but we also want to free the data in dir.
520 * currently, that's d_name and the directory traversal bits.
521 * we just copy the necessary bits and then fix up all the
522 * various pointers to the directory. needless to say, there are
523 * a bunch of places that store the directory struct. */
525 struct dir save, *tmp;
527 memcpy(&save, dir, sizeof(save));
528 memcpy(dir, node, sizeof(struct dir));
530 /* restore the red-black bits */
531 dir->d_left = save.d_left;
532 dir->d_right = save.d_right;
533 dir->d_back = save.d_back;
534 dir->d_color = save.d_color;
536 if (node == vol->v_dir) {/* we may need to fix up this pointer */
538 rootpar.d_child = vol->v_dir;
540 /* if we aren't the root directory, we have parents and
541 * siblings to worry about */
542 if (dir->d_parent->d_child == node)
543 dir->d_parent->d_child = dir;
544 dir->d_next->d_prev = dir;
545 dir->d_prev->d_next = dir;
548 /* fix up children. */
552 tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
555 if (node == curdir) /* another pointer to fixup */
558 /* we also need to fix up oforks. bleah */
559 if ((of = dir->d_ofork)) {
560 last = of->of_d_prev;
563 of = (last == of) ? NULL : of->of_d_next;
567 /* set the node's d_name */
568 node->d_m_name = save.d_m_name;
569 node->d_u_name = save.d_u_name;
570 node->d_m_name_ucs2 = save.d_m_name_ucs2;
573 if (node->d_color == DIRTREE_COLOR_BLACK)
574 dir_rmrecolor(vol, leaf);
576 if (node->d_m_name_ucs2)
577 free(node->d_u_name_ucs2);
578 if (node->d_u_name != node->d_m_name) {
579 free(node->d_u_name);
581 free(node->d_m_name);
583 #endif /* ! REMOVE_NODES */
586 /* ---------------------------------------
587 * remove the node and its childs from the tree
589 * FIXME what about opened forks with refs to it?
590 * it's an afp specs violation because you can't delete
591 * an opened forks. Now afpd doesn't care about forks opened by other
592 * process. It's fixable within afpd if fnctl_lock, doable with smb and
593 * next to impossible for nfs and local filesystem access.
595 static void dir_invalidate( struct vol *vol, struct dir *dir)
598 /* v_root can't be deleted */
599 if (movecwd(vol, vol->v_root) < 0) {
600 LOG(log_error, logtype_afpd, "cname can't chdir to : %s", vol->v_root);
604 dirchildremove(dir->d_parent, dir);
605 dir_remove( vol, dir );
608 /* ------------------------------------ */
609 static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
613 pdir = vol_tree_root(vol, dir->d_did);
614 while (pdir->d_did != dir->d_did ) {
615 if ( pdir->d_did > dir->d_did ) {
616 if ( pdir->d_left == SENTINEL ) {
623 if ( pdir->d_right == SENTINEL ) {
628 pdir = pdir->d_right;
634 #define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/"
637 caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
642 static u_int32_t did = 0;
643 static char cname[MAXPATHLEN];
644 static char lname[MAXPATHLEN];
645 ucs2_t u2_path[MAXPATHLEN];
646 ucs2_t u2_dename[MAXPATHLEN];
647 char *tmp, *savepath;
649 if (!(vol->v_flags & AFPVOL_CASEINSEN))
652 if (veto_file(ENUMVETO, path->u_name))
655 savepath = path->u_name;
657 /* very simple cache */
658 if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
659 path->u_name = cname;
661 if (of_stat( path ) == 0 ) {
664 /* something changed, we cannot stat ... */
668 if (NULL == ( dp = opendir( "." )) ) {
669 LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name);
674 /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
675 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) )
676 LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
678 /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
680 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
681 if (NULL == check_dirent(vol, de->d_name))
684 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) )
687 if (strcasecmp_w( u2_path, u2_dename) == 0) {
689 strlcpy(cname, de->d_name, sizeof(cname));
690 path->u_name = cname;
692 if (of_stat( path ) == 0 ) {
693 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
694 strlcpy(lname, tmp, sizeof(lname));
707 /* invalidate cache */
710 path->u_name = savepath;
712 /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */
718 * attempt to extend the current dir. tree to include path
719 * as a side-effect, movecwd to that point and return the new dir
722 extenddir(struct vol *vol, struct dir *dir, struct path *path)
726 if ( path->u_name == NULL) {
727 afp_errno = AFPERR_PARAM;
731 if (check_name(vol, path->u_name)) {
732 /* the name is illegal */
733 LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name);
735 afp_errno = AFPERR_PARAM;
739 if (of_stat( path ) != 0 ) {
740 if (!(vol->v_flags & AFPVOL_CASEINSEN))
742 else if(caseenumerate(vol, path, dir) != 0)
746 if (!S_ISDIR(path->st.st_mode)) {
750 /* mac name is always with the right encoding (from cname()) */
751 if (( dir = adddir( vol, dir, path)) == NULL ) {
756 if ( movecwd( vol, dir ) < 0 ) {
763 /* -------------------------
764 appledouble mkdir afp error code.
766 static int netatalk_mkdir(const char *name)
768 if (ad_mkdir(name, DIRBITS | 0777) < 0) {
771 return( AFPERR_NOOBJ );
773 return( AFPERR_VLOCK );
776 return( AFPERR_ACCESS );
778 return( AFPERR_EXIST );
781 return( AFPERR_DFULL );
783 return( AFPERR_PARAM );
789 /* ------------------- */
790 static int deletedir(char *dir)
792 char path[MAXPATHLEN + 1];
800 if ((len = strlen(dir)) +2 > sizeof(path))
804 if ((dp = opendir(dir)) == NULL)
810 remain = sizeof(path) -len -1;
811 while ((de = readdir(dp)) && err == AFP_OK) {
812 /* skip this and previous directory */
813 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
816 if (strlen(de->d_name) > remain) {
820 strcpy(path + len, de->d_name);
821 if (stat(path, &st)) {
824 if (S_ISDIR(st.st_mode)) {
825 err = deletedir(path);
827 err = netatalk_unlink(path);
832 /* okay. the directory is empty. delete it. note: we already got rid
835 err = netatalk_rmdir(dir);
840 /* do a recursive copy. */
841 static int copydir(const struct vol *vol, char *src, char *dst)
843 char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
852 /* doesn't exist or the path is too long. */
853 if (((slen = strlen(src)) > sizeof(spath) - 2) ||
854 ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
855 ((dp = opendir(src)) == NULL))
858 /* try to create the destination directory */
859 if (AFP_OK != (err = netatalk_mkdir(dst)) ) {
864 /* set things up to copy */
868 srem = sizeof(spath) - slen -1;
873 drem = sizeof(dpath) - dlen -1;
876 while ((de = readdir(dp))) {
877 /* skip this and previous directory */
878 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
881 if (strlen(de->d_name) > srem) {
885 strcpy(spath + slen, de->d_name);
887 if (stat(spath, &st) == 0) {
888 if (strlen(de->d_name) > drem) {
892 strcpy(dpath + dlen, de->d_name);
894 if (S_ISDIR(st.st_mode)) {
895 if (AFP_OK != (err = copydir(vol, spath, dpath)))
897 } else if (AFP_OK != (err = copyfile(vol, vol, spath, dpath, NULL, NULL))) {
901 /* keep the same time stamp. */
902 ut.actime = ut.modtime = st.st_mtime;
908 /* keep the same time stamp. */
909 if (stat(src, &st) == 0) {
910 ut.actime = ut.modtime = st.st_mtime;
920 /* --- public functions follow --- */
922 /* NOTE: we start off with at least one node (the root directory). */
923 static struct dir *dirinsert(struct vol *vol, struct dir *dir)
927 if ((node = dir_insert(vol, dir)))
930 /* recolor the tree. the current node is red. */
931 dir->d_color = DIRTREE_COLOR_RED;
933 /* parent of this node has to be black. if the parent node
934 * is red, then we have a grandparent. */
935 while ((dir != vol->v_root) &&
936 (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
937 /* are we on the left tree? */
938 if (dir->d_back == dir->d_back->d_back->d_left) {
939 node = dir->d_back->d_back->d_right; /* get the right node */
940 if (node->d_color == DIRTREE_COLOR_RED) {
941 /* we're red. we need to change to black. */
942 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
943 node->d_color = DIRTREE_COLOR_BLACK;
944 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
945 dir = dir->d_back->d_back; /* finished. go up. */
947 if (dir == dir->d_back->d_right) {
949 dir_leftrotate(vol, dir);
951 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
952 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
953 dir_rightrotate(vol, dir->d_back->d_back);
956 node = dir->d_back->d_back->d_left;
957 if (node->d_color == DIRTREE_COLOR_RED) {
958 /* we're red. we need to change to black. */
959 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
960 node->d_color = DIRTREE_COLOR_BLACK;
961 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
962 dir = dir->d_back->d_back; /* finished. ascend */
964 if (dir == dir->d_back->d_left) {
966 dir_rightrotate(vol, dir);
968 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
969 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
970 dir_leftrotate(vol, dir->d_back->d_back);
975 vol->v_root->d_color = DIRTREE_COLOR_BLACK;
979 /* ---------------------------- */
981 adddir(struct vol *vol, struct dir *dir, struct path *path)
983 struct dir *cdir, *edir;
991 upath = path->u_name;
993 upathlen = strlen(upath);
995 id = get_id(vol, NULL, st, dir->d_did, upath, upathlen);
999 if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
1002 name = path->m_name;
1003 if ((cdir = dirnew(name, upath)) == NULL) {
1004 LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
1007 if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, path->m_name, -1, (char **)&cdir->d_m_name_ucs2)) {
1008 LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
1009 cdir->d_m_name_ucs2 = NULL;
1014 if ((edir = dirinsert( vol, cdir ))) {
1015 /* it's not possible with LASTDID
1017 - someone else have moved the directory.
1018 - it's a symlink inside the share.
1019 - it's an ID reused, the old directory was deleted but not
1020 the cnid record and the server've reused the inode for
1022 for HASH (we should get ride of HASH)
1023 - someone else have moved the directory.
1024 - it's an ID reused as above
1025 - it's a hash duplicate and we are in big trouble
1027 deleted = (edir->d_m_name == NULL);
1029 dir_hash_del(vol, edir);
1031 edir->d_m_name = cdir->d_m_name;
1032 edir->d_u_name = cdir->d_u_name;
1033 edir->d_m_name_ucs2 = cdir->d_m_name_ucs2;
1036 LOG(log_error, logtype_afpd, "adddir: insert %s", edir->d_m_name);
1037 if (!cdir->d_parent || (cdir->d_parent == dir && !deleted)) {
1038 hash_alloc_insert(vol->v_hash, cdir, cdir);
1041 /* the old was not in the same folder */
1043 dirchildremove(cdir->d_parent, cdir);
1046 /* parent/child directories */
1047 cdir->d_parent = dir;
1048 dirchildadd(vol, dir, cdir);
1052 /* --- public functions follow --- */
1053 /* free everything down. we don't bother to recolor as this is only
1054 * called to free the entire tree */
1055 void dirfreename(struct dir *dir)
1057 if (dir->d_u_name != dir->d_m_name) {
1058 free(dir->d_u_name);
1060 if (dir->d_m_name_ucs2)
1061 free(dir->d_m_name_ucs2);
1062 free(dir->d_m_name);
1065 void dirfree(struct dir *dir)
1067 if (!dir || (dir == SENTINEL))
1070 if ( dir->d_left != SENTINEL ) {
1071 dirfree( dir->d_left );
1073 if ( dir->d_right != SENTINEL ) {
1074 dirfree( dir->d_right );
1077 if (dir != SENTINEL) {
1083 /* --------------------------------------------
1084 * most of the time mac name and unix name are the same
1086 struct dir *dirnew(const char *m_name, const char *u_name)
1090 dir = (struct dir *) calloc(1, sizeof( struct dir ));
1094 if ((dir->d_m_name = strdup(m_name)) == NULL) {
1099 if (m_name == u_name || !strcmp(m_name, u_name)) {
1100 dir->d_u_name = dir->d_m_name;
1102 else if ((dir->d_u_name = strdup(u_name)) == NULL) {
1103 free(dir->d_m_name);
1108 dir->d_m_name_ucs2 = NULL;
1109 dir->d_left = dir->d_right = SENTINEL;
1110 dir->d_next = dir->d_prev = dir;
1114 /* ------------------ */
1115 static hash_val_t hash_fun_dir(const void *key)
1117 const struct dir *k = key;
1119 static unsigned long randbox[] = {
1120 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
1121 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
1122 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
1123 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
1126 const unsigned char *str = (unsigned char *)(k->d_u_name);
1127 hash_val_t acc = k->d_parent->d_did;
1130 acc ^= randbox[(*str + acc) & 0xf];
1131 acc = (acc << 1) | (acc >> 31);
1133 acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
1134 acc = (acc << 2) | (acc >> 30);
1141 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
1142 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
1143 #define get16bits(d) (*((const uint16_t *) (d)))
1146 #if !defined (get16bits)
1147 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
1148 +(uint32_t)(((const uint8_t *)(d))[0]) )
1151 static hash_val_t hash_fun2_dir(const void *key)
1153 const struct dir *k = key;
1154 const char *data = k->d_u_name;
1155 int len = strlen(k->d_u_name);
1156 hash_val_t hash = k->d_parent->d_did, tmp;
1162 for (;len > 0; len--) {
1163 hash += get16bits (data);
1164 tmp = (get16bits (data+2) << 11) ^ hash;
1165 hash = (hash << 16) ^ tmp;
1166 data += 2*sizeof (uint16_t);
1170 /* Handle end cases */
1172 case 3: hash += get16bits (data);
1174 hash ^= data[sizeof (uint16_t)] << 18;
1177 case 2: hash += get16bits (data);
1181 case 1: hash += *data;
1186 /* Force "avalanching" of final 127 bits */
1197 /* ---------------- */
1198 static int hash_comp_dir(const void *key1, const void *key2)
1200 const struct dir *k1 = key1;
1201 const struct dir *k2 = key2;
1203 return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
1206 /* ---------------- */
1210 return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
1213 /* ------------------ */
1214 static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
1217 movecwd failed some of dir path are not there anymore.
1218 FIXME Is it true with other errors?
1219 so we remove dir from the cache
1221 if (dir->d_did == DIRDID_ROOT_PARENT)
1223 if (afp_errno == AFPERR_ACCESS) {
1224 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1227 /* FIXME should we set these?, don't need to call stat() after:
1229 ret->st_errno = EACCES;
1231 ret->m_name = dir->d_m_name;
1232 ret->u_name = dir->d_u_name;
1235 } else if (afp_errno == AFPERR_NOOBJ) {
1236 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1239 strcpy(ret->m_name, dir->d_m_name);
1240 if (dir->d_m_name == dir->d_u_name) {
1241 ret->u_name = ret->m_name;
1244 size_t tp = strlen(ret->m_name)+1;
1246 ret->u_name = ret->m_name +tp;
1247 strcpy(ret->u_name, dir->d_u_name);
1249 /* FIXME should we set :
1251 ret->st_errno = ENOENT;
1253 dir_invalidate(vol, dir);
1256 dir_invalidate(vol, dir);
1260 /* -------------------------------------------------- */
1266 stat the file or errno
1269 curdir: filename parent directory
1275 stat the dir or errno
1279 curdir: dir parent directory
1287 curdir: dir parent directory
1294 cname(struct vol *vol, struct dir *dir, char **cpath)
1296 struct dir *cdir, *scdir=NULL;
1297 static char path[ MAXPATHLEN + 1];
1298 static struct path ret;
1310 afp_errno = AFPERR_NOOBJ;
1311 memset(&ret, 0, sizeof(ret));
1312 switch (ret.m_type = *data) { /* path type */
1315 len = (unsigned char) *data++;
1318 if (afp_version >= 30) {
1324 if (afp_version >= 30) {
1326 memcpy(&hint, data, sizeof(hint));
1328 data += sizeof(hint);
1330 memcpy(&len16, data, sizeof(len16));
1337 /* else it's an error */
1339 afp_errno = AFPERR_PARAM;
1342 *cpath += len + size;
1347 if (movecwd( vol, dir ) < 0 ) {
1348 return invalidate(vol, dir, &ret );
1350 if (*path == '\0') {
1357 if (*data == sep ) {
1361 while (*data == sep && len > 0 ) {
1362 if ( dir->d_parent == NULL ) {
1365 dir = dir->d_parent;
1370 /* would this be faster with strlen + strncpy? */
1372 while ( *data != sep && len > 0 ) {
1374 if (p > &path[ MAXPATHLEN]) {
1375 afp_errno = AFPERR_PARAM;
1381 /* short cut bits by chopping off a trailing \0. this also
1382 makes the traversal happy w/ filenames at the end of the
1389 if ( p == path ) { /* end of the name parameter */
1393 if (afp_version >= 30) {
1398 static char temp[ MAXPATHLEN + 1];
1400 if (dir->d_did == DIRDID_ROOT_PARENT) {
1402 With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
1403 So we compare it with the longname from the current volume and if they match
1404 we overwrite the requested path with the utf8 volume name so that the following
1407 ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
1408 if (strcasecmp( path, temp) == 0)
1409 ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
1412 if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
1413 afp_errno = AFPERR_PARAM;
1419 /* check for OS X mangled filename :( */
1421 t = demangle_osx(vol, path, dir->d_did, &fileid);
1424 /* duplicate work but we can't reuse all convert_char we did in demangle_osx
1425 * flags weren't the same
1427 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
1428 /* at last got our view of mac name */
1433 if (ret.u_name == NULL) {
1434 if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
1435 afp_errno = AFPERR_PARAM;
1441 cdir = dir->d_child;
1443 if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
1444 (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
1445 CH_UCS2, path, -1, (char **)&tmpname) )
1448 if (!cdir->d_m_name_ucs2) {
1449 LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
1450 /* this shouldn't happen !!!! */
1454 if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1457 if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1460 cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
1466 if (dir->d_did == DIRDID_ROOT_PARENT) {
1468 root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
1469 must check against the volume name.
1471 if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
1477 cdir = dirsearch_byname(vol, dir, ret.u_name);
1481 if (cdir == NULL && scdir != NULL) {
1483 /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
1486 if ( cdir == NULL ) {
1488 /* if dir == curdir it always succeed,
1489 even if curdir is deleted.
1490 it's not a pb because it will fail in extenddir
1492 if ( movecwd( vol, dir ) < 0 ) {
1493 /* dir is not valid anymore
1494 we delete dir from the cache and abort.
1496 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1497 afp_errno = AFPERR_NOOBJ;
1500 if (afp_errno == AFPERR_ACCESS)
1502 dir_invalidate(vol, dir);
1505 cdir = extenddir( vol, dir, &ret );
1509 cdir = extenddir( vol, dir, &ret );
1510 } /* if (!extend) */
1512 if ( cdir == NULL ) {
1514 if ( len > 0 || !ret.u_name ) {
1526 * Move curdir to dir, with a possible chdir()
1528 int movecwd(struct vol *vol, struct dir *dir)
1530 char path[MAXPATHLEN + 1];
1535 if ( dir == curdir ) {
1538 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1539 afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
1543 p = path + sizeof(path) - 1;
1546 for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
1549 /* parent directory is deleted */
1550 afp_errno = AFPERR_NOOBJ;
1554 if (p -n -1 < path) {
1555 afp_errno = AFPERR_PARAM;
1562 if ( d != curdir ) {
1563 n = strlen( vol->v_path );
1564 if (p -n -1 < path) {
1565 afp_errno = AFPERR_PARAM;
1570 memcpy( p, vol->v_path, n );
1572 if ( chdir( p ) < 0 ) {
1576 afp_errno = AFPERR_ACCESS;
1579 afp_errno = AFPERR_NOOBJ;
1584 vol->v_curdir = curdir = dir;
1589 * We can't use unix file's perm to support Apple's inherited protection modes.
1590 * If we aren't the file's owner we can't change its perms when moving it and smb
1591 * nfs,... don't even try.
1593 #define AFP_CHECK_ACCESS
1595 int check_access(char *path, int mode)
1597 #ifdef AFP_CHECK_ACCESS
1605 accessmode(p, &ma, curdir, NULL);
1606 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1608 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1614 /* --------------------- */
1615 int file_access(struct path *path, int mode)
1619 accessmode(path->u_name, &ma, curdir, &path->st);
1620 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1622 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1628 /* --------------------- */
1629 void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
1631 dir->offcnt = count;
1632 dir->ctime = st->st_ctime;
1633 dir->d_flags &= ~DIRF_CNID;
1636 /* ---------------------
1637 * is our cached offspring count valid?
1640 static int diroffcnt(struct dir *dir, struct stat *st)
1642 return st->st_ctime == dir->ctime;
1645 /* ---------------------
1646 * is our cached also for reenumerate id?
1649 int dirreenumerate(struct dir *dir, struct stat *st)
1651 return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
1654 /* --------------------- */
1655 static int invisible_dots(const struct vol *vol, const char *name)
1657 return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
1660 /* ------------------------------
1662 (name, dir) with curdir:name == dir, from afp_enumerate
1665 int getdirparams(const struct vol *vol,
1666 u_int16_t bitmap, struct path *s_path,
1668 char *buf, size_t *buflen )
1672 char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
1673 int bit = 0, isad = 0;
1679 struct stat *st = &s_path->st;
1680 char *upath = s_path->u_name;
1682 if ((bitmap & ((1 << DIRPBIT_ATTR) |
1683 (1 << DIRPBIT_CDATE) |
1684 (1 << DIRPBIT_MDATE) |
1685 (1 << DIRPBIT_BDATE) |
1686 (1 << DIRPBIT_FINFO)))) {
1688 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1689 if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
1691 if (ad.ad_md->adf_flags & O_CREAT) {
1692 /* We just created it */
1693 ad_setname(&ad, s_path->m_name);
1698 dir->d_parent->d_did,
1705 if ( dir->d_did == DIRDID_ROOT) {
1706 pdid = DIRDID_ROOT_PARENT;
1707 } else if (dir->d_did == DIRDID_ROOT_PARENT) {
1710 pdid = dir->d_parent->d_did;
1714 while ( bitmap != 0 ) {
1715 while (( bitmap & 1 ) == 0 ) {
1723 ad_getattr(&ad, &ashort);
1724 } else if (invisible_dots(vol, dir->d_u_name)) {
1725 ashort = htons(ATTRBIT_INVISIBLE);
1728 ashort |= htons(ATTRBIT_SHARED);
1729 memcpy( data, &ashort, sizeof( ashort ));
1730 data += sizeof( ashort );
1734 memcpy( data, &pdid, sizeof( pdid ));
1735 data += sizeof( pdid );
1738 case DIRPBIT_CDATE :
1739 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1740 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1741 memcpy( data, &aint, sizeof( aint ));
1742 data += sizeof( aint );
1745 case DIRPBIT_MDATE :
1746 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1747 memcpy( data, &aint, sizeof( aint ));
1748 data += sizeof( aint );
1751 case DIRPBIT_BDATE :
1752 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
1753 aint = AD_DATE_START;
1754 memcpy( data, &aint, sizeof( aint ));
1755 data += sizeof( aint );
1758 case DIRPBIT_FINFO :
1760 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
1761 } else { /* no appledouble */
1762 memset( data, 0, 32 );
1763 /* set default view -- this also gets done in ad_open() */
1764 ashort = htons(FINDERINFO_CLOSEDVIEW);
1765 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
1767 /* dot files are by default visible */
1768 if (invisible_dots(vol, dir->d_u_name)) {
1769 ashort = htons(FINDERINFO_INVISIBLE);
1770 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
1776 case DIRPBIT_LNAME :
1777 if (dir->d_m_name) /* root of parent can have a null name */
1780 memset(data, 0, sizeof(u_int16_t));
1781 data += sizeof( u_int16_t );
1784 case DIRPBIT_SNAME :
1785 memset(data, 0, sizeof(u_int16_t));
1786 data += sizeof( u_int16_t );
1790 memcpy( data, &dir->d_did, sizeof( aint ));
1791 data += sizeof( aint );
1794 case DIRPBIT_OFFCNT :
1796 /* this needs to handle current directory access rights */
1797 if (diroffcnt(dir, st)) {
1798 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1800 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
1801 setdiroffcnt(dir, st, ret);
1802 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1804 ashort = htons( ashort );
1805 memcpy( data, &ashort, sizeof( ashort ));
1806 data += sizeof( ashort );
1810 aint = htonl(st->st_uid);
1811 memcpy( data, &aint, sizeof( aint ));
1812 data += sizeof( aint );
1816 aint = htonl(st->st_gid);
1817 memcpy( data, &aint, sizeof( aint ));
1818 data += sizeof( aint );
1821 case DIRPBIT_ACCESS :
1822 accessmode( upath, &ma, dir , st);
1824 *data++ = ma.ma_user;
1825 *data++ = ma.ma_world;
1826 *data++ = ma.ma_group;
1827 *data++ = ma.ma_owner;
1830 /* Client has requested the ProDOS information block.
1831 Just pass back the same basic block for all
1832 directories. <shirsch@ibm.net> */
1833 case DIRPBIT_PDINFO :
1834 if (afp_version >= 30) { /* UTF8 name */
1835 utf8 = kTextEncodingUTF8;
1836 if (dir->d_m_name) /* root of parent can have a null name */
1839 memset(data, 0, sizeof(u_int16_t));
1840 data += sizeof( u_int16_t );
1842 memcpy(data, &aint, sizeof( aint ));
1843 data += sizeof( aint );
1845 else { /* ProDOS Info Block */
1848 ashort = htons( 0x0200 );
1849 memcpy( data, &ashort, sizeof( ashort ));
1850 data += sizeof( ashort );
1851 memset( data, 0, sizeof( ashort ));
1852 data += sizeof( ashort );
1856 case DIRPBIT_UNIXPR :
1857 aint = htonl(st->st_uid);
1858 memcpy( data, &aint, sizeof( aint ));
1859 data += sizeof( aint );
1860 aint = htonl(st->st_gid);
1861 memcpy( data, &aint, sizeof( aint ));
1862 data += sizeof( aint );
1865 aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
1866 memcpy( data, &aint, sizeof( aint ));
1867 data += sizeof( aint );
1869 accessmode( upath, &ma, dir , st);
1871 *data++ = ma.ma_user;
1872 *data++ = ma.ma_world;
1873 *data++ = ma.ma_group;
1874 *data++ = ma.ma_owner;
1879 ad_close_metadata( &ad );
1881 return( AFPERR_BITMAP );
1887 ashort = htons( data - buf );
1888 memcpy( l_nameoff, &ashort, sizeof( ashort ));
1889 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, 0);
1891 if ( utf_nameoff ) {
1892 ashort = htons( data - buf );
1893 memcpy( utf_nameoff, &ashort, sizeof( ashort ));
1894 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, utf8);
1897 ad_close_metadata( &ad );
1899 *buflen = data - buf;
1903 /* ----------------------------- */
1904 int path_error(struct path *path, int error)
1906 /* - a dir with access error
1907 * - no error it's a file
1910 if (path_isadir(path))
1912 if (path->st_valid && path->st_errno)
1914 return AFPERR_BADTYPE ;
1917 /* ----------------------------- */
1918 int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1923 u_int16_t vid, bitmap;
1929 memcpy( &vid, ibuf, sizeof( vid ));
1930 ibuf += sizeof( vid );
1932 if (NULL == ( vol = getvolbyvid( vid )) ) {
1933 return( AFPERR_PARAM );
1936 if (vol->v_flags & AFPVOL_RO)
1937 return AFPERR_VLOCK;
1939 memcpy( &did, ibuf, sizeof( did ));
1940 ibuf += sizeof( int );
1942 if (NULL == ( dir = dirlookup( vol, did )) ) {
1946 memcpy( &bitmap, ibuf, sizeof( bitmap ));
1947 bitmap = ntohs( bitmap );
1948 ibuf += sizeof( bitmap );
1950 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1951 return get_afp_errno(AFPERR_NOOBJ);
1954 if ( *path->m_name != '\0' ) {
1955 rc = path_error(path, AFPERR_NOOBJ);
1956 /* maybe we are trying to set perms back */
1957 if (rc != AFPERR_ACCESS)
1962 * If ibuf is odd, make it even.
1964 if ((u_long)ibuf & 1 ) {
1968 if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
1969 setvoltime(obj, vol );
1975 * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
1977 * assume path == '\0' eg. it's a directory in canonical form
1980 struct path Cur_Path = {
1983 ".", /* unix name */
1985 NULL,/* struct dir */
1986 0, /* stat is not set */
1989 /* ------------------ */
1990 static int set_dir_errors(struct path *path, const char *where, int err)
1995 return AFPERR_ACCESS;
1997 return AFPERR_VLOCK;
1999 LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
2000 return AFPERR_PARAM;
2003 /* ------------------ */
2004 int setdirparams(struct vol *vol,
2005 struct path *path, u_int16_t d_bitmap, char *buf )
2017 u_int16_t ashort, bshort;
2019 int change_mdate = 0;
2020 int change_parent_mdate = 0;
2022 u_int16_t bitmap = d_bitmap;
2023 u_char finder_buf[32];
2026 u_int16_t upriv_bit = 0;
2029 upath = path->u_name;
2031 while ( bitmap != 0 ) {
2032 while (( bitmap & 1 ) == 0 ) {
2040 memcpy( &ashort, buf, sizeof( ashort ));
2041 buf += sizeof( ashort );
2043 case DIRPBIT_CDATE :
2045 memcpy(&cdate, buf, sizeof(cdate));
2046 buf += sizeof( cdate );
2048 case DIRPBIT_MDATE :
2049 memcpy(&newdate, buf, sizeof(newdate));
2050 buf += sizeof( newdate );
2052 case DIRPBIT_BDATE :
2054 memcpy(&bdate, buf, sizeof(bdate));
2055 buf += sizeof( bdate );
2057 case DIRPBIT_FINFO :
2059 memcpy( finder_buf, buf, 32 );
2062 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2063 change_parent_mdate = 1;
2064 memcpy( &owner, buf, sizeof(owner));
2065 buf += sizeof( owner );
2068 change_parent_mdate = 1;
2069 memcpy( &group, buf, sizeof( group ));
2070 buf += sizeof( group );
2072 case DIRPBIT_ACCESS :
2074 change_parent_mdate = 1;
2075 ma.ma_user = *buf++;
2076 ma.ma_world = *buf++;
2077 ma.ma_group = *buf++;
2078 ma.ma_owner = *buf++;
2079 mpriv = mtoumode( &ma ) | vol->v_dperm;
2080 if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2081 err = set_dir_errors(path, "setdirmode", errno);
2085 /* Ignore what the client thinks we should do to the
2086 ProDOS information block. Skip over the data and
2087 report nothing amiss. <shirsch@ibm.net> */
2088 case DIRPBIT_PDINFO :
2089 if (afp_version < 30) {
2093 err = AFPERR_BITMAP;
2097 case DIRPBIT_UNIXPR :
2098 if (vol_unix_priv(vol)) {
2099 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
2100 buf += sizeof( owner );
2101 memcpy( &group, buf, sizeof( group ));
2102 buf += sizeof( group );
2105 change_parent_mdate = 1;
2106 memcpy( &upriv, buf, sizeof( upriv ));
2107 buf += sizeof( upriv );
2108 upriv = ntohl (upriv) | vol->v_dperm;
2109 if (dir_rx_set(upriv)) {
2110 /* maybe we are trying to set perms back */
2111 if ( setdirunixmode(vol, upath, upriv) < 0 ) {
2113 err = set_dir_errors(path, "setdirunixmode", errno);
2124 err = AFPERR_BITMAP;
2132 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2134 if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
2136 * Check to see what we're trying to set. If it's anything
2137 * but ACCESS, UID, or GID, give an error. If it's any of those
2138 * three, we don't need the ad to be open, so just continue.
2140 * note: we also don't need to worry about mdate. also, be quiet
2141 * if we're using the noadouble option.
2143 if (!vol_noadouble(vol) && (d_bitmap &
2144 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
2145 (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
2146 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
2147 return AFPERR_ACCESS;
2153 * Check to see if a create was necessary. If it was, we'll want
2154 * to set our name, etc.
2156 if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
2157 ad_setname(&ad, curdir->d_m_name);
2163 while ( bitmap != 0 ) {
2164 while (( bitmap & 1 ) == 0 ) {
2172 ad_getattr(&ad, &bshort);
2173 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
2174 (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
2175 change_parent_mdate = 1;
2176 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
2177 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
2181 ad_setattr(&ad, bshort);
2184 case DIRPBIT_CDATE :
2186 ad_setdate(&ad, AD_DATE_CREATE, cdate);
2189 case DIRPBIT_MDATE :
2191 case DIRPBIT_BDATE :
2193 ad_setdate(&ad, AD_DATE_BACKUP, bdate);
2196 case DIRPBIT_FINFO :
2198 /* Fixes #2802236 */
2199 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
2200 *fflags &= htons(~FINDERINFO_ISHARED);
2202 if ( dir->d_did == DIRDID_ROOT ) {
2204 * Alright, we admit it, this is *really* sick!
2205 * The 4 bytes that we don't copy, when we're dealing
2206 * with the root of a volume, are the directory's
2207 * location information. This eliminates that annoying
2208 * behavior one sees when mounting above another mount
2211 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
2212 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
2214 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
2218 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2219 if ( (dir->d_did == DIRDID_ROOT) &&
2220 (setdeskowner( ntohl(owner), -1 ) < 0)) {
2221 err = set_dir_errors(path, "setdeskowner", errno);
2222 if (isad && err == AFPERR_PARAM) {
2223 err = AFP_OK; /* ???*/
2226 goto setdirparam_done;
2229 if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
2230 err = set_dir_errors(path, "setdirowner", errno);
2231 goto setdirparam_done;
2235 if (dir->d_did == DIRDID_ROOT)
2236 setdeskowner( -1, ntohl(group) );
2237 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2238 err = set_dir_errors(path, "setdirowner", errno);
2239 goto setdirparam_done;
2242 case DIRPBIT_ACCESS :
2243 if (dir->d_did == DIRDID_ROOT) {
2245 if (!dir_rx_set(mpriv)) {
2246 /* we can't remove read and search for owner on volume root */
2247 err = AFPERR_ACCESS;
2248 goto setdirparam_done;
2252 if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2253 err = set_dir_errors(path, "setdirmode", errno);
2254 goto setdirparam_done;
2257 case DIRPBIT_PDINFO :
2258 if (afp_version >= 30) {
2259 err = AFPERR_BITMAP;
2260 goto setdirparam_done;
2263 case DIRPBIT_UNIXPR :
2264 if (vol_unix_priv(vol)) {
2265 if (dir->d_did == DIRDID_ROOT) {
2266 if (!dir_rx_set(upriv)) {
2267 /* we can't remove read and search for owner on volume root */
2268 err = AFPERR_ACCESS;
2269 goto setdirparam_done;
2271 setdeskowner( -1, ntohl(group) );
2272 setdeskmode( upriv );
2274 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2275 err = set_dir_errors(path, "setdirowner", errno);
2276 goto setdirparam_done;
2279 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
2280 err = set_dir_errors(path, "setdirunixmode", errno);
2281 goto setdirparam_done;
2285 err = AFPERR_BITMAP;
2286 goto setdirparam_done;
2290 err = AFPERR_BITMAP;
2291 goto setdirparam_done;
2300 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
2301 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2305 ad_setdate(&ad, AD_DATE_MODIFY, newdate);
2306 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
2311 if (path->st_valid && !path->st_errno) {
2312 struct stat *st = &path->st;
2314 if (dir && dir->d_parent) {
2315 ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_parent->d_did, vol->v_stamp);
2319 ad_close_metadata( &ad);
2322 if (change_parent_mdate && dir->d_did != DIRDID_ROOT
2323 && gettimeofday(&tv, NULL) == 0) {
2324 if (!movecwd(vol, dir->d_parent)) {
2325 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2326 /* be careful with bitmap because now dir is null */
2327 bitmap = 1<<DIRPBIT_MDATE;
2328 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
2329 /* should we reset curdir ?*/
2336 int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2350 memcpy( &vid, ibuf, sizeof( vid ));
2351 ibuf += sizeof( vid );
2352 if (NULL == (vol = getvolbyvid( vid )) ) {
2353 return( AFPERR_PARAM );
2356 memcpy( &did, ibuf, sizeof( did ));
2357 ibuf += sizeof( did );
2361 * if it's CNID 2 our only choice to meet the specs is call sync.
2362 * For any other CNID just sync that dir. To my knowledge the
2363 * intended use of FPSyncDir is to sync the volume so all we're
2364 * ever going to see here is probably CNID 2. Anyway, we' prepared.
2367 if ( ntohl(did) == 2 ) {
2370 if (NULL == ( dir = dirlookup( vol, did )) ) {
2371 return afp_errno; /* was AFPERR_NOOBJ */
2374 if (movecwd( vol, dir ) < 0 )
2375 return ( AFPERR_NOOBJ );
2378 * Assuming only OSens that have dirfd also may require fsyncing directories
2379 * in order to flush metadata e.g. Linux.
2383 if (NULL == ( dp = opendir( "." )) ) {
2386 return( AFPERR_NOOBJ );
2388 return( AFPERR_ACCESS );
2390 return( AFPERR_PARAM );
2394 LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
2397 if ( fsync ( dfd ) < 0 )
2398 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2399 dir->d_u_name, strerror(errno) );
2400 closedir(dp); /* closes dfd too */
2403 if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
2406 return( AFPERR_NOOBJ );
2408 return( AFPERR_ACCESS );
2410 return( AFPERR_PARAM );
2414 LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
2415 vol->ad_path(".", ADFLAGS_DIR) );
2417 if ( fsync(dfd) < 0 )
2418 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2419 vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
2426 int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2432 struct path *s_path;
2440 memcpy( &vid, ibuf, sizeof( vid ));
2441 ibuf += sizeof( vid );
2442 if (NULL == ( vol = getvolbyvid( vid )) ) {
2443 return( AFPERR_PARAM );
2446 if (vol->v_flags & AFPVOL_RO)
2447 return AFPERR_VLOCK;
2449 memcpy( &did, ibuf, sizeof( did ));
2450 ibuf += sizeof( did );
2451 if (NULL == ( dir = dirlookup( vol, did )) ) {
2452 return afp_errno; /* was AFPERR_NOOBJ */
2454 /* for concurrent access we need to be sure we are not in the
2455 * folder we want to create...
2459 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
2460 return get_afp_errno(AFPERR_PARAM);
2462 /* cname was able to move curdir to it! */
2463 if (*s_path->m_name == '\0')
2464 return AFPERR_EXIST;
2466 upath = s_path->u_name;
2468 if (AFP_OK != (err = netatalk_mkdir( upath))) {
2472 if (of_stat(s_path) < 0) {
2476 if ((dir = adddir( vol, curdir, s_path)) == NULL) {
2480 if ( movecwd( vol, dir ) < 0 ) {
2481 return( AFPERR_PARAM );
2484 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2485 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
2486 if (vol_noadouble(vol))
2487 goto createdir_done;
2488 return( AFPERR_ACCESS );
2490 ad_setname(&ad, s_path->m_name);
2491 ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
2494 ad_close_metadata( &ad);
2497 #ifdef HAVE_NFSv4_ACLS
2498 /* FIXME: are we really inside the created dir? */
2499 addir_inherit_acl(vol);
2502 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
2503 *rbuflen = sizeof( u_int32_t );
2504 setvoltime(obj, vol );
2509 * dst new unix filename (not a pathname)
2510 * newname new mac name
2514 int renamedir(const struct vol *vol, char *src, char *dst,
2516 struct dir *newparent,
2524 /* existence check moved to afp_moveandrename */
2525 if ( unix_rename( src, dst ) < 0 ) {
2528 return( AFPERR_NOOBJ );
2530 return( AFPERR_ACCESS );
2532 return AFPERR_VLOCK;
2534 /* tried to move directory into a subdirectory of itself */
2535 return AFPERR_CANTMOVE;
2537 /* this needs to copy and delete. bleah. that means we have
2538 * to deal with entire directory hierarchies. */
2539 if ((err = copydir(vol, src, dst)) < 0) {
2543 if ((err = deletedir(src)) < 0)
2547 return( AFPERR_PARAM );
2551 vol->vfs->vfs_renamedir(vol, src, dst);
2553 len = strlen( newname );
2554 /* rename() succeeded so we need to update our tree even if we can't open
2558 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2560 if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
2561 ad_setname(&ad, newname);
2563 ad_close_metadata( &ad);
2566 dir_hash_del(vol, dir);
2567 if (dir->d_m_name == dir->d_u_name)
2568 dir->d_u_name = NULL;
2570 if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
2571 LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
2572 /* FIXME : fatal ? */
2575 dir->d_m_name = buf;
2576 strcpy( dir->d_m_name, newname );
2578 if (newname == dst) {
2579 free(dir->d_u_name);
2580 dir->d_u_name = dir->d_m_name;
2583 if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
2584 LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
2587 dir->d_u_name = buf;
2588 strcpy( dir->d_u_name, dst );
2591 if (dir->d_m_name_ucs2)
2592 free(dir->d_m_name_ucs2);
2594 dir->d_m_name_ucs2 = NULL;
2595 if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, dir->d_m_name, -1, (char**)&dir->d_m_name_ucs2))
2596 dir->d_m_name_ucs2 = NULL;
2598 if (( parent = dir->d_parent ) == NULL ) {
2601 if ( parent == newparent ) {
2602 hash_alloc_insert(vol->v_hash, dir, dir);
2606 /* detach from old parent and add to new one. */
2607 dirchildremove(parent, dir);
2608 dir->d_parent = newparent;
2609 dirchildadd(vol, newparent, dir);
2613 /* delete an empty directory */
2614 int deletecurdir(struct vol *vol)
2624 if ( curdir->d_parent == NULL ) {
2625 return( AFPERR_ACCESS );
2630 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2631 /* we never want to create a resource fork here, we are going to delete it */
2632 if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
2634 ad_getattr(&ad, &ashort);
2635 ad_close( &ad, ADFLAGS_HF );
2636 if ((ashort & htons(ATTRBIT_NODELETE))) {
2637 return AFPERR_OLOCK;
2640 err = vol->vfs->vfs_deletecurdir(vol);
2645 /* now get rid of dangling symlinks */
2646 if ((dp = opendir("."))) {
2647 while ((de = readdir(dp))) {
2648 /* skip this and previous directory */
2649 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2652 /* bail if it's not a symlink */
2653 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
2655 return AFPERR_DIRNEMPT;
2658 if ((err = netatalk_unlink(de->d_name))) {
2665 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
2670 if ( !(err = netatalk_rmdir(fdir->d_u_name))) {
2671 dirchildremove(curdir, fdir);
2672 cnid_delete(vol->v_cdb, fdir->d_did);
2673 dir_remove( vol, fdir );
2678 /* inode is used as key for cnid.
2679 * Close the descriptor only after cnid_delete
2687 int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2697 sfunc = (unsigned char) *ibuf++;
2701 if (sfunc >= 3 && sfunc <= 6) {
2702 if (afp_version < 30) {
2703 return( AFPERR_PARAM );
2710 case 3 :/* unicode */
2711 memcpy( &id, ibuf, sizeof( id ));
2714 if (( pw = getpwuid( id )) == NULL ) {
2715 return( AFPERR_NOITEM );
2717 len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
2718 pw->pw_name, -1, &name);
2725 case 4 : /* unicode */
2726 memcpy( &id, ibuf, sizeof( id ));
2729 if (NULL == ( gr = (struct group *)getgrgid( id ))) {
2730 return( AFPERR_NOITEM );
2732 len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
2733 gr->gr_name, -1, &name);
2739 #ifdef HAVE_NFSv4_ACLS
2740 case 5 : /* UUID -> username */
2741 case 6 : /* UUID -> groupname */
2742 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2743 return AFPERR_PARAM;
2744 LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
2746 len = getnamefromuuid( ibuf, &name, &type);
2747 if (len != 0) /* its a error code, not len */
2748 return AFPERR_NOITEM;
2749 if (type == UUID_USER) {
2750 if (( pw = getpwnam( name )) == NULL )
2751 return( AFPERR_NOITEM );
2752 LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
2753 id = htonl(UUID_USER);
2754 memcpy( rbuf, &id, sizeof( id ));
2755 id = htonl( pw->pw_uid);
2756 rbuf += sizeof( id );
2757 memcpy( rbuf, &id, sizeof( id ));
2758 rbuf += sizeof( id );
2759 *rbuflen = 2 * sizeof( id );
2760 } else { /* type == UUID_GROUP */
2761 if (( gr = getgrnam( name )) == NULL )
2762 return( AFPERR_NOITEM );
2763 LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
2764 id = htonl(UUID_GROUP);
2765 memcpy( rbuf, &id, sizeof( id ));
2766 rbuf += sizeof( id );
2767 id = htonl( gr->gr_gid);
2768 memcpy( rbuf, &id, sizeof( id ));
2769 rbuf += sizeof( id );
2770 *rbuflen = 2 * sizeof( id );
2775 return( AFPERR_PARAM );
2779 len = strlen( name );
2782 u_int16_t tp = htons(len);
2783 memcpy(rbuf, &tp, sizeof(tp));
2792 memcpy( rbuf, name, len );
2800 int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2809 sfunc = (unsigned char) *ibuf++;
2811 LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
2814 case 2 : /* unicode */
2815 if (afp_version < 30) {
2816 return( AFPERR_PARAM );
2818 memcpy(&ulen, ibuf, sizeof(ulen));
2821 LOG(log_debug, logtype_afpd, "afp_mapname: alive");
2825 len = (unsigned char) *ibuf++;
2827 #ifdef HAVE_NFSv4_ACLS
2828 case 5 : /* username -> UUID */
2829 case 6 : /* groupname -> UUID */
2830 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2831 return AFPERR_PARAM;
2832 memcpy(&ulen, ibuf, sizeof(ulen));
2838 return( AFPERR_PARAM );
2844 return AFPERR_PARAM;
2847 case 1 : /* unicode */
2849 if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) {
2850 return( AFPERR_NOITEM );
2854 memcpy( rbuf, &id, sizeof( id ));
2855 *rbuflen = sizeof( id );
2858 case 2 : /* unicode */
2860 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
2861 if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
2862 return( AFPERR_NOITEM );
2865 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
2867 memcpy( rbuf, &id, sizeof( id ));
2868 *rbuflen = sizeof( id );
2870 #ifdef HAVE_NFSv4_ACLS
2871 case 5 : /* username -> UUID */
2872 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2873 if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
2874 return AFPERR_NOITEM;
2875 *rbuflen = UUID_BINSIZE;
2877 case 6 : /* groupname -> UUID */
2878 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2879 if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
2880 return AFPERR_NOITEM;
2881 *rbuflen = UUID_BINSIZE;
2889 /* ------------------------------------
2890 variable DID support
2892 int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2903 /* do nothing as dids are static for the life of the process. */
2907 memcpy(&vid, ibuf, sizeof( vid ));
2908 ibuf += sizeof( vid );
2909 if (( vol = getvolbyvid( vid )) == NULL ) {
2910 return( AFPERR_PARAM );
2913 memcpy( &did, ibuf, sizeof( did ));
2914 ibuf += sizeof( did );
2915 if (( dir = dirlookup( vol, did )) == NULL ) {
2916 return( AFPERR_PARAM );
2919 /* dir_remove -- deletedid */
2925 /* did creation gets done automatically
2926 * there's a pb again with case but move it to cname
2928 int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2931 struct dir *parentdir;
2939 memcpy(&vid, ibuf, sizeof(vid));
2940 ibuf += sizeof( vid );
2942 if (NULL == ( vol = getvolbyvid( vid )) ) {
2943 return( AFPERR_PARAM );
2946 memcpy(&did, ibuf, sizeof(did));
2947 ibuf += sizeof(did);
2949 if (NULL == ( parentdir = dirlookup( vol, did )) ) {
2953 if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
2954 return get_afp_errno(AFPERR_PARAM);
2957 if ( *path->m_name != '\0' ) {
2958 return path_error(path, AFPERR_NOOBJ);
2961 if ( !path->st_valid && of_stat(path ) < 0 ) {
2962 return( AFPERR_NOOBJ );
2964 if ( path->st_errno ) {
2965 return( AFPERR_NOOBJ );
2968 memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did));
2969 *rbuflen = sizeof(curdir->d_did);