2 * $Id: directory.c,v 1.136 2010-02-28 17:02:49 didg 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 (lstat(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 (lstat(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 (lstat(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;
1125 /* ------------------ */
1126 static hash_val_t hash_fun_dir(const void *key)
1128 const struct dir *k = key;
1130 static unsigned long randbox[] = {
1131 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
1132 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
1133 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
1134 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
1137 const unsigned char *str = (unsigned char *)(k->d_u_name);
1138 hash_val_t acc = k->d_parent->d_did;
1141 acc ^= randbox[(*str + acc) & 0xf];
1142 acc = (acc << 1) | (acc >> 31);
1144 acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
1145 acc = (acc << 2) | (acc >> 30);
1152 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
1153 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
1154 #define get16bits(d) (*((const uint16_t *) (d)))
1157 #if !defined (get16bits)
1158 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
1159 +(uint32_t)(((const uint8_t *)(d))[0]) )
1162 static hash_val_t hash_fun2_dir(const void *key)
1164 const struct dir *k = key;
1165 const char *data = k->d_u_name;
1166 int len = strlen(k->d_u_name);
1167 hash_val_t hash = k->d_parent->d_did, tmp;
1173 for (;len > 0; len--) {
1174 hash += get16bits (data);
1175 tmp = (get16bits (data+2) << 11) ^ hash;
1176 hash = (hash << 16) ^ tmp;
1177 data += 2*sizeof (uint16_t);
1181 /* Handle end cases */
1183 case 3: hash += get16bits (data);
1185 hash ^= data[sizeof (uint16_t)] << 18;
1188 case 2: hash += get16bits (data);
1192 case 1: hash += *data;
1197 /* Force "avalanching" of final 127 bits */
1208 /* ---------------- */
1209 static int hash_comp_dir(const void *key1, const void *key2)
1211 const struct dir *k1 = key1;
1212 const struct dir *k2 = key2;
1214 return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
1217 /* ---------------- */
1221 return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
1224 /* ------------------ */
1225 static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
1228 movecwd failed some of dir path are not there anymore.
1229 FIXME Is it true with other errors?
1230 so we remove dir from the cache
1232 if (dir->d_did == DIRDID_ROOT_PARENT)
1234 if (afp_errno == AFPERR_ACCESS) {
1235 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1238 /* FIXME should we set these?, don't need to call stat() after:
1240 ret->st_errno = EACCES;
1242 ret->m_name = dir->d_m_name;
1243 ret->u_name = dir->d_u_name;
1246 } else if (afp_errno == AFPERR_NOOBJ) {
1247 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1250 strcpy(ret->m_name, dir->d_m_name);
1251 if (dir->d_m_name == dir->d_u_name) {
1252 ret->u_name = ret->m_name;
1255 size_t tp = strlen(ret->m_name)+1;
1257 ret->u_name = ret->m_name +tp;
1258 strcpy(ret->u_name, dir->d_u_name);
1260 /* FIXME should we set :
1262 ret->st_errno = ENOENT;
1264 dir_invalidate(vol, dir);
1267 dir_invalidate(vol, dir);
1271 /* -------------------------------------------------- */
1277 stat the file or errno
1280 curdir: filename parent directory
1286 stat the dir or errno
1290 curdir: dir parent directory
1298 curdir: dir parent directory
1305 cname(struct vol *vol, struct dir *dir, char **cpath)
1307 struct dir *cdir, *scdir=NULL;
1308 static char path[ MAXPATHLEN + 1];
1309 static struct path ret;
1321 afp_errno = AFPERR_NOOBJ;
1322 memset(&ret, 0, sizeof(ret));
1323 switch (ret.m_type = *data) { /* path type */
1326 len = (unsigned char) *data++;
1329 if (afp_version >= 30) {
1335 if (afp_version >= 30) {
1337 memcpy(&hint, data, sizeof(hint));
1339 data += sizeof(hint);
1341 memcpy(&len16, data, sizeof(len16));
1348 /* else it's an error */
1350 afp_errno = AFPERR_PARAM;
1353 *cpath += len + size;
1358 if (movecwd( vol, dir ) < 0 ) {
1359 return invalidate(vol, dir, &ret );
1361 if (*path == '\0') {
1368 if (*data == sep ) {
1372 while (*data == sep && len > 0 ) {
1373 if ( dir->d_parent == NULL ) {
1376 dir = dir->d_parent;
1381 /* would this be faster with strlen + strncpy? */
1383 while ( *data != sep && len > 0 ) {
1385 if (p > &path[ MAXPATHLEN]) {
1386 afp_errno = AFPERR_PARAM;
1392 /* short cut bits by chopping off a trailing \0. this also
1393 makes the traversal happy w/ filenames at the end of the
1400 if ( p == path ) { /* end of the name parameter */
1404 if (afp_version >= 30) {
1409 static char temp[ MAXPATHLEN + 1];
1411 if (dir->d_did == DIRDID_ROOT_PARENT) {
1413 With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
1414 So we compare it with the longname from the current volume and if they match
1415 we overwrite the requested path with the utf8 volume name so that the following
1418 ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
1419 if (strcasecmp( path, temp) == 0)
1420 ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
1423 if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
1424 afp_errno = AFPERR_PARAM;
1430 /* check for OS X mangled filename :( */
1432 t = demangle_osx(vol, path, dir->d_did, &fileid);
1435 /* duplicate work but we can't reuse all convert_char we did in demangle_osx
1436 * flags weren't the same
1438 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
1439 /* at last got our view of mac name */
1444 if (ret.u_name == NULL) {
1445 if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
1446 afp_errno = AFPERR_PARAM;
1452 cdir = dir->d_child;
1454 if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
1455 (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
1456 CH_UCS2, path, -1, (char **)&tmpname) )
1459 if (!cdir->d_m_name_ucs2) {
1460 LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
1461 /* this shouldn't happen !!!! */
1465 if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1468 if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1471 cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
1477 if (dir->d_did == DIRDID_ROOT_PARENT) {
1479 root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
1480 must check against the volume name.
1482 if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
1488 cdir = dirsearch_byname(vol, dir, ret.u_name);
1492 if (cdir == NULL && scdir != NULL) {
1494 /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
1497 if ( cdir == NULL ) {
1499 /* if dir == curdir it always succeed,
1500 even if curdir is deleted.
1501 it's not a pb because it will fail in extenddir
1503 if ( movecwd( vol, dir ) < 0 ) {
1504 /* dir is not valid anymore
1505 we delete dir from the cache and abort.
1507 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1508 afp_errno = AFPERR_NOOBJ;
1511 if (afp_errno == AFPERR_ACCESS)
1513 dir_invalidate(vol, dir);
1516 cdir = extenddir( vol, dir, &ret );
1520 cdir = extenddir( vol, dir, &ret );
1521 } /* if (!extend) */
1523 if ( cdir == NULL ) {
1525 if ( len > 0 || !ret.u_name ) {
1537 * Move curdir to dir, with a possible chdir()
1539 int movecwd(struct vol *vol, struct dir *dir)
1541 char path[MAXPATHLEN + 1];
1547 if ( dir == curdir ) {
1550 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1551 afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
1555 p = path + sizeof(path) - 1;
1558 for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
1561 /* parent directory is deleted */
1562 afp_errno = AFPERR_NOOBJ;
1566 if (p -n -1 < path) {
1567 afp_errno = AFPERR_PARAM;
1574 if ( d != curdir ) {
1575 n = strlen( vol->v_path );
1576 if (p -n -1 < path) {
1577 afp_errno = AFPERR_PARAM;
1582 memcpy( p, vol->v_path, n );
1584 if ( (ret = lchdir(vol, p )) != 0 ) {
1585 LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
1588 /* p is a symlink or getcwd failed */
1589 afp_errno = AFPERR_BADTYPE;
1590 vol->v_curdir = curdir = vol->v_dir;
1591 if (chdir(vol->v_path ) < 0) {
1592 LOG(log_debug, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
1593 /* XXX what do we do here? */
1600 afp_errno = AFPERR_ACCESS;
1603 afp_errno = AFPERR_NOOBJ;
1608 vol->v_curdir = curdir = dir;
1613 * We can't use unix file's perm to support Apple's inherited protection modes.
1614 * If we aren't the file's owner we can't change its perms when moving it and smb
1615 * nfs,... don't even try.
1617 #define AFP_CHECK_ACCESS
1619 int check_access(char *path, int mode)
1621 #ifdef AFP_CHECK_ACCESS
1629 accessmode(p, &ma, curdir, NULL);
1630 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1632 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1638 /* --------------------- */
1639 int file_access(struct path *path, int mode)
1643 accessmode(path->u_name, &ma, curdir, &path->st);
1644 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1646 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1652 /* --------------------- */
1653 void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
1655 dir->offcnt = count;
1656 dir->ctime = st->st_ctime;
1657 dir->d_flags &= ~DIRF_CNID;
1660 /* ---------------------
1661 * is our cached offspring count valid?
1664 static int diroffcnt(struct dir *dir, struct stat *st)
1666 return st->st_ctime == dir->ctime;
1669 /* ---------------------
1670 * is our cached also for reenumerate id?
1673 int dirreenumerate(struct dir *dir, struct stat *st)
1675 return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
1678 /* --------------------- */
1679 static int invisible_dots(const struct vol *vol, const char *name)
1681 return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
1684 /* ------------------------------
1686 (name, dir) with curdir:name == dir, from afp_enumerate
1689 int getdirparams(const struct vol *vol,
1690 u_int16_t bitmap, struct path *s_path,
1692 char *buf, size_t *buflen )
1696 char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
1697 int bit = 0, isad = 0;
1703 struct stat *st = &s_path->st;
1704 char *upath = s_path->u_name;
1706 if ((bitmap & ((1 << DIRPBIT_ATTR) |
1707 (1 << DIRPBIT_CDATE) |
1708 (1 << DIRPBIT_MDATE) |
1709 (1 << DIRPBIT_BDATE) |
1710 (1 << DIRPBIT_FINFO)))) {
1712 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1713 if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
1715 if (ad.ad_md->adf_flags & O_CREAT) {
1716 /* We just created it */
1717 ad_setname(&ad, s_path->m_name);
1722 dir->d_parent->d_did,
1729 if ( dir->d_did == DIRDID_ROOT) {
1730 pdid = DIRDID_ROOT_PARENT;
1731 } else if (dir->d_did == DIRDID_ROOT_PARENT) {
1734 pdid = dir->d_parent->d_did;
1738 while ( bitmap != 0 ) {
1739 while (( bitmap & 1 ) == 0 ) {
1747 ad_getattr(&ad, &ashort);
1748 } else if (invisible_dots(vol, dir->d_u_name)) {
1749 ashort = htons(ATTRBIT_INVISIBLE);
1752 ashort |= htons(ATTRBIT_SHARED);
1753 memcpy( data, &ashort, sizeof( ashort ));
1754 data += sizeof( ashort );
1758 memcpy( data, &pdid, sizeof( pdid ));
1759 data += sizeof( pdid );
1762 case DIRPBIT_CDATE :
1763 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1764 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1765 memcpy( data, &aint, sizeof( aint ));
1766 data += sizeof( aint );
1769 case DIRPBIT_MDATE :
1770 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1771 memcpy( data, &aint, sizeof( aint ));
1772 data += sizeof( aint );
1775 case DIRPBIT_BDATE :
1776 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
1777 aint = AD_DATE_START;
1778 memcpy( data, &aint, sizeof( aint ));
1779 data += sizeof( aint );
1782 case DIRPBIT_FINFO :
1784 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
1785 } else { /* no appledouble */
1786 memset( data, 0, 32 );
1787 /* set default view -- this also gets done in ad_open() */
1788 ashort = htons(FINDERINFO_CLOSEDVIEW);
1789 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
1791 /* dot files are by default visible */
1792 if (invisible_dots(vol, dir->d_u_name)) {
1793 ashort = htons(FINDERINFO_INVISIBLE);
1794 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
1800 case DIRPBIT_LNAME :
1801 if (dir->d_m_name) /* root of parent can have a null name */
1804 memset(data, 0, sizeof(u_int16_t));
1805 data += sizeof( u_int16_t );
1808 case DIRPBIT_SNAME :
1809 memset(data, 0, sizeof(u_int16_t));
1810 data += sizeof( u_int16_t );
1814 memcpy( data, &dir->d_did, sizeof( aint ));
1815 data += sizeof( aint );
1818 case DIRPBIT_OFFCNT :
1820 /* this needs to handle current directory access rights */
1821 if (diroffcnt(dir, st)) {
1822 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1824 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
1825 setdiroffcnt(dir, st, ret);
1826 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1828 ashort = htons( ashort );
1829 memcpy( data, &ashort, sizeof( ashort ));
1830 data += sizeof( ashort );
1834 aint = htonl(st->st_uid);
1835 memcpy( data, &aint, sizeof( aint ));
1836 data += sizeof( aint );
1840 aint = htonl(st->st_gid);
1841 memcpy( data, &aint, sizeof( aint ));
1842 data += sizeof( aint );
1845 case DIRPBIT_ACCESS :
1846 accessmode( upath, &ma, dir , st);
1848 *data++ = ma.ma_user;
1849 *data++ = ma.ma_world;
1850 *data++ = ma.ma_group;
1851 *data++ = ma.ma_owner;
1854 /* Client has requested the ProDOS information block.
1855 Just pass back the same basic block for all
1856 directories. <shirsch@ibm.net> */
1857 case DIRPBIT_PDINFO :
1858 if (afp_version >= 30) { /* UTF8 name */
1859 utf8 = kTextEncodingUTF8;
1860 if (dir->d_m_name) /* root of parent can have a null name */
1863 memset(data, 0, sizeof(u_int16_t));
1864 data += sizeof( u_int16_t );
1866 memcpy(data, &aint, sizeof( aint ));
1867 data += sizeof( aint );
1869 else { /* ProDOS Info Block */
1872 ashort = htons( 0x0200 );
1873 memcpy( data, &ashort, sizeof( ashort ));
1874 data += sizeof( ashort );
1875 memset( data, 0, sizeof( ashort ));
1876 data += sizeof( ashort );
1880 case DIRPBIT_UNIXPR :
1881 aint = htonl(st->st_uid);
1882 memcpy( data, &aint, sizeof( aint ));
1883 data += sizeof( aint );
1884 aint = htonl(st->st_gid);
1885 memcpy( data, &aint, sizeof( aint ));
1886 data += sizeof( aint );
1889 aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
1890 memcpy( data, &aint, sizeof( aint ));
1891 data += sizeof( aint );
1893 accessmode( upath, &ma, dir , st);
1895 *data++ = ma.ma_user;
1896 *data++ = ma.ma_world;
1897 *data++ = ma.ma_group;
1898 *data++ = ma.ma_owner;
1903 ad_close_metadata( &ad );
1905 return( AFPERR_BITMAP );
1911 ashort = htons( data - buf );
1912 memcpy( l_nameoff, &ashort, sizeof( ashort ));
1913 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, 0);
1915 if ( utf_nameoff ) {
1916 ashort = htons( data - buf );
1917 memcpy( utf_nameoff, &ashort, sizeof( ashort ));
1918 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, utf8);
1921 ad_close_metadata( &ad );
1923 *buflen = data - buf;
1927 /* ----------------------------- */
1928 int path_error(struct path *path, int error)
1930 /* - a dir with access error
1931 * - no error it's a file
1934 if (path_isadir(path))
1936 if (path->st_valid && path->st_errno)
1938 return AFPERR_BADTYPE ;
1941 /* ----------------------------- */
1942 int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1947 u_int16_t vid, bitmap;
1953 memcpy( &vid, ibuf, sizeof( vid ));
1954 ibuf += sizeof( vid );
1956 if (NULL == ( vol = getvolbyvid( vid )) ) {
1957 return( AFPERR_PARAM );
1960 if (vol->v_flags & AFPVOL_RO)
1961 return AFPERR_VLOCK;
1963 memcpy( &did, ibuf, sizeof( did ));
1964 ibuf += sizeof( int );
1966 if (NULL == ( dir = dirlookup( vol, did )) ) {
1970 memcpy( &bitmap, ibuf, sizeof( bitmap ));
1971 bitmap = ntohs( bitmap );
1972 ibuf += sizeof( bitmap );
1974 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1975 return get_afp_errno(AFPERR_NOOBJ);
1978 if ( *path->m_name != '\0' ) {
1979 rc = path_error(path, AFPERR_NOOBJ);
1980 /* maybe we are trying to set perms back */
1981 if (rc != AFPERR_ACCESS)
1986 * If ibuf is odd, make it even.
1988 if ((u_long)ibuf & 1 ) {
1992 if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
1993 setvoltime(obj, vol );
1999 * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
2001 * assume path == '\0' eg. it's a directory in canonical form
2004 struct path Cur_Path = {
2007 ".", /* unix name */
2009 NULL,/* struct dir */
2010 0, /* stat is not set */
2013 /* ------------------ */
2014 static int set_dir_errors(struct path *path, const char *where, int err)
2019 return AFPERR_ACCESS;
2021 return AFPERR_VLOCK;
2023 LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
2024 return AFPERR_PARAM;
2027 /* ------------------ */
2028 int setdirparams(struct vol *vol,
2029 struct path *path, u_int16_t d_bitmap, char *buf )
2041 u_int16_t ashort, bshort, oshort;
2043 int change_mdate = 0;
2044 int change_parent_mdate = 0;
2046 u_int16_t bitmap = d_bitmap;
2047 u_char finder_buf[32];
2050 u_int16_t upriv_bit = 0;
2053 upath = path->u_name;
2055 while ( bitmap != 0 ) {
2056 while (( bitmap & 1 ) == 0 ) {
2064 memcpy( &ashort, buf, sizeof( ashort ));
2065 buf += sizeof( ashort );
2067 case DIRPBIT_CDATE :
2069 memcpy(&cdate, buf, sizeof(cdate));
2070 buf += sizeof( cdate );
2072 case DIRPBIT_MDATE :
2073 memcpy(&newdate, buf, sizeof(newdate));
2074 buf += sizeof( newdate );
2076 case DIRPBIT_BDATE :
2078 memcpy(&bdate, buf, sizeof(bdate));
2079 buf += sizeof( bdate );
2081 case DIRPBIT_FINFO :
2083 memcpy( finder_buf, buf, 32 );
2086 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2087 change_parent_mdate = 1;
2088 memcpy( &owner, buf, sizeof(owner));
2089 buf += sizeof( owner );
2092 change_parent_mdate = 1;
2093 memcpy( &group, buf, sizeof( group ));
2094 buf += sizeof( group );
2096 case DIRPBIT_ACCESS :
2098 change_parent_mdate = 1;
2099 ma.ma_user = *buf++;
2100 ma.ma_world = *buf++;
2101 ma.ma_group = *buf++;
2102 ma.ma_owner = *buf++;
2103 mpriv = mtoumode( &ma ) | vol->v_dperm;
2104 if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2105 err = set_dir_errors(path, "setdirmode", errno);
2109 /* Ignore what the client thinks we should do to the
2110 ProDOS information block. Skip over the data and
2111 report nothing amiss. <shirsch@ibm.net> */
2112 case DIRPBIT_PDINFO :
2113 if (afp_version < 30) {
2117 err = AFPERR_BITMAP;
2121 case DIRPBIT_UNIXPR :
2122 if (vol_unix_priv(vol)) {
2123 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
2124 buf += sizeof( owner );
2125 memcpy( &group, buf, sizeof( group ));
2126 buf += sizeof( group );
2129 change_parent_mdate = 1;
2130 memcpy( &upriv, buf, sizeof( upriv ));
2131 buf += sizeof( upriv );
2132 upriv = ntohl (upriv) | vol->v_dperm;
2133 if (dir_rx_set(upriv)) {
2134 /* maybe we are trying to set perms back */
2135 if ( setdirunixmode(vol, upath, upriv) < 0 ) {
2137 err = set_dir_errors(path, "setdirunixmode", errno);
2148 err = AFPERR_BITMAP;
2156 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2158 if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
2160 * Check to see what we're trying to set. If it's anything
2161 * but ACCESS, UID, or GID, give an error. If it's any of those
2162 * three, we don't need the ad to be open, so just continue.
2164 * note: we also don't need to worry about mdate. also, be quiet
2165 * if we're using the noadouble option.
2167 if (!vol_noadouble(vol) && (d_bitmap &
2168 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
2169 (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
2170 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
2171 return AFPERR_ACCESS;
2177 * Check to see if a create was necessary. If it was, we'll want
2178 * to set our name, etc.
2180 if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
2181 ad_setname(&ad, curdir->d_m_name);
2187 while ( bitmap != 0 ) {
2188 while (( bitmap & 1 ) == 0 ) {
2196 ad_getattr(&ad, &bshort);
2198 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
2199 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
2203 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
2204 change_parent_mdate = 1;
2205 ad_setattr(&ad, bshort);
2208 case DIRPBIT_CDATE :
2210 ad_setdate(&ad, AD_DATE_CREATE, cdate);
2213 case DIRPBIT_MDATE :
2215 case DIRPBIT_BDATE :
2217 ad_setdate(&ad, AD_DATE_BACKUP, bdate);
2220 case DIRPBIT_FINFO :
2222 /* Fixes #2802236 */
2223 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
2224 *fflags &= htons(~FINDERINFO_ISHARED);
2226 if ( dir->d_did == DIRDID_ROOT ) {
2228 * Alright, we admit it, this is *really* sick!
2229 * The 4 bytes that we don't copy, when we're dealing
2230 * with the root of a volume, are the directory's
2231 * location information. This eliminates that annoying
2232 * behavior one sees when mounting above another mount
2235 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
2236 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
2238 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
2242 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2243 if ( (dir->d_did == DIRDID_ROOT) &&
2244 (setdeskowner( ntohl(owner), -1 ) < 0)) {
2245 err = set_dir_errors(path, "setdeskowner", errno);
2246 if (isad && err == AFPERR_PARAM) {
2247 err = AFP_OK; /* ???*/
2250 goto setdirparam_done;
2253 if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
2254 err = set_dir_errors(path, "setdirowner", errno);
2255 goto setdirparam_done;
2259 if (dir->d_did == DIRDID_ROOT)
2260 setdeskowner( -1, ntohl(group) );
2261 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2262 err = set_dir_errors(path, "setdirowner", errno);
2263 goto setdirparam_done;
2266 case DIRPBIT_ACCESS :
2267 if (dir->d_did == DIRDID_ROOT) {
2269 if (!dir_rx_set(mpriv)) {
2270 /* we can't remove read and search for owner on volume root */
2271 err = AFPERR_ACCESS;
2272 goto setdirparam_done;
2276 if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2277 err = set_dir_errors(path, "setdirmode", errno);
2278 goto setdirparam_done;
2281 case DIRPBIT_PDINFO :
2282 if (afp_version >= 30) {
2283 err = AFPERR_BITMAP;
2284 goto setdirparam_done;
2287 case DIRPBIT_UNIXPR :
2288 if (vol_unix_priv(vol)) {
2289 if (dir->d_did == DIRDID_ROOT) {
2290 if (!dir_rx_set(upriv)) {
2291 /* we can't remove read and search for owner on volume root */
2292 err = AFPERR_ACCESS;
2293 goto setdirparam_done;
2295 setdeskowner( -1, ntohl(group) );
2296 setdeskmode( upriv );
2298 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2299 err = set_dir_errors(path, "setdirowner", errno);
2300 goto setdirparam_done;
2303 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
2304 err = set_dir_errors(path, "setdirunixmode", errno);
2305 goto setdirparam_done;
2309 err = AFPERR_BITMAP;
2310 goto setdirparam_done;
2314 err = AFPERR_BITMAP;
2315 goto setdirparam_done;
2324 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
2325 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2329 ad_setdate(&ad, AD_DATE_MODIFY, newdate);
2330 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
2335 if (path->st_valid && !path->st_errno) {
2336 struct stat *st = &path->st;
2338 if (dir && dir->d_parent) {
2339 ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_parent->d_did, vol->v_stamp);
2343 ad_close_metadata( &ad);
2346 if (change_parent_mdate && dir->d_did != DIRDID_ROOT
2347 && gettimeofday(&tv, NULL) == 0) {
2348 if (!movecwd(vol, dir->d_parent)) {
2349 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2350 /* be careful with bitmap because now dir is null */
2351 bitmap = 1<<DIRPBIT_MDATE;
2352 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
2353 /* should we reset curdir ?*/
2360 int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2374 memcpy( &vid, ibuf, sizeof( vid ));
2375 ibuf += sizeof( vid );
2376 if (NULL == (vol = getvolbyvid( vid )) ) {
2377 return( AFPERR_PARAM );
2380 memcpy( &did, ibuf, sizeof( did ));
2381 ibuf += sizeof( did );
2385 * if it's CNID 2 our only choice to meet the specs is call sync.
2386 * For any other CNID just sync that dir. To my knowledge the
2387 * intended use of FPSyncDir is to sync the volume so all we're
2388 * ever going to see here is probably CNID 2. Anyway, we' prepared.
2391 if ( ntohl(did) == 2 ) {
2394 if (NULL == ( dir = dirlookup( vol, did )) ) {
2395 return afp_errno; /* was AFPERR_NOOBJ */
2398 if (movecwd( vol, dir ) < 0 )
2399 return ( AFPERR_NOOBJ );
2402 * Assuming only OSens that have dirfd also may require fsyncing directories
2403 * in order to flush metadata e.g. Linux.
2407 if (NULL == ( dp = opendir( "." )) ) {
2410 return( AFPERR_NOOBJ );
2412 return( AFPERR_ACCESS );
2414 return( AFPERR_PARAM );
2418 LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
2421 if ( fsync ( dfd ) < 0 )
2422 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2423 dir->d_u_name, strerror(errno) );
2424 closedir(dp); /* closes dfd too */
2427 if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
2430 return( AFPERR_NOOBJ );
2432 return( AFPERR_ACCESS );
2434 return( AFPERR_PARAM );
2438 LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
2439 vol->ad_path(".", ADFLAGS_DIR) );
2441 if ( fsync(dfd) < 0 )
2442 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2443 vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
2450 int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2456 struct path *s_path;
2464 memcpy( &vid, ibuf, sizeof( vid ));
2465 ibuf += sizeof( vid );
2466 if (NULL == ( vol = getvolbyvid( vid )) ) {
2467 return( AFPERR_PARAM );
2470 if (vol->v_flags & AFPVOL_RO)
2471 return AFPERR_VLOCK;
2473 memcpy( &did, ibuf, sizeof( did ));
2474 ibuf += sizeof( did );
2475 if (NULL == ( dir = dirlookup( vol, did )) ) {
2476 return afp_errno; /* was AFPERR_NOOBJ */
2478 /* for concurrent access we need to be sure we are not in the
2479 * folder we want to create...
2483 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
2484 return get_afp_errno(AFPERR_PARAM);
2486 /* cname was able to move curdir to it! */
2487 if (*s_path->m_name == '\0')
2488 return AFPERR_EXIST;
2490 upath = s_path->u_name;
2492 if (AFP_OK != (err = netatalk_mkdir( upath))) {
2496 if (of_stat(s_path) < 0) {
2500 if ((dir = adddir( vol, curdir, s_path)) == NULL) {
2504 if ( movecwd( vol, dir ) < 0 ) {
2505 return( AFPERR_PARAM );
2508 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2509 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
2510 if (vol_noadouble(vol))
2511 goto createdir_done;
2512 return( AFPERR_ACCESS );
2514 ad_setname(&ad, s_path->m_name);
2515 ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
2518 ad_close_metadata( &ad);
2521 #ifdef HAVE_NFSv4_ACLS
2522 /* FIXME: are we really inside the created dir? */
2523 addir_inherit_acl(vol);
2526 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
2527 *rbuflen = sizeof( u_int32_t );
2528 setvoltime(obj, vol );
2533 * dst new unix filename (not a pathname)
2534 * newname new mac name
2538 int renamedir(const struct vol *vol, char *src, char *dst,
2540 struct dir *newparent,
2548 /* existence check moved to afp_moveandrename */
2549 if ( unix_rename( src, dst ) < 0 ) {
2552 return( AFPERR_NOOBJ );
2554 return( AFPERR_ACCESS );
2556 return AFPERR_VLOCK;
2558 /* tried to move directory into a subdirectory of itself */
2559 return AFPERR_CANTMOVE;
2561 /* this needs to copy and delete. bleah. that means we have
2562 * to deal with entire directory hierarchies. */
2563 if ((err = copydir(vol, src, dst)) < 0) {
2567 if ((err = deletedir(src)) < 0)
2571 return( AFPERR_PARAM );
2575 vol->vfs->vfs_renamedir(vol, src, dst);
2577 len = strlen( newname );
2578 /* rename() succeeded so we need to update our tree even if we can't open
2582 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2584 if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
2585 ad_setname(&ad, newname);
2587 ad_close_metadata( &ad);
2590 dir_hash_del(vol, dir);
2591 if (dir->d_m_name == dir->d_u_name)
2592 dir->d_u_name = NULL;
2594 if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
2595 LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
2596 /* FIXME : fatal ? */
2599 dir->d_m_name = buf;
2600 strcpy( dir->d_m_name, newname );
2602 if (newname == dst) {
2603 free(dir->d_u_name);
2604 dir->d_u_name = dir->d_m_name;
2607 if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
2608 LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
2611 dir->d_u_name = buf;
2612 strcpy( dir->d_u_name, dst );
2615 if (dir->d_m_name_ucs2)
2616 free(dir->d_m_name_ucs2);
2618 dir->d_m_name_ucs2 = NULL;
2619 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))
2620 dir->d_m_name_ucs2 = NULL;
2622 if (( parent = dir->d_parent ) == NULL ) {
2625 if ( parent == newparent ) {
2626 hash_alloc_insert(vol->v_hash, dir, dir);
2630 /* detach from old parent and add to new one. */
2631 dirchildremove(parent, dir);
2632 dir->d_parent = newparent;
2633 dirchildadd(vol, newparent, dir);
2637 /* delete an empty directory */
2638 int deletecurdir(struct vol *vol)
2648 if ( curdir->d_parent == NULL ) {
2649 return( AFPERR_ACCESS );
2654 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2655 /* we never want to create a resource fork here, we are going to delete it */
2656 if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
2658 ad_getattr(&ad, &ashort);
2659 ad_close( &ad, ADFLAGS_HF );
2660 if ((ashort & htons(ATTRBIT_NODELETE))) {
2661 return AFPERR_OLOCK;
2664 err = vol->vfs->vfs_deletecurdir(vol);
2669 /* now get rid of dangling symlinks */
2670 if ((dp = opendir("."))) {
2671 while ((de = readdir(dp))) {
2672 /* skip this and previous directory */
2673 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2676 /* bail if it's not a symlink */
2677 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
2679 return AFPERR_DIRNEMPT;
2682 if ((err = netatalk_unlink(de->d_name))) {
2689 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
2694 err = netatalk_rmdir_all_errors(fdir->d_u_name);
2695 if ( err == AFP_OK || err == AFPERR_NOOBJ) {
2696 dirchildremove(curdir, fdir);
2697 cnid_delete(vol->v_cdb, fdir->d_did);
2698 dir_remove( vol, fdir );
2702 /* inode is used as key for cnid.
2703 * Close the descriptor only after cnid_delete
2711 int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2721 sfunc = (unsigned char) *ibuf++;
2725 if (sfunc >= 3 && sfunc <= 6) {
2726 if (afp_version < 30) {
2727 return( AFPERR_PARAM );
2734 case 3 :/* unicode */
2735 memcpy( &id, ibuf, sizeof( id ));
2738 if (( pw = getpwuid( id )) == NULL ) {
2739 return( AFPERR_NOITEM );
2741 len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
2742 pw->pw_name, -1, &name);
2749 case 4 : /* unicode */
2750 memcpy( &id, ibuf, sizeof( id ));
2753 if (NULL == ( gr = (struct group *)getgrgid( id ))) {
2754 return( AFPERR_NOITEM );
2756 len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
2757 gr->gr_name, -1, &name);
2763 #ifdef HAVE_NFSv4_ACLS
2764 case 5 : /* UUID -> username */
2765 case 6 : /* UUID -> groupname */
2766 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2767 return AFPERR_PARAM;
2768 LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
2770 len = getnamefromuuid( ibuf, &name, &type);
2771 if (len != 0) /* its a error code, not len */
2772 return AFPERR_NOITEM;
2773 if (type == UUID_USER) {
2774 if (( pw = getpwnam( name )) == NULL )
2775 return( AFPERR_NOITEM );
2776 LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
2777 id = htonl(UUID_USER);
2778 memcpy( rbuf, &id, sizeof( id ));
2779 id = htonl( pw->pw_uid);
2780 rbuf += sizeof( id );
2781 memcpy( rbuf, &id, sizeof( id ));
2782 rbuf += sizeof( id );
2783 *rbuflen = 2 * sizeof( id );
2784 } else { /* type == UUID_GROUP */
2785 if (( gr = getgrnam( name )) == NULL )
2786 return( AFPERR_NOITEM );
2787 LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
2788 id = htonl(UUID_GROUP);
2789 memcpy( rbuf, &id, sizeof( id ));
2790 rbuf += sizeof( id );
2791 id = htonl( gr->gr_gid);
2792 memcpy( rbuf, &id, sizeof( id ));
2793 rbuf += sizeof( id );
2794 *rbuflen = 2 * sizeof( id );
2799 return( AFPERR_PARAM );
2803 len = strlen( name );
2806 u_int16_t tp = htons(len);
2807 memcpy(rbuf, &tp, sizeof(tp));
2816 memcpy( rbuf, name, len );
2824 int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2833 sfunc = (unsigned char) *ibuf++;
2835 LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
2838 case 2 : /* unicode */
2839 if (afp_version < 30) {
2840 return( AFPERR_PARAM );
2842 memcpy(&ulen, ibuf, sizeof(ulen));
2845 LOG(log_debug, logtype_afpd, "afp_mapname: alive");
2849 len = (unsigned char) *ibuf++;
2851 #ifdef HAVE_NFSv4_ACLS
2852 case 5 : /* username -> UUID */
2853 case 6 : /* groupname -> UUID */
2854 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2855 return AFPERR_PARAM;
2856 memcpy(&ulen, ibuf, sizeof(ulen));
2862 return( AFPERR_PARAM );
2868 return AFPERR_PARAM;
2871 case 1 : /* unicode */
2873 if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) {
2874 return( AFPERR_NOITEM );
2878 memcpy( rbuf, &id, sizeof( id ));
2879 *rbuflen = sizeof( id );
2882 case 2 : /* unicode */
2884 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
2885 if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
2886 return( AFPERR_NOITEM );
2889 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
2891 memcpy( rbuf, &id, sizeof( id ));
2892 *rbuflen = sizeof( id );
2894 #ifdef HAVE_NFSv4_ACLS
2895 case 5 : /* username -> UUID */
2896 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2897 if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
2898 return AFPERR_NOITEM;
2899 *rbuflen = UUID_BINSIZE;
2901 case 6 : /* groupname -> UUID */
2902 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2903 if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
2904 return AFPERR_NOITEM;
2905 *rbuflen = UUID_BINSIZE;
2913 /* ------------------------------------
2914 variable DID support
2916 int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2927 /* do nothing as dids are static for the life of the process. */
2931 memcpy(&vid, ibuf, sizeof( vid ));
2932 ibuf += sizeof( vid );
2933 if (( vol = getvolbyvid( vid )) == NULL ) {
2934 return( AFPERR_PARAM );
2937 memcpy( &did, ibuf, sizeof( did ));
2938 ibuf += sizeof( did );
2939 if (( dir = dirlookup( vol, did )) == NULL ) {
2940 return( AFPERR_PARAM );
2943 /* dir_remove -- deletedid */
2949 /* did creation gets done automatically
2950 * there's a pb again with case but move it to cname
2952 int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2955 struct dir *parentdir;
2963 memcpy(&vid, ibuf, sizeof(vid));
2964 ibuf += sizeof( vid );
2966 if (NULL == ( vol = getvolbyvid( vid )) ) {
2967 return( AFPERR_PARAM );
2970 memcpy(&did, ibuf, sizeof(did));
2971 ibuf += sizeof(did);
2973 if (NULL == ( parentdir = dirlookup( vol, did )) ) {
2977 if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
2978 return get_afp_errno(AFPERR_PARAM);
2981 if ( *path->m_name != '\0' ) {
2982 return path_error(path, AFPERR_NOOBJ);
2985 if ( !path->st_valid && of_stat(path ) < 0 ) {
2986 return( AFPERR_NOOBJ );
2988 if ( path->st_errno ) {
2989 return( AFPERR_NOOBJ );
2992 memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did));
2993 *rbuflen = sizeof(curdir->d_did);