2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
5 * 19 jan 2000 implemented red-black trees for directory lookups
11 #endif /* HAVE_CONFIG_H */
16 #else /* STDC_HEADERS */
20 #endif /* HAVE_STRCHR */
21 char *strchr (), *strrchr ();
23 #define memcpy(d,s,n) bcopy ((s), (d), (n))
24 #define memmove(d,s,n) bcopy ((s), (d), (n))
25 #endif /* ! HAVE_MEMCPY */
26 #endif /* STDC_HEADERS */
35 #include <sys/param.h>
39 #include <atalk/adouble.h>
40 #include <atalk/vfs.h>
41 #include <atalk/afp.h>
42 #include <atalk/util.h>
43 #include <atalk/cnid.h>
44 #include <atalk/logger.h>
45 #include <atalk/uuid.h>
46 #include <atalk/unix.h>
48 #include "directory.h"
59 #ifdef HAVE_NFSv4_ACLS
60 extern void addir_inherit_acl(const struct vol *vol);
67 * There are currently two cache structures where afpd caches directory information
68 * a) a DID/dirname cache in a hashtable
69 * b) a (red-black) tree with CNIDs as key
71 * a) is for searching by DID/dirname
72 * b) is for searching by CNID
74 * Through additional parent, child, previous and next pointers, b) is also used to
75 * represent the on-disk layout of the filesystem. parent and child point to parent
76 * and child directory respectively, linking 2 or more subdirectories in one
77 * directory with previous and next pointers.
79 * Usage examples, highlighting the main functions:
81 * a) is eg used in enumerate():
83 * dir = dirsearch_byname() // search in cache
84 * if (dir == NULL) // not found
85 * dir = adddir() // add to cache
88 * b) is eg used in afp_getfildirparams()
89 * dirlookup() // wrapper for cache and db search
90 * => dir = dirsearch() // search in cache
94 * cnid_resolve() // resolve with CNID database
95 * cname() // add to cache
101 #define SENTINEL (&sentinel)
102 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
103 DIRTREE_COLOR_BLACK, /* color */
104 NULL, NULL, /* parent, child */
105 NULL, NULL, /* previous, next */
106 NULL, 0, 0, /* oforks, did, flags */
107 0, 0, /* ctime, offcnt */
108 NULL, NULL, NULL}; /* mname, uname, ucs2-name */
109 static struct dir rootpar = { SENTINEL, SENTINEL, NULL,
117 /* (from IM: Toolbox Essentials)
118 * dirFinderInfo (DInfo) fields:
120 * frRect 8 folder's window rectangle
122 * frLocation 4 folder's location in window
123 * frView 2 folder's view (default == closedView (256))
125 * extended dirFinderInfo (DXInfo) fields:
126 * frScroll 4 scroll position
127 * frOpenChain: 4 directory ID chain of open folders
128 * frScript: 1 script flag and code
129 * frXFlags: 1 reserved
130 * frComment: 2 comment ID
131 * frPutAway: 4 home directory ID
135 vol_tree_root(const struct vol *vol, u_int32_t did)
139 if (vol->v_curdir && vol->v_curdir->d_did == did) {
149 * redid did assignment for directories. now we use red-black trees.
153 dirsearch(const struct vol *vol, u_int32_t did)
158 /* check for 0 did */
160 afp_errno = AFPERR_PARAM;
163 if ( did == DIRDID_ROOT_PARENT ) {
165 rootpar.d_did = DIRDID_ROOT_PARENT;
166 rootpar.d_child = vol->v_dir;
170 dir = vol_tree_root(vol, did);
172 afp_errno = AFPERR_NOOBJ;
173 while ( dir != SENTINEL ) {
174 if (dir->d_did == did)
175 return dir->d_m_name ? dir : NULL;
176 dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
181 /* ------------------- */
182 int get_afp_errno(const int param)
184 if (afp_errno != AFPERR_DID1)
189 /* ------------------- */
191 dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
193 struct dir *dir = NULL;
195 if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
201 hn = hash_lookup(vol->v_hash, &key);
209 /* -----------------------------------------
210 * if did is not in the cache resolve it with cnid
213 * OSX call it with bogus id, ie file ID not folder ID,
214 * and we are really bad in this case.
217 dirlookup( struct vol *vol, u_int32_t did)
222 static char path[MAXPATHLEN + 1];
225 static char buffer[12 + MAXPATHLEN + 1];
226 int buflen = 12 + MAXPATHLEN + 1;
231 ret = dirsearch(vol, did);
232 if (ret != NULL || afp_errno == AFPERR_PARAM)
235 utf8 = utf8_encoding();
236 maxpath = (utf8)?MAXPATHLEN -7:255;
238 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
239 afp_errno = AFPERR_NOOBJ;
242 ptr = path + MAXPATHLEN;
243 if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
244 afp_errno = AFPERR_NOOBJ;
248 pathlen = len; /* no 0 in the last part */
250 strcpy(ptr - len, mpath);
253 ret = dirsearch(vol,id);
258 if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
260 NULL == (mpath = utompath(vol, upath, cnid, utf8))
262 afp_errno = AFPERR_NOOBJ;
266 len = strlen(mpath) + 1;
268 if (pathlen > maxpath) {
269 afp_errno = AFPERR_PARAM;
272 strcpy(ptr - len, mpath);
276 /* fill the cache, another place where we know about the path type */
282 temp16 = htons(pathlen);
283 memcpy(ptr, &temp16, sizeof(temp16));
285 temp = htonl(kTextEncodingUTF8);
287 memcpy(ptr, &temp, sizeof(temp));
293 *ptr = (unsigned char)pathlen;
297 /* cname is not efficient */
298 if (cname( vol, ret, &ptr ) == NULL )
301 return dirsearch(vol, did);
304 /* child addition/removal */
305 static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
310 b->d_next = a->d_child;
311 b->d_prev = b->d_next->d_prev;
312 b->d_next->d_prev = b;
313 b->d_prev->d_next = b;
315 if (!hash_alloc_insert(vol->v_hash, b, b)) {
316 LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
320 static void dirchildremove(struct dir *a,struct dir *b)
323 a->d_child = (b == b->d_next) ? NULL : b->d_next;
324 b->d_next->d_prev = b->d_prev;
325 b->d_prev->d_next = b->d_next;
326 b->d_next = b->d_prev = b;
329 /* --------------------------- */
330 /* rotate the tree to the left */
331 static void dir_leftrotate(struct vol *vol, struct dir *dir)
333 struct dir *right = dir->d_right;
335 /* whee. move the right's left tree into dir's right tree */
336 dir->d_right = right->d_left;
337 if (right->d_left != SENTINEL)
338 right->d_left->d_back = dir;
340 if (right != SENTINEL) {
341 right->d_back = dir->d_back;
345 if (!dir->d_back) /* no parent. move the right tree to the top. */
347 else if (dir == dir->d_back->d_left) /* we were on the left */
348 dir->d_back->d_left = right;
350 dir->d_back->d_right = right; /* we were on the right */
352 /* re-insert dir on the left tree */
359 /* rotate the tree to the right */
360 static void dir_rightrotate(struct vol *vol, struct dir *dir)
362 struct dir *left = dir->d_left;
364 /* whee. move the left's right tree into dir's left tree */
365 dir->d_left = left->d_right;
366 if (left->d_right != SENTINEL)
367 left->d_right->d_back = dir;
369 if (left != SENTINEL) {
370 left->d_back = dir->d_back;
374 if (!dir->d_back) /* no parent. move the left tree to the top. */
376 else if (dir == dir->d_back->d_right) /* we were on the right */
377 dir->d_back->d_right = left;
379 dir->d_back->d_left = left; /* we were on the left */
381 /* re-insert dir on the right tree */
387 /* recolor after a removal */
388 static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
392 while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
393 /* are we on the left tree? */
394 if (dir == dir->d_back->d_left) {
395 leaf = dir->d_back->d_right; /* get right side */
396 if (leaf->d_color == DIRTREE_COLOR_RED) {
397 /* we're red. we need to change to black. */
398 leaf->d_color = DIRTREE_COLOR_BLACK;
399 dir->d_back->d_color = DIRTREE_COLOR_RED;
400 dir_leftrotate(vol, dir->d_back);
401 leaf = dir->d_back->d_right;
404 /* right leaf has black end nodes */
405 if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
406 (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
407 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
408 dir = dir->d_back; /* ascend */
410 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
411 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
412 leaf->d_color = DIRTREE_COLOR_RED;
413 dir_rightrotate(vol, leaf);
414 leaf = dir->d_back->d_right;
416 leaf->d_color = dir->d_back->d_color;
417 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
418 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
419 dir_leftrotate(vol, dir->d_back);
422 } else { /* right tree */
423 leaf = dir->d_back->d_left; /* left tree */
424 if (leaf->d_color == DIRTREE_COLOR_RED) {
425 leaf->d_color = DIRTREE_COLOR_BLACK;
426 dir->d_back->d_color = DIRTREE_COLOR_RED;
427 dir_rightrotate(vol, dir->d_back);
428 leaf = dir->d_back->d_left;
431 /* left leaf has black end nodes */
432 if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
433 (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
434 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
435 dir = dir->d_back; /* ascend */
437 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
438 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
439 leaf->d_color = DIRTREE_COLOR_RED;
440 dir_leftrotate(vol, leaf);
441 leaf = dir->d_back->d_left;
443 leaf->d_color = dir->d_back->d_color;
444 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
445 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
446 dir_rightrotate(vol, dir->d_back);
451 dir->d_color = DIRTREE_COLOR_BLACK;
457 /* --------------------- */
458 static void dir_hash_del(const struct vol *vol, struct dir *dir)
462 hn = hash_lookup(vol->v_hash, dir);
464 LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
467 hash_delete(vol->v_hash, hn);
471 /* remove the node from the tree. this is just like insertion, but
472 * different. actually, it has to worry about a bunch of things that
473 * insertion doesn't care about. */
475 static void dir_remove( struct vol *vol, struct dir *dir)
478 struct ofork *of, *last;
479 struct dir *node, *leaf;
480 #endif /* REMOVE_NODES */
482 if (!dir || (dir == SENTINEL))
485 /* i'm not sure if it really helps to delete stuff. */
486 dir_hash_del(vol, dir);
487 vol->v_curdir = NULL;
490 dir->d_m_name = NULL;
491 dir->d_u_name = NULL;
492 dir->d_m_name_ucs2 = NULL;
493 #else /* ! REMOVE_NODES */
495 /* go searching for a node with at most one child */
496 if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
500 while (node->d_left != SENTINEL)
505 leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
508 leaf->d_back = node->d_back;
511 } else if (node == node->d_back->d_left) { /* left tree */
512 node->d_back->d_left = leaf;
514 node->d_back->d_right = leaf;
517 /* we want to free node, but we also want to free the data in dir.
518 * currently, that's d_name and the directory traversal bits.
519 * we just copy the necessary bits and then fix up all the
520 * various pointers to the directory. needless to say, there are
521 * a bunch of places that store the directory struct. */
523 struct dir save, *tmp;
525 memcpy(&save, dir, sizeof(save));
526 memcpy(dir, node, sizeof(struct dir));
528 /* restore the red-black bits */
529 dir->d_left = save.d_left;
530 dir->d_right = save.d_right;
531 dir->d_back = save.d_back;
532 dir->d_color = save.d_color;
534 if (node == vol->v_dir) {/* we may need to fix up this pointer */
536 rootpar.d_child = vol->v_dir;
538 /* if we aren't the root directory, we have parents and
539 * siblings to worry about */
540 if (dir->d_parent->d_child == node)
541 dir->d_parent->d_child = dir;
542 dir->d_next->d_prev = dir;
543 dir->d_prev->d_next = dir;
546 /* fix up children. */
550 tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
553 if (node == curdir) /* another pointer to fixup */
556 /* we also need to fix up oforks. bleah */
557 if ((of = dir->d_ofork)) {
558 last = of->of_d_prev;
561 of = (last == of) ? NULL : of->of_d_next;
565 /* set the node's d_name */
566 node->d_m_name = save.d_m_name;
567 node->d_u_name = save.d_u_name;
568 node->d_m_name_ucs2 = save.d_m_name_ucs2;
571 if (node->d_color == DIRTREE_COLOR_BLACK)
572 dir_rmrecolor(vol, leaf);
574 if (node->d_m_name_ucs2)
575 free(node->d_u_name_ucs2);
576 if (node->d_u_name != node->d_m_name) {
577 free(node->d_u_name);
579 free(node->d_m_name);
581 #endif /* ! REMOVE_NODES */
584 /* ---------------------------------------
585 * remove the node and its childs from the tree
587 * FIXME what about opened forks with refs to it?
588 * it's an afp specs violation because you can't delete
589 * an opened forks. Now afpd doesn't care about forks opened by other
590 * process. It's fixable within afpd if fnctl_lock, doable with smb and
591 * next to impossible for nfs and local filesystem access.
593 static void dir_invalidate( struct vol *vol, struct dir *dir)
596 /* v_root can't be deleted */
597 if (movecwd(vol, vol->v_root) < 0) {
598 LOG(log_error, logtype_afpd, "cname can't chdir to : %s", vol->v_root);
602 dirchildremove(dir->d_parent, dir);
603 dir_remove( vol, dir );
606 /* ------------------------------------ */
607 static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
611 pdir = vol_tree_root(vol, dir->d_did);
612 while (pdir->d_did != dir->d_did ) {
613 if ( pdir->d_did > dir->d_did ) {
614 if ( pdir->d_left == SENTINEL ) {
621 if ( pdir->d_right == SENTINEL ) {
626 pdir = pdir->d_right;
632 #define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/"
635 caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
640 static u_int32_t did = 0;
641 static char cname[MAXPATHLEN];
642 static char lname[MAXPATHLEN];
643 ucs2_t u2_path[MAXPATHLEN];
644 ucs2_t u2_dename[MAXPATHLEN];
645 char *tmp, *savepath;
647 if (!(vol->v_flags & AFPVOL_CASEINSEN))
650 if (veto_file(ENUMVETO, path->u_name))
653 savepath = path->u_name;
655 /* very simple cache */
656 if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
657 path->u_name = cname;
659 if (of_stat( path ) == 0 ) {
662 /* something changed, we cannot stat ... */
666 if (NULL == ( dp = opendir( "." )) ) {
667 LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name);
672 /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
673 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) )
674 LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
676 /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
678 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
679 if (NULL == check_dirent(vol, de->d_name))
682 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) )
685 if (strcasecmp_w( u2_path, u2_dename) == 0) {
687 strlcpy(cname, de->d_name, sizeof(cname));
688 path->u_name = cname;
690 if (of_stat( path ) == 0 ) {
691 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
692 strlcpy(lname, tmp, sizeof(lname));
705 /* invalidate cache */
708 path->u_name = savepath;
710 /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */
716 * attempt to extend the current dir. tree to include path
717 * as a side-effect, movecwd to that point and return the new dir
720 extenddir(struct vol *vol, struct dir *dir, struct path *path)
724 if ( path->u_name == NULL) {
725 afp_errno = AFPERR_PARAM;
729 if (check_name(vol, path->u_name)) {
730 /* the name is illegal */
731 LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name);
733 afp_errno = AFPERR_PARAM;
737 if (of_stat( path ) != 0 ) {
738 if (!(vol->v_flags & AFPVOL_CASEINSEN))
740 else if(caseenumerate(vol, path, dir) != 0)
744 if (!S_ISDIR(path->st.st_mode)) {
748 /* mac name is always with the right encoding (from cname()) */
749 if (( dir = adddir( vol, dir, path)) == NULL ) {
754 if ( movecwd( vol, dir ) < 0 ) {
761 /* -------------------------
762 appledouble mkdir afp error code.
764 static int netatalk_mkdir(const struct vol *vol, const char *name)
769 if (vol->v_flags & AFPVOL_UNIX_PRIV) {
770 if (lstat(".", &st) < 0)
772 int mode = (DIRBITS & (~S_ISGID & st.st_mode)) | (0777 & ~vol->v_umask);
773 LOG(log_maxdebug, logtype_afpd, "netatalk_mkdir(\"%s\") {parent mode: %04o, vol umask: %04o}",
774 name, st.st_mode, vol->v_umask);
776 ret = mkdir(name, mode);
778 ret = ad_mkdir(name, DIRBITS | 0777);
784 return( AFPERR_NOOBJ );
786 return( AFPERR_VLOCK );
789 return( AFPERR_ACCESS );
791 return( AFPERR_EXIST );
794 return( AFPERR_DFULL );
796 return( AFPERR_PARAM );
802 /* ------------------- */
803 static int deletedir(int dirfd, char *dir)
805 char path[MAXPATHLEN + 1];
813 if ((len = strlen(dir)) +2 > sizeof(path))
817 if ((dp = opendirat(dirfd, dir)) == NULL)
823 remain = sizeof(path) -len -1;
824 while ((de = readdir(dp)) && err == AFP_OK) {
825 /* skip this and previous directory */
826 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
829 if (strlen(de->d_name) > remain) {
833 strcpy(path + len, de->d_name);
834 if (lstatat(dirfd, path, &st)) {
837 if (S_ISDIR(st.st_mode)) {
838 err = deletedir(dirfd, path);
840 err = netatalk_unlinkat(dirfd, path);
845 /* okay. the directory is empty. delete it. note: we already got rid
848 err = netatalk_rmdir(dirfd, dir);
853 /* do a recursive copy. */
854 static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
856 char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
865 /* doesn't exist or the path is too long. */
866 if (((slen = strlen(src)) > sizeof(spath) - 2) ||
867 ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
868 ((dp = opendirat(dirfd, src)) == NULL))
871 /* try to create the destination directory */
872 if (AFP_OK != (err = netatalk_mkdir(vol, dst)) ) {
877 /* set things up to copy */
881 srem = sizeof(spath) - slen -1;
886 drem = sizeof(dpath) - dlen -1;
889 while ((de = readdir(dp))) {
890 /* skip this and previous directory */
891 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
894 if (strlen(de->d_name) > srem) {
898 strcpy(spath + slen, de->d_name);
900 if (lstatat(dirfd, spath, &st) == 0) {
901 if (strlen(de->d_name) > drem) {
905 strcpy(dpath + dlen, de->d_name);
907 if (S_ISDIR(st.st_mode)) {
908 if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath)))
910 } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) {
914 /* keep the same time stamp. */
915 ut.actime = ut.modtime = st.st_mtime;
921 /* keep the same time stamp. */
922 if (lstatat(dirfd, src, &st) == 0) {
923 ut.actime = ut.modtime = st.st_mtime;
933 /* --- public functions follow --- */
935 /* NOTE: we start off with at least one node (the root directory). */
936 static struct dir *dirinsert(struct vol *vol, struct dir *dir)
940 if ((node = dir_insert(vol, dir)))
943 /* recolor the tree. the current node is red. */
944 dir->d_color = DIRTREE_COLOR_RED;
946 /* parent of this node has to be black. if the parent node
947 * is red, then we have a grandparent. */
948 while ((dir != vol->v_root) &&
949 (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
950 /* are we on the left tree? */
951 if (dir->d_back == dir->d_back->d_back->d_left) {
952 node = dir->d_back->d_back->d_right; /* get the right node */
953 if (node->d_color == DIRTREE_COLOR_RED) {
954 /* we're red. we need to change to black. */
955 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
956 node->d_color = DIRTREE_COLOR_BLACK;
957 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
958 dir = dir->d_back->d_back; /* finished. go up. */
960 if (dir == dir->d_back->d_right) {
962 dir_leftrotate(vol, dir);
964 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
965 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
966 dir_rightrotate(vol, dir->d_back->d_back);
969 node = dir->d_back->d_back->d_left;
970 if (node->d_color == DIRTREE_COLOR_RED) {
971 /* we're red. we need to change to black. */
972 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
973 node->d_color = DIRTREE_COLOR_BLACK;
974 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
975 dir = dir->d_back->d_back; /* finished. ascend */
977 if (dir == dir->d_back->d_left) {
979 dir_rightrotate(vol, dir);
981 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
982 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
983 dir_leftrotate(vol, dir->d_back->d_back);
988 vol->v_root->d_color = DIRTREE_COLOR_BLACK;
992 /* ---------------------------- */
994 adddir(struct vol *vol, struct dir *dir, struct path *path)
996 struct dir *cdir, *edir;
1003 struct adouble *adp = NULL;
1006 upath = path->u_name;
1008 upathlen = strlen(upath);
1010 /* get_id needs adp for reading CNID from adouble file */
1011 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1012 if ((ad_open_metadata(upath, ADFLAGS_DIR, 0, &ad)) == 0)
1015 id = get_id(vol, adp, st, dir->d_did, upath, upathlen);
1018 ad_close_metadata(adp);
1023 if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
1026 name = path->m_name;
1027 if ((cdir = dirnew(name, upath)) == NULL) {
1028 LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
1031 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)) {
1032 LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
1033 cdir->d_m_name_ucs2 = NULL;
1038 if ((edir = dirinsert( vol, cdir ))) {
1039 /* it's not possible with LASTDID
1041 - someone else have moved the directory.
1042 - it's a symlink inside the share.
1043 - it's an ID reused, the old directory was deleted but not
1044 the cnid record and the server've reused the inode for
1046 for HASH (we should get ride of HASH)
1047 - someone else have moved the directory.
1048 - it's an ID reused as above
1049 - it's a hash duplicate and we are in big trouble
1051 deleted = (edir->d_m_name == NULL);
1053 dir_hash_del(vol, edir);
1055 edir->d_m_name = cdir->d_m_name;
1056 edir->d_u_name = cdir->d_u_name;
1057 edir->d_m_name_ucs2 = cdir->d_m_name_ucs2;
1060 LOG(log_error, logtype_afpd, "adddir: insert %s", edir->d_m_name);
1061 if (!cdir->d_parent || (cdir->d_parent == dir && !deleted)) {
1062 hash_alloc_insert(vol->v_hash, cdir, cdir);
1065 /* the old was not in the same folder */
1067 dirchildremove(cdir->d_parent, cdir);
1070 /* parent/child directories */
1071 cdir->d_parent = dir;
1072 dirchildadd(vol, dir, cdir);
1076 /* --- public functions follow --- */
1077 /* free everything down. we don't bother to recolor as this is only
1078 * called to free the entire tree */
1079 void dirfreename(struct dir *dir)
1081 if (dir->d_u_name != dir->d_m_name) {
1082 free(dir->d_u_name);
1084 if (dir->d_m_name_ucs2)
1085 free(dir->d_m_name_ucs2);
1086 free(dir->d_m_name);
1089 void dirfree(struct dir *dir)
1091 if (!dir || (dir == SENTINEL))
1094 if ( dir->d_left != SENTINEL ) {
1095 dirfree( dir->d_left );
1097 if ( dir->d_right != SENTINEL ) {
1098 dirfree( dir->d_right );
1101 if (dir != SENTINEL) {
1107 /* --------------------------------------------
1108 * most of the time mac name and unix name are the same
1110 struct dir *dirnew(const char *m_name, const char *u_name)
1114 dir = (struct dir *) calloc(1, sizeof( struct dir ));
1118 if ((dir->d_m_name = strdup(m_name)) == NULL) {
1123 if (m_name == u_name || !strcmp(m_name, u_name)) {
1124 dir->d_u_name = dir->d_m_name;
1126 else if ((dir->d_u_name = strdup(u_name)) == NULL) {
1127 free(dir->d_m_name);
1132 dir->d_m_name_ucs2 = NULL;
1133 dir->d_left = dir->d_right = SENTINEL;
1134 dir->d_next = dir->d_prev = dir;
1139 /* ------------------ */
1140 static hash_val_t hash_fun_dir(const void *key)
1142 const struct dir *k = key;
1144 static unsigned long randbox[] = {
1145 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
1146 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
1147 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
1148 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
1151 const unsigned char *str = (unsigned char *)(k->d_u_name);
1152 hash_val_t acc = k->d_parent->d_did;
1155 acc ^= randbox[(*str + acc) & 0xf];
1156 acc = (acc << 1) | (acc >> 31);
1158 acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
1159 acc = (acc << 2) | (acc >> 30);
1167 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
1168 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
1169 #define get16bits(d) (*((const uint16_t *) (d)))
1172 #if !defined (get16bits)
1173 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
1174 +(uint32_t)(((const uint8_t *)(d))[0]) )
1177 static hash_val_t hash_fun2_dir(const void *key)
1179 const struct dir *k = key;
1180 const char *data = k->d_u_name;
1181 int len = strlen(k->d_u_name);
1182 hash_val_t hash = k->d_parent->d_did, tmp;
1188 for (;len > 0; len--) {
1189 hash += get16bits (data);
1190 tmp = (get16bits (data+2) << 11) ^ hash;
1191 hash = (hash << 16) ^ tmp;
1192 data += 2*sizeof (uint16_t);
1196 /* Handle end cases */
1198 case 3: hash += get16bits (data);
1200 hash ^= data[sizeof (uint16_t)] << 18;
1203 case 2: hash += get16bits (data);
1207 case 1: hash += *data;
1212 /* Force "avalanching" of final 127 bits */
1223 /* ---------------- */
1224 static int hash_comp_dir(const void *key1, const void *key2)
1226 const struct dir *k1 = key1;
1227 const struct dir *k2 = key2;
1229 return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
1232 /* ---------------- */
1236 return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
1239 /* ------------------ */
1240 static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
1243 movecwd failed some of dir path are not there anymore.
1244 FIXME Is it true with other errors?
1245 so we remove dir from the cache
1247 if (dir->d_did == DIRDID_ROOT_PARENT)
1249 if (afp_errno == AFPERR_ACCESS) {
1250 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1253 /* FIXME should we set these?, don't need to call stat() after:
1255 ret->st_errno = EACCES;
1257 ret->m_name = dir->d_m_name;
1258 ret->u_name = dir->d_u_name;
1261 } else if (afp_errno == AFPERR_NOOBJ) {
1262 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1265 strcpy(ret->m_name, dir->d_m_name);
1266 if (dir->d_m_name == dir->d_u_name) {
1267 ret->u_name = ret->m_name;
1270 size_t tp = strlen(ret->m_name)+1;
1272 ret->u_name = ret->m_name +tp;
1273 strcpy(ret->u_name, dir->d_u_name);
1275 /* FIXME should we set :
1277 ret->st_errno = ENOENT;
1279 dir_invalidate(vol, dir);
1282 dir_invalidate(vol, dir);
1286 /* -------------------------------------------------- */
1292 stat the file or errno
1295 curdir: filename parent directory
1301 stat the dir or errno
1305 curdir: dir parent directory
1313 curdir: dir parent directory
1320 cname(struct vol *vol, struct dir *dir, char **cpath)
1322 struct dir *cdir, *scdir=NULL;
1323 static char path[ MAXPATHLEN + 1];
1324 static struct path ret;
1336 afp_errno = AFPERR_NOOBJ;
1337 memset(&ret, 0, sizeof(ret));
1338 switch (ret.m_type = *data) { /* path type */
1341 len = (unsigned char) *data++;
1344 if (afp_version >= 30) {
1350 if (afp_version >= 30) {
1352 memcpy(&hint, data, sizeof(hint));
1354 data += sizeof(hint);
1356 memcpy(&len16, data, sizeof(len16));
1363 /* else it's an error */
1365 afp_errno = AFPERR_PARAM;
1368 *cpath += len + size;
1373 if (movecwd( vol, dir ) < 0 ) {
1374 return invalidate(vol, dir, &ret );
1376 if (*path == '\0') {
1383 if (*data == sep ) {
1387 while (*data == sep && len > 0 ) {
1388 if ( dir->d_parent == NULL ) {
1391 dir = dir->d_parent;
1396 /* would this be faster with strlen + strncpy? */
1398 while ( *data != sep && len > 0 ) {
1400 if (p > &path[ MAXPATHLEN]) {
1401 afp_errno = AFPERR_PARAM;
1407 /* short cut bits by chopping off a trailing \0. this also
1408 makes the traversal happy w/ filenames at the end of the
1415 if ( p == path ) { /* end of the name parameter */
1419 if (afp_version >= 30) {
1424 static char temp[ MAXPATHLEN + 1];
1426 if (dir->d_did == DIRDID_ROOT_PARENT) {
1428 With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
1429 So we compare it with the longname from the current volume and if they match
1430 we overwrite the requested path with the utf8 volume name so that the following
1433 ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
1434 if (strcasecmp( path, temp) == 0)
1435 ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
1438 if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
1439 afp_errno = AFPERR_PARAM;
1446 if (strlen(ret.m_name) > 255) { /* Safeguard */
1447 afp_errno = AFPERR_PARAM;
1451 /* check for OS X mangled filename :( */
1453 t = demangle_osx(vol, path, dir->d_did, &fileid);
1456 /* duplicate work but we can't reuse all convert_char we did in demangle_osx
1457 * flags weren't the same
1459 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
1460 /* at last got our view of mac name */
1465 if (ret.u_name == NULL) {
1466 if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
1467 afp_errno = AFPERR_PARAM;
1473 cdir = dir->d_child;
1475 if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
1476 (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
1477 CH_UCS2, path, -1, (char **)&tmpname) )
1480 if (!cdir->d_m_name_ucs2) {
1481 LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
1482 /* this shouldn't happen !!!! */
1486 if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1489 if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1492 cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
1498 if (dir->d_did == DIRDID_ROOT_PARENT) {
1500 root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
1501 must check against the volume name.
1503 if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
1509 cdir = dirsearch_byname(vol, dir, ret.u_name);
1513 if (cdir == NULL && scdir != NULL) {
1515 /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
1518 if ( cdir == NULL ) {
1520 /* if dir == curdir it always succeed,
1521 even if curdir is deleted.
1522 it's not a pb because it will fail in extenddir
1524 if ( movecwd( vol, dir ) < 0 ) {
1525 /* dir is not valid anymore
1526 we delete dir from the cache and abort.
1528 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1529 afp_errno = AFPERR_NOOBJ;
1532 if (afp_errno == AFPERR_ACCESS)
1534 dir_invalidate(vol, dir);
1537 cdir = extenddir( vol, dir, &ret );
1541 cdir = extenddir( vol, dir, &ret );
1542 } /* if (!extend) */
1544 if ( cdir == NULL ) {
1546 if ( len > 0 || !ret.u_name ) {
1558 * Move curdir to dir, with a possible chdir()
1560 int movecwd(struct vol *vol, struct dir *dir)
1562 char path[MAXPATHLEN + 1];
1568 if ( dir == curdir ) {
1571 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1572 afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
1576 p = path + sizeof(path) - 1;
1578 for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
1581 /* parent directory is deleted */
1582 afp_errno = AFPERR_NOOBJ;
1586 if (p -n -1 < path) {
1587 afp_errno = AFPERR_PARAM;
1594 if ( d != curdir ) {
1595 n = strlen( vol->v_path );
1596 if (p -n -1 < path) {
1597 afp_errno = AFPERR_PARAM;
1602 memcpy( p, vol->v_path, n );
1604 if ( (ret = lchdir(p )) != 0 ) {
1605 LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
1608 /* p is a symlink or getcwd failed */
1609 afp_errno = AFPERR_BADTYPE;
1610 vol->v_curdir = curdir = vol->v_dir;
1611 if (chdir(vol->v_path ) < 0) {
1612 LOG(log_debug, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
1613 /* XXX what do we do here? */
1620 afp_errno = AFPERR_ACCESS;
1623 afp_errno = AFPERR_NOOBJ;
1628 vol->v_curdir = curdir = dir;
1633 * We can't use unix file's perm to support Apple's inherited protection modes.
1634 * If we aren't the file's owner we can't change its perms when moving it and smb
1635 * nfs,... don't even try.
1637 #define AFP_CHECK_ACCESS
1639 int check_access(char *path, int mode)
1641 #ifdef AFP_CHECK_ACCESS
1649 accessmode(p, &ma, curdir, NULL);
1650 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1652 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1658 /* --------------------- */
1659 int file_access(struct path *path, int mode)
1663 accessmode(path->u_name, &ma, curdir, &path->st);
1664 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1666 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1672 /* --------------------- */
1673 void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
1675 dir->offcnt = count;
1676 dir->ctime = st->st_ctime;
1677 dir->d_flags &= ~DIRF_CNID;
1680 /* ---------------------
1681 * is our cached offspring count valid?
1684 static int diroffcnt(struct dir *dir, struct stat *st)
1686 return st->st_ctime == dir->ctime;
1689 /* ---------------------
1690 * is our cached also for reenumerate id?
1693 int dirreenumerate(struct dir *dir, struct stat *st)
1695 return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
1698 /* --------------------- */
1699 static int invisible_dots(const struct vol *vol, const char *name)
1701 return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
1704 /* ------------------------------
1706 (name, dir) with curdir:name == dir, from afp_enumerate
1709 int getdirparams(const struct vol *vol,
1710 u_int16_t bitmap, struct path *s_path,
1712 char *buf, size_t *buflen )
1716 char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
1717 int bit = 0, isad = 0;
1723 struct stat *st = &s_path->st;
1724 char *upath = s_path->u_name;
1726 if ((bitmap & ((1 << DIRPBIT_ATTR) |
1727 (1 << DIRPBIT_CDATE) |
1728 (1 << DIRPBIT_MDATE) |
1729 (1 << DIRPBIT_BDATE) |
1730 (1 << DIRPBIT_FINFO)))) {
1732 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1733 if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
1735 if (ad.ad_md->adf_flags & O_CREAT) {
1736 /* We just created it */
1737 ad_setname(&ad, s_path->m_name);
1742 dir->d_parent->d_did,
1749 if ( dir->d_did == DIRDID_ROOT) {
1750 pdid = DIRDID_ROOT_PARENT;
1751 } else if (dir->d_did == DIRDID_ROOT_PARENT) {
1754 pdid = dir->d_parent->d_did;
1758 while ( bitmap != 0 ) {
1759 while (( bitmap & 1 ) == 0 ) {
1767 ad_getattr(&ad, &ashort);
1768 } else if (invisible_dots(vol, dir->d_u_name)) {
1769 ashort = htons(ATTRBIT_INVISIBLE);
1772 ashort |= htons(ATTRBIT_SHARED);
1773 memcpy( data, &ashort, sizeof( ashort ));
1774 data += sizeof( ashort );
1778 memcpy( data, &pdid, sizeof( pdid ));
1779 data += sizeof( pdid );
1782 case DIRPBIT_CDATE :
1783 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1784 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1785 memcpy( data, &aint, sizeof( aint ));
1786 data += sizeof( aint );
1789 case DIRPBIT_MDATE :
1790 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1791 memcpy( data, &aint, sizeof( aint ));
1792 data += sizeof( aint );
1795 case DIRPBIT_BDATE :
1796 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
1797 aint = AD_DATE_START;
1798 memcpy( data, &aint, sizeof( aint ));
1799 data += sizeof( aint );
1802 case DIRPBIT_FINFO :
1804 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
1805 } else { /* no appledouble */
1806 memset( data, 0, 32 );
1807 /* set default view -- this also gets done in ad_open() */
1808 ashort = htons(FINDERINFO_CLOSEDVIEW);
1809 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
1811 /* dot files are by default visible */
1812 if (invisible_dots(vol, dir->d_u_name)) {
1813 ashort = htons(FINDERINFO_INVISIBLE);
1814 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
1820 case DIRPBIT_LNAME :
1821 if (dir->d_m_name) /* root of parent can have a null name */
1824 memset(data, 0, sizeof(u_int16_t));
1825 data += sizeof( u_int16_t );
1828 case DIRPBIT_SNAME :
1829 memset(data, 0, sizeof(u_int16_t));
1830 data += sizeof( u_int16_t );
1834 memcpy( data, &dir->d_did, sizeof( aint ));
1835 data += sizeof( aint );
1838 case DIRPBIT_OFFCNT :
1840 /* this needs to handle current directory access rights */
1841 if (diroffcnt(dir, st)) {
1842 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1844 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
1845 setdiroffcnt(dir, st, ret);
1846 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1848 ashort = htons( ashort );
1849 memcpy( data, &ashort, sizeof( ashort ));
1850 data += sizeof( ashort );
1854 aint = htonl(st->st_uid);
1855 memcpy( data, &aint, sizeof( aint ));
1856 data += sizeof( aint );
1860 aint = htonl(st->st_gid);
1861 memcpy( data, &aint, sizeof( aint ));
1862 data += sizeof( aint );
1865 case DIRPBIT_ACCESS :
1866 accessmode( upath, &ma, dir , st);
1868 *data++ = ma.ma_user;
1869 *data++ = ma.ma_world;
1870 *data++ = ma.ma_group;
1871 *data++ = ma.ma_owner;
1874 /* Client has requested the ProDOS information block.
1875 Just pass back the same basic block for all
1876 directories. <shirsch@ibm.net> */
1877 case DIRPBIT_PDINFO :
1878 if (afp_version >= 30) { /* UTF8 name */
1879 utf8 = kTextEncodingUTF8;
1880 if (dir->d_m_name) /* root of parent can have a null name */
1883 memset(data, 0, sizeof(u_int16_t));
1884 data += sizeof( u_int16_t );
1886 memcpy(data, &aint, sizeof( aint ));
1887 data += sizeof( aint );
1889 else { /* ProDOS Info Block */
1892 ashort = htons( 0x0200 );
1893 memcpy( data, &ashort, sizeof( ashort ));
1894 data += sizeof( ashort );
1895 memset( data, 0, sizeof( ashort ));
1896 data += sizeof( ashort );
1900 case DIRPBIT_UNIXPR :
1901 aint = htonl(st->st_uid);
1902 memcpy( data, &aint, sizeof( aint ));
1903 data += sizeof( aint );
1904 aint = htonl(st->st_gid);
1905 memcpy( data, &aint, sizeof( aint ));
1906 data += sizeof( aint );
1909 aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
1910 memcpy( data, &aint, sizeof( aint ));
1911 data += sizeof( aint );
1913 accessmode( upath, &ma, dir , st);
1915 *data++ = ma.ma_user;
1916 *data++ = ma.ma_world;
1917 *data++ = ma.ma_group;
1918 *data++ = ma.ma_owner;
1923 ad_close_metadata( &ad );
1925 return( AFPERR_BITMAP );
1931 ashort = htons( data - buf );
1932 memcpy( l_nameoff, &ashort, sizeof( ashort ));
1933 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, 0);
1935 if ( utf_nameoff ) {
1936 ashort = htons( data - buf );
1937 memcpy( utf_nameoff, &ashort, sizeof( ashort ));
1938 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, utf8);
1941 ad_close_metadata( &ad );
1943 *buflen = data - buf;
1947 /* ----------------------------- */
1948 int path_error(struct path *path, int error)
1950 /* - a dir with access error
1951 * - no error it's a file
1954 if (path_isadir(path))
1956 if (path->st_valid && path->st_errno)
1958 return AFPERR_BADTYPE ;
1961 /* ----------------------------- */
1962 int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1967 u_int16_t vid, bitmap;
1973 memcpy( &vid, ibuf, sizeof( vid ));
1974 ibuf += sizeof( vid );
1976 if (NULL == ( vol = getvolbyvid( vid )) ) {
1977 return( AFPERR_PARAM );
1980 if (vol->v_flags & AFPVOL_RO)
1981 return AFPERR_VLOCK;
1983 memcpy( &did, ibuf, sizeof( did ));
1984 ibuf += sizeof( int );
1986 if (NULL == ( dir = dirlookup( vol, did )) ) {
1990 memcpy( &bitmap, ibuf, sizeof( bitmap ));
1991 bitmap = ntohs( bitmap );
1992 ibuf += sizeof( bitmap );
1994 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1995 return get_afp_errno(AFPERR_NOOBJ);
1998 if ( *path->m_name != '\0' ) {
1999 rc = path_error(path, AFPERR_NOOBJ);
2000 /* maybe we are trying to set perms back */
2001 if (rc != AFPERR_ACCESS)
2006 * If ibuf is odd, make it even.
2008 if ((u_long)ibuf & 1 ) {
2012 if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
2013 setvoltime(obj, vol );
2019 * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
2021 * assume path == '\0' eg. it's a directory in canonical form
2024 struct path Cur_Path = {
2027 ".", /* unix name */
2029 NULL,/* struct dir */
2030 0, /* stat is not set */
2033 /* ------------------ */
2034 static int set_dir_errors(struct path *path, const char *where, int err)
2039 return AFPERR_ACCESS;
2041 return AFPERR_VLOCK;
2043 LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
2044 return AFPERR_PARAM;
2047 /* ------------------ */
2048 int setdirparams(struct vol *vol,
2049 struct path *path, u_int16_t d_bitmap, char *buf )
2061 u_int16_t ashort, bshort, oshort;
2063 int change_mdate = 0;
2064 int change_parent_mdate = 0;
2066 u_int16_t bitmap = d_bitmap;
2067 u_char finder_buf[32];
2070 u_int16_t upriv_bit = 0;
2073 upath = path->u_name;
2075 while ( bitmap != 0 ) {
2076 while (( bitmap & 1 ) == 0 ) {
2084 memcpy( &ashort, buf, sizeof( ashort ));
2085 buf += sizeof( ashort );
2087 case DIRPBIT_CDATE :
2089 memcpy(&cdate, buf, sizeof(cdate));
2090 buf += sizeof( cdate );
2092 case DIRPBIT_MDATE :
2093 memcpy(&newdate, buf, sizeof(newdate));
2094 buf += sizeof( newdate );
2096 case DIRPBIT_BDATE :
2098 memcpy(&bdate, buf, sizeof(bdate));
2099 buf += sizeof( bdate );
2101 case DIRPBIT_FINFO :
2103 memcpy( finder_buf, buf, 32 );
2106 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2107 change_parent_mdate = 1;
2108 memcpy( &owner, buf, sizeof(owner));
2109 buf += sizeof( owner );
2112 change_parent_mdate = 1;
2113 memcpy( &group, buf, sizeof( group ));
2114 buf += sizeof( group );
2116 case DIRPBIT_ACCESS :
2118 change_parent_mdate = 1;
2119 ma.ma_user = *buf++;
2120 ma.ma_world = *buf++;
2121 ma.ma_group = *buf++;
2122 ma.ma_owner = *buf++;
2123 mpriv = mtoumode( &ma ) | vol->v_dperm;
2124 if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2125 err = set_dir_errors(path, "setdirmode", errno);
2129 /* Ignore what the client thinks we should do to the
2130 ProDOS information block. Skip over the data and
2131 report nothing amiss. <shirsch@ibm.net> */
2132 case DIRPBIT_PDINFO :
2133 if (afp_version < 30) {
2137 err = AFPERR_BITMAP;
2141 case DIRPBIT_UNIXPR :
2142 if (vol_unix_priv(vol)) {
2143 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
2144 buf += sizeof( owner );
2145 memcpy( &group, buf, sizeof( group ));
2146 buf += sizeof( group );
2149 change_parent_mdate = 1;
2150 memcpy( &upriv, buf, sizeof( upriv ));
2151 buf += sizeof( upriv );
2152 upriv = ntohl (upriv) | vol->v_dperm;
2153 if (dir_rx_set(upriv)) {
2154 /* maybe we are trying to set perms back */
2155 if ( setdirunixmode(vol, upath, upriv) < 0 ) {
2157 err = set_dir_errors(path, "setdirunixmode", errno);
2168 err = AFPERR_BITMAP;
2176 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2178 if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
2180 * Check to see what we're trying to set. If it's anything
2181 * but ACCESS, UID, or GID, give an error. If it's any of those
2182 * three, we don't need the ad to be open, so just continue.
2184 * note: we also don't need to worry about mdate. also, be quiet
2185 * if we're using the noadouble option.
2187 if (!vol_noadouble(vol) && (d_bitmap &
2188 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
2189 (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
2190 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
2191 return AFPERR_ACCESS;
2197 * Check to see if a create was necessary. If it was, we'll want
2198 * to set our name, etc.
2200 if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
2201 ad_setname(&ad, curdir->d_m_name);
2207 while ( bitmap != 0 ) {
2208 while (( bitmap & 1 ) == 0 ) {
2216 ad_getattr(&ad, &bshort);
2218 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
2219 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
2223 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
2224 change_parent_mdate = 1;
2225 ad_setattr(&ad, bshort);
2228 case DIRPBIT_CDATE :
2230 ad_setdate(&ad, AD_DATE_CREATE, cdate);
2233 case DIRPBIT_MDATE :
2235 case DIRPBIT_BDATE :
2237 ad_setdate(&ad, AD_DATE_BACKUP, bdate);
2240 case DIRPBIT_FINFO :
2242 /* Fixes #2802236 */
2243 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
2244 *fflags &= htons(~FINDERINFO_ISHARED);
2246 if ( dir->d_did == DIRDID_ROOT ) {
2248 * Alright, we admit it, this is *really* sick!
2249 * The 4 bytes that we don't copy, when we're dealing
2250 * with the root of a volume, are the directory's
2251 * location information. This eliminates that annoying
2252 * behavior one sees when mounting above another mount
2255 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
2256 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
2258 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
2262 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2263 if ( (dir->d_did == DIRDID_ROOT) &&
2264 (setdeskowner( ntohl(owner), -1 ) < 0)) {
2265 err = set_dir_errors(path, "setdeskowner", errno);
2266 if (isad && err == AFPERR_PARAM) {
2267 err = AFP_OK; /* ???*/
2270 goto setdirparam_done;
2273 if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
2274 err = set_dir_errors(path, "setdirowner", errno);
2275 goto setdirparam_done;
2279 if (dir->d_did == DIRDID_ROOT)
2280 setdeskowner( -1, ntohl(group) );
2281 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2282 err = set_dir_errors(path, "setdirowner", errno);
2283 goto setdirparam_done;
2286 case DIRPBIT_ACCESS :
2287 if (dir->d_did == DIRDID_ROOT) {
2289 if (!dir_rx_set(mpriv)) {
2290 /* we can't remove read and search for owner on volume root */
2291 err = AFPERR_ACCESS;
2292 goto setdirparam_done;
2296 if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2297 err = set_dir_errors(path, "setdirmode", errno);
2298 goto setdirparam_done;
2301 case DIRPBIT_PDINFO :
2302 if (afp_version >= 30) {
2303 err = AFPERR_BITMAP;
2304 goto setdirparam_done;
2307 case DIRPBIT_UNIXPR :
2308 if (vol_unix_priv(vol)) {
2309 if (dir->d_did == DIRDID_ROOT) {
2310 if (!dir_rx_set(upriv)) {
2311 /* we can't remove read and search for owner on volume root */
2312 err = AFPERR_ACCESS;
2313 goto setdirparam_done;
2315 setdeskowner( -1, ntohl(group) );
2316 setdeskmode( upriv );
2318 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2319 err = set_dir_errors(path, "setdirowner", errno);
2320 goto setdirparam_done;
2323 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
2324 err = set_dir_errors(path, "setdirunixmode", errno);
2325 goto setdirparam_done;
2329 err = AFPERR_BITMAP;
2330 goto setdirparam_done;
2334 err = AFPERR_BITMAP;
2335 goto setdirparam_done;
2344 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
2345 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2349 ad_setdate(&ad, AD_DATE_MODIFY, newdate);
2350 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
2355 if (path->st_valid && !path->st_errno) {
2356 struct stat *st = &path->st;
2358 if (dir && dir->d_parent) {
2359 ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_parent->d_did, vol->v_stamp);
2363 ad_close_metadata( &ad);
2366 if (change_parent_mdate && dir->d_did != DIRDID_ROOT
2367 && gettimeofday(&tv, NULL) == 0) {
2368 if (!movecwd(vol, dir->d_parent)) {
2369 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2370 /* be careful with bitmap because now dir is null */
2371 bitmap = 1<<DIRPBIT_MDATE;
2372 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
2373 /* should we reset curdir ?*/
2380 int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2394 memcpy( &vid, ibuf, sizeof( vid ));
2395 ibuf += sizeof( vid );
2396 if (NULL == (vol = getvolbyvid( vid )) ) {
2397 return( AFPERR_PARAM );
2400 memcpy( &did, ibuf, sizeof( did ));
2401 ibuf += sizeof( did );
2405 * if it's CNID 2 our only choice to meet the specs is call sync.
2406 * For any other CNID just sync that dir. To my knowledge the
2407 * intended use of FPSyncDir is to sync the volume so all we're
2408 * ever going to see here is probably CNID 2. Anyway, we' prepared.
2411 if ( ntohl(did) == 2 ) {
2414 if (NULL == ( dir = dirlookup( vol, did )) ) {
2415 return afp_errno; /* was AFPERR_NOOBJ */
2418 if (movecwd( vol, dir ) < 0 )
2419 return ( AFPERR_NOOBJ );
2422 * Assuming only OSens that have dirfd also may require fsyncing directories
2423 * in order to flush metadata e.g. Linux.
2427 if (NULL == ( dp = opendir( "." )) ) {
2430 return( AFPERR_NOOBJ );
2432 return( AFPERR_ACCESS );
2434 return( AFPERR_PARAM );
2438 LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
2441 if ( fsync ( dfd ) < 0 )
2442 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2443 dir->d_u_name, strerror(errno) );
2444 closedir(dp); /* closes dfd too */
2447 if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
2450 return( AFPERR_NOOBJ );
2452 return( AFPERR_ACCESS );
2454 return( AFPERR_PARAM );
2458 LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
2459 vol->ad_path(".", ADFLAGS_DIR) );
2461 if ( fsync(dfd) < 0 )
2462 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2463 vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
2470 int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2476 struct path *s_path;
2484 memcpy( &vid, ibuf, sizeof( vid ));
2485 ibuf += sizeof( vid );
2486 if (NULL == ( vol = getvolbyvid( vid )) ) {
2487 return( AFPERR_PARAM );
2490 if (vol->v_flags & AFPVOL_RO)
2491 return AFPERR_VLOCK;
2493 memcpy( &did, ibuf, sizeof( did ));
2494 ibuf += sizeof( did );
2495 if (NULL == ( dir = dirlookup( vol, did )) ) {
2496 return afp_errno; /* was AFPERR_NOOBJ */
2498 /* for concurrent access we need to be sure we are not in the
2499 * folder we want to create...
2503 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
2504 return get_afp_errno(AFPERR_PARAM);
2506 /* cname was able to move curdir to it! */
2507 if (*s_path->m_name == '\0')
2508 return AFPERR_EXIST;
2510 upath = s_path->u_name;
2512 if (AFP_OK != (err = netatalk_mkdir(vol, upath))) {
2516 if (of_stat(s_path) < 0) {
2520 if ((dir = adddir( vol, curdir, s_path)) == NULL) {
2524 if ( movecwd( vol, dir ) < 0 ) {
2525 return( AFPERR_PARAM );
2528 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2529 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
2530 if (vol_noadouble(vol))
2531 goto createdir_done;
2532 return( AFPERR_ACCESS );
2534 ad_setname(&ad, s_path->m_name);
2535 ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
2538 ad_close_metadata( &ad);
2541 #ifdef HAVE_NFSv4_ACLS
2542 /* FIXME: are we really inside the created dir? */
2543 addir_inherit_acl(vol);
2546 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
2547 *rbuflen = sizeof( u_int32_t );
2548 setvoltime(obj, vol );
2553 * dst new unix filename (not a pathname)
2554 * newname new mac name
2556 * dirfd -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd
2558 int renamedir(const struct vol *vol,
2563 struct dir *newparent,
2571 /* existence check moved to afp_moveandrename */
2572 if ( unix_rename(dirfd, src, -1, dst ) < 0 ) {
2575 return( AFPERR_NOOBJ );
2577 return( AFPERR_ACCESS );
2579 return AFPERR_VLOCK;
2581 /* tried to move directory into a subdirectory of itself */
2582 return AFPERR_CANTMOVE;
2584 /* this needs to copy and delete. bleah. that means we have
2585 * to deal with entire directory hierarchies. */
2586 if ((err = copydir(vol, dirfd, src, dst)) < 0) {
2590 if ((err = deletedir(dirfd, src)) < 0)
2594 return( AFPERR_PARAM );
2598 vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
2600 len = strlen( newname );
2601 /* rename() succeeded so we need to update our tree even if we can't open
2605 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2607 if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
2608 ad_setname(&ad, newname);
2610 ad_close_metadata( &ad);
2613 dir_hash_del(vol, dir);
2614 if (dir->d_m_name == dir->d_u_name)
2615 dir->d_u_name = NULL;
2617 if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
2618 LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
2619 /* FIXME : fatal ? */
2622 dir->d_m_name = buf;
2623 strcpy( dir->d_m_name, newname );
2625 if (newname == dst) {
2626 free(dir->d_u_name);
2627 dir->d_u_name = dir->d_m_name;
2630 if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
2631 LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
2634 dir->d_u_name = buf;
2635 strcpy( dir->d_u_name, dst );
2638 if (dir->d_m_name_ucs2)
2639 free(dir->d_m_name_ucs2);
2641 dir->d_m_name_ucs2 = NULL;
2642 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))
2643 dir->d_m_name_ucs2 = NULL;
2645 if (( parent = dir->d_parent ) == NULL ) {
2648 if ( parent == newparent ) {
2649 hash_alloc_insert(vol->v_hash, dir, dir);
2653 /* detach from old parent and add to new one. */
2654 dirchildremove(parent, dir);
2655 dir->d_parent = newparent;
2656 dirchildadd(vol, newparent, dir);
2660 /* delete an empty directory */
2661 int deletecurdir(struct vol *vol)
2671 if ( curdir->d_parent == NULL ) {
2672 return( AFPERR_ACCESS );
2677 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2678 /* we never want to create a resource fork here, we are going to delete it */
2679 if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
2681 ad_getattr(&ad, &ashort);
2682 ad_close_metadata(&ad);
2683 if ((ashort & htons(ATTRBIT_NODELETE))) {
2684 return AFPERR_OLOCK;
2687 err = vol->vfs->vfs_deletecurdir(vol);
2692 /* now get rid of dangling symlinks */
2693 if ((dp = opendir("."))) {
2694 while ((de = readdir(dp))) {
2695 /* skip this and previous directory */
2696 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2699 /* bail if it's not a symlink */
2700 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
2702 return AFPERR_DIRNEMPT;
2705 if ((err = netatalk_unlink(de->d_name))) {
2712 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
2717 err = netatalk_rmdir_all_errors(-1, fdir->d_u_name);
2718 if ( err == AFP_OK || err == AFPERR_NOOBJ) {
2719 dirchildremove(curdir, fdir);
2720 cnid_delete(vol->v_cdb, fdir->d_did);
2721 dir_remove( vol, fdir );
2725 /* inode is used as key for cnid.
2726 * Close the descriptor only after cnid_delete
2734 int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2744 sfunc = (unsigned char) *ibuf++;
2748 if (sfunc >= 3 && sfunc <= 6) {
2749 if (afp_version < 30) {
2750 return( AFPERR_PARAM );
2757 case 3 :/* unicode */
2758 memcpy( &id, ibuf, sizeof( id ));
2761 if (( pw = getpwuid( id )) == NULL ) {
2762 return( AFPERR_NOITEM );
2764 len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
2765 pw->pw_name, -1, &name);
2772 case 4 : /* unicode */
2773 memcpy( &id, ibuf, sizeof( id ));
2776 if (NULL == ( gr = (struct group *)getgrgid( id ))) {
2777 return( AFPERR_NOITEM );
2779 len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
2780 gr->gr_name, -1, &name);
2786 #ifdef HAVE_NFSv4_ACLS
2787 case 5 : /* UUID -> username */
2788 case 6 : /* UUID -> groupname */
2789 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2790 return AFPERR_PARAM;
2791 LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
2793 len = getnamefromuuid( ibuf, &name, &type);
2794 if (len != 0) /* its a error code, not len */
2795 return AFPERR_NOITEM;
2796 if (type == UUID_USER) {
2797 if (( pw = getpwnam( name )) == NULL )
2798 return( AFPERR_NOITEM );
2799 LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
2800 id = htonl(UUID_USER);
2801 memcpy( rbuf, &id, sizeof( id ));
2802 id = htonl( pw->pw_uid);
2803 rbuf += sizeof( id );
2804 memcpy( rbuf, &id, sizeof( id ));
2805 rbuf += sizeof( id );
2806 *rbuflen = 2 * sizeof( id );
2807 } else { /* type == UUID_GROUP */
2808 if (( gr = getgrnam( name )) == NULL )
2809 return( AFPERR_NOITEM );
2810 LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
2811 id = htonl(UUID_GROUP);
2812 memcpy( rbuf, &id, sizeof( id ));
2813 rbuf += sizeof( id );
2814 id = htonl( gr->gr_gid);
2815 memcpy( rbuf, &id, sizeof( id ));
2816 rbuf += sizeof( id );
2817 *rbuflen = 2 * sizeof( id );
2822 return( AFPERR_PARAM );
2826 len = strlen( name );
2829 u_int16_t tp = htons(len);
2830 memcpy(rbuf, &tp, sizeof(tp));
2839 memcpy( rbuf, name, len );
2847 int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2856 sfunc = (unsigned char) *ibuf++;
2858 LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
2861 case 2 : /* unicode */
2862 if (afp_version < 30) {
2863 return( AFPERR_PARAM );
2865 memcpy(&ulen, ibuf, sizeof(ulen));
2868 LOG(log_debug, logtype_afpd, "afp_mapname: alive");
2872 len = (unsigned char) *ibuf++;
2874 #ifdef HAVE_NFSv4_ACLS
2875 case 5 : /* username -> UUID */
2876 case 6 : /* groupname -> UUID */
2877 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2878 return AFPERR_PARAM;
2879 memcpy(&ulen, ibuf, sizeof(ulen));
2885 return( AFPERR_PARAM );
2891 return AFPERR_PARAM;
2894 case 1 : /* unicode */
2896 if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) {
2897 return( AFPERR_NOITEM );
2901 memcpy( rbuf, &id, sizeof( id ));
2902 *rbuflen = sizeof( id );
2905 case 2 : /* unicode */
2907 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
2908 if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
2909 return( AFPERR_NOITEM );
2912 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
2914 memcpy( rbuf, &id, sizeof( id ));
2915 *rbuflen = sizeof( id );
2917 #ifdef HAVE_NFSv4_ACLS
2918 case 5 : /* username -> UUID */
2919 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2920 if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
2921 return AFPERR_NOITEM;
2922 *rbuflen = UUID_BINSIZE;
2924 case 6 : /* groupname -> UUID */
2925 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2926 if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
2927 return AFPERR_NOITEM;
2928 *rbuflen = UUID_BINSIZE;
2936 /* ------------------------------------
2937 variable DID support
2939 int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2950 /* do nothing as dids are static for the life of the process. */
2954 memcpy(&vid, ibuf, sizeof( vid ));
2955 ibuf += sizeof( vid );
2956 if (( vol = getvolbyvid( vid )) == NULL ) {
2957 return( AFPERR_PARAM );
2960 memcpy( &did, ibuf, sizeof( did ));
2961 ibuf += sizeof( did );
2962 if (( dir = dirlookup( vol, did )) == NULL ) {
2963 return( AFPERR_PARAM );
2966 /* dir_remove -- deletedid */
2972 /* did creation gets done automatically
2973 * there's a pb again with case but move it to cname
2975 int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2978 struct dir *parentdir;
2986 memcpy(&vid, ibuf, sizeof(vid));
2987 ibuf += sizeof( vid );
2989 if (NULL == ( vol = getvolbyvid( vid )) ) {
2990 return( AFPERR_PARAM );
2993 memcpy(&did, ibuf, sizeof(did));
2994 ibuf += sizeof(did);
2996 if (NULL == ( parentdir = dirlookup( vol, did )) ) {
3000 if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
3001 return get_afp_errno(AFPERR_PARAM);
3004 if ( *path->m_name != '\0' ) {
3005 return path_error(path, AFPERR_NOOBJ);
3008 if ( !path->st_valid && of_stat(path ) < 0 ) {
3009 return( AFPERR_NOOBJ );
3011 if ( path->st_errno ) {
3012 return( AFPERR_NOOBJ );
3015 memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did));
3016 *rbuflen = sizeof(curdir->d_did);