2 * $Id: directory.c,v 1.140 2010-03-12 15:16:49 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(int dirfd, char *dir)
792 char path[MAXPATHLEN + 1];
800 if ((len = strlen(dir)) +2 > sizeof(path))
804 if ((dp = opendirat(dirfd, 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 (lstatat(dirfd, path, &st)) {
824 if (S_ISDIR(st.st_mode)) {
825 err = deletedir(dirfd, path);
827 err = netatalk_unlinkat(dirfd, path);
832 /* okay. the directory is empty. delete it. note: we already got rid
835 err = netatalk_rmdir(dirfd, dir);
840 /* do a recursive copy. */
841 static int copydir(const struct vol *vol, int dirfd, 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 = opendirat(dirfd, 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 (lstatat(dirfd, 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, dirfd, spath, dpath)))
897 } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, 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 (lstatat(dirfd, 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;
990 struct adouble *adp = NULL;
993 upath = path->u_name;
995 upathlen = strlen(upath);
997 /* get_id needs adp for reading CNID from adouble file */
998 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
999 if ((ad_open_metadata(upath, ADFLAGS_DIR, 0, &ad)) == 0)
1002 id = get_id(vol, adp, st, dir->d_did, upath, upathlen);
1005 ad_close_metadata(adp);
1010 if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
1013 name = path->m_name;
1014 if ((cdir = dirnew(name, upath)) == NULL) {
1015 LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
1018 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)) {
1019 LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
1020 cdir->d_m_name_ucs2 = NULL;
1025 if ((edir = dirinsert( vol, cdir ))) {
1026 /* it's not possible with LASTDID
1028 - someone else have moved the directory.
1029 - it's a symlink inside the share.
1030 - it's an ID reused, the old directory was deleted but not
1031 the cnid record and the server've reused the inode for
1033 for HASH (we should get ride of HASH)
1034 - someone else have moved the directory.
1035 - it's an ID reused as above
1036 - it's a hash duplicate and we are in big trouble
1038 deleted = (edir->d_m_name == NULL);
1040 dir_hash_del(vol, edir);
1042 edir->d_m_name = cdir->d_m_name;
1043 edir->d_u_name = cdir->d_u_name;
1044 edir->d_m_name_ucs2 = cdir->d_m_name_ucs2;
1047 LOG(log_error, logtype_afpd, "adddir: insert %s", edir->d_m_name);
1048 if (!cdir->d_parent || (cdir->d_parent == dir && !deleted)) {
1049 hash_alloc_insert(vol->v_hash, cdir, cdir);
1052 /* the old was not in the same folder */
1054 dirchildremove(cdir->d_parent, cdir);
1057 /* parent/child directories */
1058 cdir->d_parent = dir;
1059 dirchildadd(vol, dir, cdir);
1063 /* --- public functions follow --- */
1064 /* free everything down. we don't bother to recolor as this is only
1065 * called to free the entire tree */
1066 void dirfreename(struct dir *dir)
1068 if (dir->d_u_name != dir->d_m_name) {
1069 free(dir->d_u_name);
1071 if (dir->d_m_name_ucs2)
1072 free(dir->d_m_name_ucs2);
1073 free(dir->d_m_name);
1076 void dirfree(struct dir *dir)
1078 if (!dir || (dir == SENTINEL))
1081 if ( dir->d_left != SENTINEL ) {
1082 dirfree( dir->d_left );
1084 if ( dir->d_right != SENTINEL ) {
1085 dirfree( dir->d_right );
1088 if (dir != SENTINEL) {
1094 /* --------------------------------------------
1095 * most of the time mac name and unix name are the same
1097 struct dir *dirnew(const char *m_name, const char *u_name)
1101 dir = (struct dir *) calloc(1, sizeof( struct dir ));
1105 if ((dir->d_m_name = strdup(m_name)) == NULL) {
1110 if (m_name == u_name || !strcmp(m_name, u_name)) {
1111 dir->d_u_name = dir->d_m_name;
1113 else if ((dir->d_u_name = strdup(u_name)) == NULL) {
1114 free(dir->d_m_name);
1119 dir->d_m_name_ucs2 = NULL;
1120 dir->d_left = dir->d_right = SENTINEL;
1121 dir->d_next = dir->d_prev = dir;
1126 /* ------------------ */
1127 static hash_val_t hash_fun_dir(const void *key)
1129 const struct dir *k = key;
1131 static unsigned long randbox[] = {
1132 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
1133 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
1134 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
1135 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
1138 const unsigned char *str = (unsigned char *)(k->d_u_name);
1139 hash_val_t acc = k->d_parent->d_did;
1142 acc ^= randbox[(*str + acc) & 0xf];
1143 acc = (acc << 1) | (acc >> 31);
1145 acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
1146 acc = (acc << 2) | (acc >> 30);
1154 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
1155 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
1156 #define get16bits(d) (*((const uint16_t *) (d)))
1159 #if !defined (get16bits)
1160 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
1161 +(uint32_t)(((const uint8_t *)(d))[0]) )
1164 static hash_val_t hash_fun2_dir(const void *key)
1166 const struct dir *k = key;
1167 const char *data = k->d_u_name;
1168 int len = strlen(k->d_u_name);
1169 hash_val_t hash = k->d_parent->d_did, tmp;
1175 for (;len > 0; len--) {
1176 hash += get16bits (data);
1177 tmp = (get16bits (data+2) << 11) ^ hash;
1178 hash = (hash << 16) ^ tmp;
1179 data += 2*sizeof (uint16_t);
1183 /* Handle end cases */
1185 case 3: hash += get16bits (data);
1187 hash ^= data[sizeof (uint16_t)] << 18;
1190 case 2: hash += get16bits (data);
1194 case 1: hash += *data;
1199 /* Force "avalanching" of final 127 bits */
1210 /* ---------------- */
1211 static int hash_comp_dir(const void *key1, const void *key2)
1213 const struct dir *k1 = key1;
1214 const struct dir *k2 = key2;
1216 return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
1219 /* ---------------- */
1223 return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
1226 /* ------------------ */
1227 static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
1230 movecwd failed some of dir path are not there anymore.
1231 FIXME Is it true with other errors?
1232 so we remove dir from the cache
1234 if (dir->d_did == DIRDID_ROOT_PARENT)
1236 if (afp_errno == AFPERR_ACCESS) {
1237 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1240 /* FIXME should we set these?, don't need to call stat() after:
1242 ret->st_errno = EACCES;
1244 ret->m_name = dir->d_m_name;
1245 ret->u_name = dir->d_u_name;
1248 } else if (afp_errno == AFPERR_NOOBJ) {
1249 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1252 strcpy(ret->m_name, dir->d_m_name);
1253 if (dir->d_m_name == dir->d_u_name) {
1254 ret->u_name = ret->m_name;
1257 size_t tp = strlen(ret->m_name)+1;
1259 ret->u_name = ret->m_name +tp;
1260 strcpy(ret->u_name, dir->d_u_name);
1262 /* FIXME should we set :
1264 ret->st_errno = ENOENT;
1266 dir_invalidate(vol, dir);
1269 dir_invalidate(vol, dir);
1273 /* -------------------------------------------------- */
1279 stat the file or errno
1282 curdir: filename parent directory
1288 stat the dir or errno
1292 curdir: dir parent directory
1300 curdir: dir parent directory
1307 cname(struct vol *vol, struct dir *dir, char **cpath)
1309 struct dir *cdir, *scdir=NULL;
1310 static char path[ MAXPATHLEN + 1];
1311 static struct path ret;
1323 afp_errno = AFPERR_NOOBJ;
1324 memset(&ret, 0, sizeof(ret));
1325 switch (ret.m_type = *data) { /* path type */
1328 len = (unsigned char) *data++;
1331 if (afp_version >= 30) {
1337 if (afp_version >= 30) {
1339 memcpy(&hint, data, sizeof(hint));
1341 data += sizeof(hint);
1343 memcpy(&len16, data, sizeof(len16));
1350 /* else it's an error */
1352 afp_errno = AFPERR_PARAM;
1355 *cpath += len + size;
1360 if (movecwd( vol, dir ) < 0 ) {
1361 return invalidate(vol, dir, &ret );
1363 if (*path == '\0') {
1370 if (*data == sep ) {
1374 while (*data == sep && len > 0 ) {
1375 if ( dir->d_parent == NULL ) {
1378 dir = dir->d_parent;
1383 /* would this be faster with strlen + strncpy? */
1385 while ( *data != sep && len > 0 ) {
1387 if (p > &path[ MAXPATHLEN]) {
1388 afp_errno = AFPERR_PARAM;
1394 /* short cut bits by chopping off a trailing \0. this also
1395 makes the traversal happy w/ filenames at the end of the
1402 if ( p == path ) { /* end of the name parameter */
1406 if (afp_version >= 30) {
1411 static char temp[ MAXPATHLEN + 1];
1413 if (dir->d_did == DIRDID_ROOT_PARENT) {
1415 With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
1416 So we compare it with the longname from the current volume and if they match
1417 we overwrite the requested path with the utf8 volume name so that the following
1420 ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
1421 if (strcasecmp( path, temp) == 0)
1422 ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
1425 if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
1426 afp_errno = AFPERR_PARAM;
1432 /* check for OS X mangled filename :( */
1434 t = demangle_osx(vol, path, dir->d_did, &fileid);
1437 /* duplicate work but we can't reuse all convert_char we did in demangle_osx
1438 * flags weren't the same
1440 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
1441 /* at last got our view of mac name */
1446 if (ret.u_name == NULL) {
1447 if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
1448 afp_errno = AFPERR_PARAM;
1454 cdir = dir->d_child;
1456 if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
1457 (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
1458 CH_UCS2, path, -1, (char **)&tmpname) )
1461 if (!cdir->d_m_name_ucs2) {
1462 LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
1463 /* this shouldn't happen !!!! */
1467 if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1470 if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1473 cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
1479 if (dir->d_did == DIRDID_ROOT_PARENT) {
1481 root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
1482 must check against the volume name.
1484 if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
1490 cdir = dirsearch_byname(vol, dir, ret.u_name);
1494 if (cdir == NULL && scdir != NULL) {
1496 /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
1499 if ( cdir == NULL ) {
1501 /* if dir == curdir it always succeed,
1502 even if curdir is deleted.
1503 it's not a pb because it will fail in extenddir
1505 if ( movecwd( vol, dir ) < 0 ) {
1506 /* dir is not valid anymore
1507 we delete dir from the cache and abort.
1509 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1510 afp_errno = AFPERR_NOOBJ;
1513 if (afp_errno == AFPERR_ACCESS)
1515 dir_invalidate(vol, dir);
1518 cdir = extenddir( vol, dir, &ret );
1522 cdir = extenddir( vol, dir, &ret );
1523 } /* if (!extend) */
1525 if ( cdir == NULL ) {
1527 if ( len > 0 || !ret.u_name ) {
1539 * Move curdir to dir, with a possible chdir()
1541 int movecwd(struct vol *vol, struct dir *dir)
1543 char path[MAXPATHLEN + 1];
1549 if ( dir == curdir ) {
1552 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1553 afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
1557 p = path + sizeof(path) - 1;
1559 for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
1562 /* parent directory is deleted */
1563 afp_errno = AFPERR_NOOBJ;
1567 if (p -n -1 < path) {
1568 afp_errno = AFPERR_PARAM;
1575 if ( d != curdir ) {
1576 n = strlen( vol->v_path );
1577 if (p -n -1 < path) {
1578 afp_errno = AFPERR_PARAM;
1583 memcpy( p, vol->v_path, n );
1585 if ( (ret = lchdir(p )) != 0 ) {
1586 LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
1589 /* p is a symlink or getcwd failed */
1590 afp_errno = AFPERR_BADTYPE;
1591 vol->v_curdir = curdir = vol->v_dir;
1592 if (chdir(vol->v_path ) < 0) {
1593 LOG(log_debug, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
1594 /* XXX what do we do here? */
1601 afp_errno = AFPERR_ACCESS;
1604 afp_errno = AFPERR_NOOBJ;
1609 vol->v_curdir = curdir = dir;
1614 * We can't use unix file's perm to support Apple's inherited protection modes.
1615 * If we aren't the file's owner we can't change its perms when moving it and smb
1616 * nfs,... don't even try.
1618 #define AFP_CHECK_ACCESS
1620 int check_access(char *path, int mode)
1622 #ifdef AFP_CHECK_ACCESS
1630 accessmode(p, &ma, curdir, NULL);
1631 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1633 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1639 /* --------------------- */
1640 int file_access(struct path *path, int mode)
1644 accessmode(path->u_name, &ma, curdir, &path->st);
1645 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1647 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1653 /* --------------------- */
1654 void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
1656 dir->offcnt = count;
1657 dir->ctime = st->st_ctime;
1658 dir->d_flags &= ~DIRF_CNID;
1661 /* ---------------------
1662 * is our cached offspring count valid?
1665 static int diroffcnt(struct dir *dir, struct stat *st)
1667 return st->st_ctime == dir->ctime;
1670 /* ---------------------
1671 * is our cached also for reenumerate id?
1674 int dirreenumerate(struct dir *dir, struct stat *st)
1676 return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
1679 /* --------------------- */
1680 static int invisible_dots(const struct vol *vol, const char *name)
1682 return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
1685 /* ------------------------------
1687 (name, dir) with curdir:name == dir, from afp_enumerate
1690 int getdirparams(const struct vol *vol,
1691 u_int16_t bitmap, struct path *s_path,
1693 char *buf, size_t *buflen )
1697 char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
1698 int bit = 0, isad = 0;
1704 struct stat *st = &s_path->st;
1705 char *upath = s_path->u_name;
1707 if ((bitmap & ((1 << DIRPBIT_ATTR) |
1708 (1 << DIRPBIT_CDATE) |
1709 (1 << DIRPBIT_MDATE) |
1710 (1 << DIRPBIT_BDATE) |
1711 (1 << DIRPBIT_FINFO)))) {
1713 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1714 if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
1716 if (ad.ad_md->adf_flags & O_CREAT) {
1717 /* We just created it */
1718 ad_setname(&ad, s_path->m_name);
1723 dir->d_parent->d_did,
1730 if ( dir->d_did == DIRDID_ROOT) {
1731 pdid = DIRDID_ROOT_PARENT;
1732 } else if (dir->d_did == DIRDID_ROOT_PARENT) {
1735 pdid = dir->d_parent->d_did;
1739 while ( bitmap != 0 ) {
1740 while (( bitmap & 1 ) == 0 ) {
1748 ad_getattr(&ad, &ashort);
1749 } else if (invisible_dots(vol, dir->d_u_name)) {
1750 ashort = htons(ATTRBIT_INVISIBLE);
1753 ashort |= htons(ATTRBIT_SHARED);
1754 memcpy( data, &ashort, sizeof( ashort ));
1755 data += sizeof( ashort );
1759 memcpy( data, &pdid, sizeof( pdid ));
1760 data += sizeof( pdid );
1763 case DIRPBIT_CDATE :
1764 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1765 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1766 memcpy( data, &aint, sizeof( aint ));
1767 data += sizeof( aint );
1770 case DIRPBIT_MDATE :
1771 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1772 memcpy( data, &aint, sizeof( aint ));
1773 data += sizeof( aint );
1776 case DIRPBIT_BDATE :
1777 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
1778 aint = AD_DATE_START;
1779 memcpy( data, &aint, sizeof( aint ));
1780 data += sizeof( aint );
1783 case DIRPBIT_FINFO :
1785 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
1786 } else { /* no appledouble */
1787 memset( data, 0, 32 );
1788 /* set default view -- this also gets done in ad_open() */
1789 ashort = htons(FINDERINFO_CLOSEDVIEW);
1790 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
1792 /* dot files are by default visible */
1793 if (invisible_dots(vol, dir->d_u_name)) {
1794 ashort = htons(FINDERINFO_INVISIBLE);
1795 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
1801 case DIRPBIT_LNAME :
1802 if (dir->d_m_name) /* root of parent can have a null name */
1805 memset(data, 0, sizeof(u_int16_t));
1806 data += sizeof( u_int16_t );
1809 case DIRPBIT_SNAME :
1810 memset(data, 0, sizeof(u_int16_t));
1811 data += sizeof( u_int16_t );
1815 memcpy( data, &dir->d_did, sizeof( aint ));
1816 data += sizeof( aint );
1819 case DIRPBIT_OFFCNT :
1821 /* this needs to handle current directory access rights */
1822 if (diroffcnt(dir, st)) {
1823 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1825 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
1826 setdiroffcnt(dir, st, ret);
1827 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1829 ashort = htons( ashort );
1830 memcpy( data, &ashort, sizeof( ashort ));
1831 data += sizeof( ashort );
1835 aint = htonl(st->st_uid);
1836 memcpy( data, &aint, sizeof( aint ));
1837 data += sizeof( aint );
1841 aint = htonl(st->st_gid);
1842 memcpy( data, &aint, sizeof( aint ));
1843 data += sizeof( aint );
1846 case DIRPBIT_ACCESS :
1847 accessmode( upath, &ma, dir , st);
1849 *data++ = ma.ma_user;
1850 *data++ = ma.ma_world;
1851 *data++ = ma.ma_group;
1852 *data++ = ma.ma_owner;
1855 /* Client has requested the ProDOS information block.
1856 Just pass back the same basic block for all
1857 directories. <shirsch@ibm.net> */
1858 case DIRPBIT_PDINFO :
1859 if (afp_version >= 30) { /* UTF8 name */
1860 utf8 = kTextEncodingUTF8;
1861 if (dir->d_m_name) /* root of parent can have a null name */
1864 memset(data, 0, sizeof(u_int16_t));
1865 data += sizeof( u_int16_t );
1867 memcpy(data, &aint, sizeof( aint ));
1868 data += sizeof( aint );
1870 else { /* ProDOS Info Block */
1873 ashort = htons( 0x0200 );
1874 memcpy( data, &ashort, sizeof( ashort ));
1875 data += sizeof( ashort );
1876 memset( data, 0, sizeof( ashort ));
1877 data += sizeof( ashort );
1881 case DIRPBIT_UNIXPR :
1882 aint = htonl(st->st_uid);
1883 memcpy( data, &aint, sizeof( aint ));
1884 data += sizeof( aint );
1885 aint = htonl(st->st_gid);
1886 memcpy( data, &aint, sizeof( aint ));
1887 data += sizeof( aint );
1890 aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
1891 memcpy( data, &aint, sizeof( aint ));
1892 data += sizeof( aint );
1894 accessmode( upath, &ma, dir , st);
1896 *data++ = ma.ma_user;
1897 *data++ = ma.ma_world;
1898 *data++ = ma.ma_group;
1899 *data++ = ma.ma_owner;
1904 ad_close_metadata( &ad );
1906 return( AFPERR_BITMAP );
1912 ashort = htons( data - buf );
1913 memcpy( l_nameoff, &ashort, sizeof( ashort ));
1914 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, 0);
1916 if ( utf_nameoff ) {
1917 ashort = htons( data - buf );
1918 memcpy( utf_nameoff, &ashort, sizeof( ashort ));
1919 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, utf8);
1922 ad_close_metadata( &ad );
1924 *buflen = data - buf;
1928 /* ----------------------------- */
1929 int path_error(struct path *path, int error)
1931 /* - a dir with access error
1932 * - no error it's a file
1935 if (path_isadir(path))
1937 if (path->st_valid && path->st_errno)
1939 return AFPERR_BADTYPE ;
1942 /* ----------------------------- */
1943 int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1948 u_int16_t vid, bitmap;
1954 memcpy( &vid, ibuf, sizeof( vid ));
1955 ibuf += sizeof( vid );
1957 if (NULL == ( vol = getvolbyvid( vid )) ) {
1958 return( AFPERR_PARAM );
1961 if (vol->v_flags & AFPVOL_RO)
1962 return AFPERR_VLOCK;
1964 memcpy( &did, ibuf, sizeof( did ));
1965 ibuf += sizeof( int );
1967 if (NULL == ( dir = dirlookup( vol, did )) ) {
1971 memcpy( &bitmap, ibuf, sizeof( bitmap ));
1972 bitmap = ntohs( bitmap );
1973 ibuf += sizeof( bitmap );
1975 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1976 return get_afp_errno(AFPERR_NOOBJ);
1979 if ( *path->m_name != '\0' ) {
1980 rc = path_error(path, AFPERR_NOOBJ);
1981 /* maybe we are trying to set perms back */
1982 if (rc != AFPERR_ACCESS)
1987 * If ibuf is odd, make it even.
1989 if ((u_long)ibuf & 1 ) {
1993 if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
1994 setvoltime(obj, vol );
2000 * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
2002 * assume path == '\0' eg. it's a directory in canonical form
2005 struct path Cur_Path = {
2008 ".", /* unix name */
2010 NULL,/* struct dir */
2011 0, /* stat is not set */
2014 /* ------------------ */
2015 static int set_dir_errors(struct path *path, const char *where, int err)
2020 return AFPERR_ACCESS;
2022 return AFPERR_VLOCK;
2024 LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
2025 return AFPERR_PARAM;
2028 /* ------------------ */
2029 int setdirparams(struct vol *vol,
2030 struct path *path, u_int16_t d_bitmap, char *buf )
2042 u_int16_t ashort, bshort, oshort;
2044 int change_mdate = 0;
2045 int change_parent_mdate = 0;
2047 u_int16_t bitmap = d_bitmap;
2048 u_char finder_buf[32];
2051 u_int16_t upriv_bit = 0;
2054 upath = path->u_name;
2056 while ( bitmap != 0 ) {
2057 while (( bitmap & 1 ) == 0 ) {
2065 memcpy( &ashort, buf, sizeof( ashort ));
2066 buf += sizeof( ashort );
2068 case DIRPBIT_CDATE :
2070 memcpy(&cdate, buf, sizeof(cdate));
2071 buf += sizeof( cdate );
2073 case DIRPBIT_MDATE :
2074 memcpy(&newdate, buf, sizeof(newdate));
2075 buf += sizeof( newdate );
2077 case DIRPBIT_BDATE :
2079 memcpy(&bdate, buf, sizeof(bdate));
2080 buf += sizeof( bdate );
2082 case DIRPBIT_FINFO :
2084 memcpy( finder_buf, buf, 32 );
2087 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2088 change_parent_mdate = 1;
2089 memcpy( &owner, buf, sizeof(owner));
2090 buf += sizeof( owner );
2093 change_parent_mdate = 1;
2094 memcpy( &group, buf, sizeof( group ));
2095 buf += sizeof( group );
2097 case DIRPBIT_ACCESS :
2099 change_parent_mdate = 1;
2100 ma.ma_user = *buf++;
2101 ma.ma_world = *buf++;
2102 ma.ma_group = *buf++;
2103 ma.ma_owner = *buf++;
2104 mpriv = mtoumode( &ma ) | vol->v_dperm;
2105 if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2106 err = set_dir_errors(path, "setdirmode", errno);
2110 /* Ignore what the client thinks we should do to the
2111 ProDOS information block. Skip over the data and
2112 report nothing amiss. <shirsch@ibm.net> */
2113 case DIRPBIT_PDINFO :
2114 if (afp_version < 30) {
2118 err = AFPERR_BITMAP;
2122 case DIRPBIT_UNIXPR :
2123 if (vol_unix_priv(vol)) {
2124 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
2125 buf += sizeof( owner );
2126 memcpy( &group, buf, sizeof( group ));
2127 buf += sizeof( group );
2130 change_parent_mdate = 1;
2131 memcpy( &upriv, buf, sizeof( upriv ));
2132 buf += sizeof( upriv );
2133 upriv = ntohl (upriv) | vol->v_dperm;
2134 if (dir_rx_set(upriv)) {
2135 /* maybe we are trying to set perms back */
2136 if ( setdirunixmode(vol, upath, upriv) < 0 ) {
2138 err = set_dir_errors(path, "setdirunixmode", errno);
2149 err = AFPERR_BITMAP;
2157 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2159 if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
2161 * Check to see what we're trying to set. If it's anything
2162 * but ACCESS, UID, or GID, give an error. If it's any of those
2163 * three, we don't need the ad to be open, so just continue.
2165 * note: we also don't need to worry about mdate. also, be quiet
2166 * if we're using the noadouble option.
2168 if (!vol_noadouble(vol) && (d_bitmap &
2169 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
2170 (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
2171 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
2172 return AFPERR_ACCESS;
2178 * Check to see if a create was necessary. If it was, we'll want
2179 * to set our name, etc.
2181 if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
2182 ad_setname(&ad, curdir->d_m_name);
2188 while ( bitmap != 0 ) {
2189 while (( bitmap & 1 ) == 0 ) {
2197 ad_getattr(&ad, &bshort);
2199 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
2200 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
2204 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
2205 change_parent_mdate = 1;
2206 ad_setattr(&ad, bshort);
2209 case DIRPBIT_CDATE :
2211 ad_setdate(&ad, AD_DATE_CREATE, cdate);
2214 case DIRPBIT_MDATE :
2216 case DIRPBIT_BDATE :
2218 ad_setdate(&ad, AD_DATE_BACKUP, bdate);
2221 case DIRPBIT_FINFO :
2223 /* Fixes #2802236 */
2224 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
2225 *fflags &= htons(~FINDERINFO_ISHARED);
2227 if ( dir->d_did == DIRDID_ROOT ) {
2229 * Alright, we admit it, this is *really* sick!
2230 * The 4 bytes that we don't copy, when we're dealing
2231 * with the root of a volume, are the directory's
2232 * location information. This eliminates that annoying
2233 * behavior one sees when mounting above another mount
2236 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
2237 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
2239 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
2243 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2244 if ( (dir->d_did == DIRDID_ROOT) &&
2245 (setdeskowner( ntohl(owner), -1 ) < 0)) {
2246 err = set_dir_errors(path, "setdeskowner", errno);
2247 if (isad && err == AFPERR_PARAM) {
2248 err = AFP_OK; /* ???*/
2251 goto setdirparam_done;
2254 if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
2255 err = set_dir_errors(path, "setdirowner", errno);
2256 goto setdirparam_done;
2260 if (dir->d_did == DIRDID_ROOT)
2261 setdeskowner( -1, ntohl(group) );
2262 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2263 err = set_dir_errors(path, "setdirowner", errno);
2264 goto setdirparam_done;
2267 case DIRPBIT_ACCESS :
2268 if (dir->d_did == DIRDID_ROOT) {
2270 if (!dir_rx_set(mpriv)) {
2271 /* we can't remove read and search for owner on volume root */
2272 err = AFPERR_ACCESS;
2273 goto setdirparam_done;
2277 if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2278 err = set_dir_errors(path, "setdirmode", errno);
2279 goto setdirparam_done;
2282 case DIRPBIT_PDINFO :
2283 if (afp_version >= 30) {
2284 err = AFPERR_BITMAP;
2285 goto setdirparam_done;
2288 case DIRPBIT_UNIXPR :
2289 if (vol_unix_priv(vol)) {
2290 if (dir->d_did == DIRDID_ROOT) {
2291 if (!dir_rx_set(upriv)) {
2292 /* we can't remove read and search for owner on volume root */
2293 err = AFPERR_ACCESS;
2294 goto setdirparam_done;
2296 setdeskowner( -1, ntohl(group) );
2297 setdeskmode( upriv );
2299 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2300 err = set_dir_errors(path, "setdirowner", errno);
2301 goto setdirparam_done;
2304 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
2305 err = set_dir_errors(path, "setdirunixmode", errno);
2306 goto setdirparam_done;
2310 err = AFPERR_BITMAP;
2311 goto setdirparam_done;
2315 err = AFPERR_BITMAP;
2316 goto setdirparam_done;
2325 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
2326 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2330 ad_setdate(&ad, AD_DATE_MODIFY, newdate);
2331 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
2336 if (path->st_valid && !path->st_errno) {
2337 struct stat *st = &path->st;
2339 if (dir && dir->d_parent) {
2340 ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_parent->d_did, vol->v_stamp);
2344 ad_close_metadata( &ad);
2347 if (change_parent_mdate && dir->d_did != DIRDID_ROOT
2348 && gettimeofday(&tv, NULL) == 0) {
2349 if (!movecwd(vol, dir->d_parent)) {
2350 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2351 /* be careful with bitmap because now dir is null */
2352 bitmap = 1<<DIRPBIT_MDATE;
2353 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
2354 /* should we reset curdir ?*/
2361 int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2375 memcpy( &vid, ibuf, sizeof( vid ));
2376 ibuf += sizeof( vid );
2377 if (NULL == (vol = getvolbyvid( vid )) ) {
2378 return( AFPERR_PARAM );
2381 memcpy( &did, ibuf, sizeof( did ));
2382 ibuf += sizeof( did );
2386 * if it's CNID 2 our only choice to meet the specs is call sync.
2387 * For any other CNID just sync that dir. To my knowledge the
2388 * intended use of FPSyncDir is to sync the volume so all we're
2389 * ever going to see here is probably CNID 2. Anyway, we' prepared.
2392 if ( ntohl(did) == 2 ) {
2395 if (NULL == ( dir = dirlookup( vol, did )) ) {
2396 return afp_errno; /* was AFPERR_NOOBJ */
2399 if (movecwd( vol, dir ) < 0 )
2400 return ( AFPERR_NOOBJ );
2403 * Assuming only OSens that have dirfd also may require fsyncing directories
2404 * in order to flush metadata e.g. Linux.
2408 if (NULL == ( dp = opendir( "." )) ) {
2411 return( AFPERR_NOOBJ );
2413 return( AFPERR_ACCESS );
2415 return( AFPERR_PARAM );
2419 LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
2422 if ( fsync ( dfd ) < 0 )
2423 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2424 dir->d_u_name, strerror(errno) );
2425 closedir(dp); /* closes dfd too */
2428 if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
2431 return( AFPERR_NOOBJ );
2433 return( AFPERR_ACCESS );
2435 return( AFPERR_PARAM );
2439 LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
2440 vol->ad_path(".", ADFLAGS_DIR) );
2442 if ( fsync(dfd) < 0 )
2443 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2444 vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
2451 int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2457 struct path *s_path;
2465 memcpy( &vid, ibuf, sizeof( vid ));
2466 ibuf += sizeof( vid );
2467 if (NULL == ( vol = getvolbyvid( vid )) ) {
2468 return( AFPERR_PARAM );
2471 if (vol->v_flags & AFPVOL_RO)
2472 return AFPERR_VLOCK;
2474 memcpy( &did, ibuf, sizeof( did ));
2475 ibuf += sizeof( did );
2476 if (NULL == ( dir = dirlookup( vol, did )) ) {
2477 return afp_errno; /* was AFPERR_NOOBJ */
2479 /* for concurrent access we need to be sure we are not in the
2480 * folder we want to create...
2484 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
2485 return get_afp_errno(AFPERR_PARAM);
2487 /* cname was able to move curdir to it! */
2488 if (*s_path->m_name == '\0')
2489 return AFPERR_EXIST;
2491 upath = s_path->u_name;
2493 if (AFP_OK != (err = netatalk_mkdir( upath))) {
2497 if (of_stat(s_path) < 0) {
2501 if ((dir = adddir( vol, curdir, s_path)) == NULL) {
2505 if ( movecwd( vol, dir ) < 0 ) {
2506 return( AFPERR_PARAM );
2509 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2510 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
2511 if (vol_noadouble(vol))
2512 goto createdir_done;
2513 return( AFPERR_ACCESS );
2515 ad_setname(&ad, s_path->m_name);
2516 ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
2519 ad_close_metadata( &ad);
2522 #ifdef HAVE_NFSv4_ACLS
2523 /* FIXME: are we really inside the created dir? */
2524 addir_inherit_acl(vol);
2527 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
2528 *rbuflen = sizeof( u_int32_t );
2529 setvoltime(obj, vol );
2534 * dst new unix filename (not a pathname)
2535 * newname new mac name
2537 * dirfd -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd
2539 int renamedir(const struct vol *vol,
2544 struct dir *newparent,
2552 /* existence check moved to afp_moveandrename */
2553 if ( unix_rename(dirfd, src, -1, dst ) < 0 ) {
2556 return( AFPERR_NOOBJ );
2558 return( AFPERR_ACCESS );
2560 return AFPERR_VLOCK;
2562 /* tried to move directory into a subdirectory of itself */
2563 return AFPERR_CANTMOVE;
2565 /* this needs to copy and delete. bleah. that means we have
2566 * to deal with entire directory hierarchies. */
2567 if ((err = copydir(vol, dirfd, src, dst)) < 0) {
2571 if ((err = deletedir(dirfd, src)) < 0)
2575 return( AFPERR_PARAM );
2579 vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
2581 len = strlen( newname );
2582 /* rename() succeeded so we need to update our tree even if we can't open
2586 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2588 if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
2589 ad_setname(&ad, newname);
2591 ad_close_metadata( &ad);
2594 dir_hash_del(vol, dir);
2595 if (dir->d_m_name == dir->d_u_name)
2596 dir->d_u_name = NULL;
2598 if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
2599 LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
2600 /* FIXME : fatal ? */
2603 dir->d_m_name = buf;
2604 strcpy( dir->d_m_name, newname );
2606 if (newname == dst) {
2607 free(dir->d_u_name);
2608 dir->d_u_name = dir->d_m_name;
2611 if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
2612 LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
2615 dir->d_u_name = buf;
2616 strcpy( dir->d_u_name, dst );
2619 if (dir->d_m_name_ucs2)
2620 free(dir->d_m_name_ucs2);
2622 dir->d_m_name_ucs2 = NULL;
2623 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))
2624 dir->d_m_name_ucs2 = NULL;
2626 if (( parent = dir->d_parent ) == NULL ) {
2629 if ( parent == newparent ) {
2630 hash_alloc_insert(vol->v_hash, dir, dir);
2634 /* detach from old parent and add to new one. */
2635 dirchildremove(parent, dir);
2636 dir->d_parent = newparent;
2637 dirchildadd(vol, newparent, dir);
2641 /* delete an empty directory */
2642 int deletecurdir(struct vol *vol)
2652 if ( curdir->d_parent == NULL ) {
2653 return( AFPERR_ACCESS );
2658 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2659 /* we never want to create a resource fork here, we are going to delete it */
2660 if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
2662 ad_getattr(&ad, &ashort);
2663 ad_close_metadata(&ad);
2664 if ((ashort & htons(ATTRBIT_NODELETE))) {
2665 return AFPERR_OLOCK;
2668 err = vol->vfs->vfs_deletecurdir(vol);
2673 /* now get rid of dangling symlinks */
2674 if ((dp = opendir("."))) {
2675 while ((de = readdir(dp))) {
2676 /* skip this and previous directory */
2677 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2680 /* bail if it's not a symlink */
2681 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
2683 return AFPERR_DIRNEMPT;
2686 if ((err = netatalk_unlink(de->d_name))) {
2693 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
2698 err = netatalk_rmdir_all_errors(-1, fdir->d_u_name);
2699 if ( err == AFP_OK || err == AFPERR_NOOBJ) {
2700 dirchildremove(curdir, fdir);
2701 cnid_delete(vol->v_cdb, fdir->d_did);
2702 dir_remove( vol, fdir );
2706 /* inode is used as key for cnid.
2707 * Close the descriptor only after cnid_delete
2715 int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2725 sfunc = (unsigned char) *ibuf++;
2729 if (sfunc >= 3 && sfunc <= 6) {
2730 if (afp_version < 30) {
2731 return( AFPERR_PARAM );
2738 case 3 :/* unicode */
2739 memcpy( &id, ibuf, sizeof( id ));
2742 if (( pw = getpwuid( id )) == NULL ) {
2743 return( AFPERR_NOITEM );
2745 len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
2746 pw->pw_name, -1, &name);
2753 case 4 : /* unicode */
2754 memcpy( &id, ibuf, sizeof( id ));
2757 if (NULL == ( gr = (struct group *)getgrgid( id ))) {
2758 return( AFPERR_NOITEM );
2760 len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
2761 gr->gr_name, -1, &name);
2767 #ifdef HAVE_NFSv4_ACLS
2768 case 5 : /* UUID -> username */
2769 case 6 : /* UUID -> groupname */
2770 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2771 return AFPERR_PARAM;
2772 LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
2774 len = getnamefromuuid( ibuf, &name, &type);
2775 if (len != 0) /* its a error code, not len */
2776 return AFPERR_NOITEM;
2777 if (type == UUID_USER) {
2778 if (( pw = getpwnam( name )) == NULL )
2779 return( AFPERR_NOITEM );
2780 LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
2781 id = htonl(UUID_USER);
2782 memcpy( rbuf, &id, sizeof( id ));
2783 id = htonl( pw->pw_uid);
2784 rbuf += sizeof( id );
2785 memcpy( rbuf, &id, sizeof( id ));
2786 rbuf += sizeof( id );
2787 *rbuflen = 2 * sizeof( id );
2788 } else { /* type == UUID_GROUP */
2789 if (( gr = getgrnam( name )) == NULL )
2790 return( AFPERR_NOITEM );
2791 LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
2792 id = htonl(UUID_GROUP);
2793 memcpy( rbuf, &id, sizeof( id ));
2794 rbuf += sizeof( id );
2795 id = htonl( gr->gr_gid);
2796 memcpy( rbuf, &id, sizeof( id ));
2797 rbuf += sizeof( id );
2798 *rbuflen = 2 * sizeof( id );
2803 return( AFPERR_PARAM );
2807 len = strlen( name );
2810 u_int16_t tp = htons(len);
2811 memcpy(rbuf, &tp, sizeof(tp));
2820 memcpy( rbuf, name, len );
2828 int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2837 sfunc = (unsigned char) *ibuf++;
2839 LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
2842 case 2 : /* unicode */
2843 if (afp_version < 30) {
2844 return( AFPERR_PARAM );
2846 memcpy(&ulen, ibuf, sizeof(ulen));
2849 LOG(log_debug, logtype_afpd, "afp_mapname: alive");
2853 len = (unsigned char) *ibuf++;
2855 #ifdef HAVE_NFSv4_ACLS
2856 case 5 : /* username -> UUID */
2857 case 6 : /* groupname -> UUID */
2858 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2859 return AFPERR_PARAM;
2860 memcpy(&ulen, ibuf, sizeof(ulen));
2866 return( AFPERR_PARAM );
2872 return AFPERR_PARAM;
2875 case 1 : /* unicode */
2877 if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) {
2878 return( AFPERR_NOITEM );
2882 memcpy( rbuf, &id, sizeof( id ));
2883 *rbuflen = sizeof( id );
2886 case 2 : /* unicode */
2888 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
2889 if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
2890 return( AFPERR_NOITEM );
2893 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
2895 memcpy( rbuf, &id, sizeof( id ));
2896 *rbuflen = sizeof( id );
2898 #ifdef HAVE_NFSv4_ACLS
2899 case 5 : /* username -> UUID */
2900 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2901 if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
2902 return AFPERR_NOITEM;
2903 *rbuflen = UUID_BINSIZE;
2905 case 6 : /* groupname -> UUID */
2906 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2907 if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
2908 return AFPERR_NOITEM;
2909 *rbuflen = UUID_BINSIZE;
2917 /* ------------------------------------
2918 variable DID support
2920 int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2931 /* do nothing as dids are static for the life of the process. */
2935 memcpy(&vid, ibuf, sizeof( vid ));
2936 ibuf += sizeof( vid );
2937 if (( vol = getvolbyvid( vid )) == NULL ) {
2938 return( AFPERR_PARAM );
2941 memcpy( &did, ibuf, sizeof( did ));
2942 ibuf += sizeof( did );
2943 if (( dir = dirlookup( vol, did )) == NULL ) {
2944 return( AFPERR_PARAM );
2947 /* dir_remove -- deletedid */
2953 /* did creation gets done automatically
2954 * there's a pb again with case but move it to cname
2956 int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2959 struct dir *parentdir;
2967 memcpy(&vid, ibuf, sizeof(vid));
2968 ibuf += sizeof( vid );
2970 if (NULL == ( vol = getvolbyvid( vid )) ) {
2971 return( AFPERR_PARAM );
2974 memcpy(&did, ibuf, sizeof(did));
2975 ibuf += sizeof(did);
2977 if (NULL == ( parentdir = dirlookup( vol, did )) ) {
2981 if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
2982 return get_afp_errno(AFPERR_PARAM);
2985 if ( *path->m_name != '\0' ) {
2986 return path_error(path, AFPERR_NOOBJ);
2989 if ( !path->st_valid && of_stat(path ) < 0 ) {
2990 return( AFPERR_NOOBJ );
2992 if ( path->st_errno ) {
2993 return( AFPERR_NOOBJ );
2996 memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did));
2997 *rbuflen = sizeof(curdir->d_did);