2 * $Id: directory.c,v 1.140 2010-03-12 15:16:49 franklahm Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
7 * 19 jan 2000 implemented red-black trees for directory lookups
13 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
25 #define memcpy(d,s,n) bcopy ((s), (d), (n))
26 #define memmove(d,s,n) bcopy ((s), (d), (n))
27 #endif /* ! HAVE_MEMCPY */
28 #endif /* STDC_HEADERS */
37 #include <sys/param.h>
41 #include <atalk/adouble.h>
42 #include <atalk/vfs.h>
43 #include <atalk/afp.h>
44 #include <atalk/util.h>
45 #include <atalk/cnid.h>
46 #include <atalk/logger.h>
47 #include <atalk/uuid.h>
48 #include <atalk/unix.h>
50 #include "directory.h"
62 #ifdef HAVE_NFSv4_ACLS
63 extern void addir_inherit_acl(const struct vol *vol);
70 * There are currently two cache structures where afpd caches directory information
71 * a) a DID/dirname cache in a hashtable
72 * b) a (red-black) tree with CNIDs as key
74 * a) is for searching by DID/dirname
75 * b) is for searching by CNID
77 * Through additional parent, child, previous and next pointers, b) is also used to
78 * represent the on-disk layout of the filesystem. parent and child point to parent
79 * and child directory respectively, linking 2 or more subdirectories in one
80 * directory with previous and next pointers.
82 * Usage examples, highlighting the main functions:
84 * a) is eg used in enumerate():
86 * dir = dirsearch_byname() // search in cache
87 * if (dir == NULL) // not found
88 * dir = adddir() // add to cache
91 * b) is eg used in afp_getfildirparams()
92 * dirlookup() // wrapper for cache and db search
93 * => dir = dirsearch() // search in cache
97 * cnid_resolve() // resolve with CNID database
98 * cname() // add to cache
104 #define SENTINEL (&sentinel)
105 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
106 DIRTREE_COLOR_BLACK, /* color */
107 NULL, NULL, /* parent, child */
108 NULL, NULL, /* previous, next */
109 NULL, 0, 0, /* oforks, did, flags */
110 0, 0, /* ctime, offcnt */
111 NULL, NULL, NULL}; /* mname, uname, ucs2-name */
112 static struct dir rootpar = { SENTINEL, SENTINEL, NULL,
120 /* (from IM: Toolbox Essentials)
121 * dirFinderInfo (DInfo) fields:
123 * frRect 8 folder's window rectangle
125 * frLocation 4 folder's location in window
126 * frView 2 folder's view (default == closedView (256))
128 * extended dirFinderInfo (DXInfo) fields:
129 * frScroll 4 scroll position
130 * frOpenChain: 4 directory ID chain of open folders
131 * frScript: 1 script flag and code
132 * frXFlags: 1 reserved
133 * frComment: 2 comment ID
134 * frPutAway: 4 home directory ID
138 vol_tree_root(const struct vol *vol, u_int32_t did)
142 if (vol->v_curdir && vol->v_curdir->d_did == did) {
152 * redid did assignment for directories. now we use red-black trees.
156 dirsearch(const struct vol *vol, u_int32_t did)
161 /* check for 0 did */
163 afp_errno = AFPERR_PARAM;
166 if ( did == DIRDID_ROOT_PARENT ) {
168 rootpar.d_did = DIRDID_ROOT_PARENT;
169 rootpar.d_child = vol->v_dir;
173 dir = vol_tree_root(vol, did);
175 afp_errno = AFPERR_NOOBJ;
176 while ( dir != SENTINEL ) {
177 if (dir->d_did == did)
178 return dir->d_m_name ? dir : NULL;
179 dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
184 /* ------------------- */
185 int get_afp_errno(const int param)
187 if (afp_errno != AFPERR_DID1)
192 /* ------------------- */
194 dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
196 struct dir *dir = NULL;
198 if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
204 hn = hash_lookup(vol->v_hash, &key);
212 /* -----------------------------------------
213 * if did is not in the cache resolve it with cnid
216 * OSX call it with bogus id, ie file ID not folder ID,
217 * and we are really bad in this case.
220 dirlookup( struct vol *vol, u_int32_t did)
225 static char path[MAXPATHLEN + 1];
228 static char buffer[12 + MAXPATHLEN + 1];
229 int buflen = 12 + MAXPATHLEN + 1;
234 ret = dirsearch(vol, did);
235 if (ret != NULL || afp_errno == AFPERR_PARAM)
238 utf8 = utf8_encoding();
239 maxpath = (utf8)?MAXPATHLEN -7:255;
241 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
242 afp_errno = AFPERR_NOOBJ;
245 ptr = path + MAXPATHLEN;
246 if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
247 afp_errno = AFPERR_NOOBJ;
251 pathlen = len; /* no 0 in the last part */
253 strcpy(ptr - len, mpath);
256 ret = dirsearch(vol,id);
261 if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
263 NULL == (mpath = utompath(vol, upath, cnid, utf8))
265 afp_errno = AFPERR_NOOBJ;
269 len = strlen(mpath) + 1;
271 if (pathlen > maxpath) {
272 afp_errno = AFPERR_PARAM;
275 strcpy(ptr - len, mpath);
279 /* fill the cache, another place where we know about the path type */
285 temp16 = htons(pathlen);
286 memcpy(ptr, &temp16, sizeof(temp16));
288 temp = htonl(kTextEncodingUTF8);
290 memcpy(ptr, &temp, sizeof(temp));
296 *ptr = (unsigned char)pathlen;
300 /* cname is not efficient */
301 if (cname( vol, ret, &ptr ) == NULL )
304 return dirsearch(vol, did);
307 /* child addition/removal */
308 static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
313 b->d_next = a->d_child;
314 b->d_prev = b->d_next->d_prev;
315 b->d_next->d_prev = b;
316 b->d_prev->d_next = b;
318 if (!hash_alloc_insert(vol->v_hash, b, b)) {
319 LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
323 static void dirchildremove(struct dir *a,struct dir *b)
326 a->d_child = (b == b->d_next) ? NULL : b->d_next;
327 b->d_next->d_prev = b->d_prev;
328 b->d_prev->d_next = b->d_next;
329 b->d_next = b->d_prev = b;
332 /* --------------------------- */
333 /* rotate the tree to the left */
334 static void dir_leftrotate(struct vol *vol, struct dir *dir)
336 struct dir *right = dir->d_right;
338 /* whee. move the right's left tree into dir's right tree */
339 dir->d_right = right->d_left;
340 if (right->d_left != SENTINEL)
341 right->d_left->d_back = dir;
343 if (right != SENTINEL) {
344 right->d_back = dir->d_back;
348 if (!dir->d_back) /* no parent. move the right tree to the top. */
350 else if (dir == dir->d_back->d_left) /* we were on the left */
351 dir->d_back->d_left = right;
353 dir->d_back->d_right = right; /* we were on the right */
355 /* re-insert dir on the left tree */
362 /* rotate the tree to the right */
363 static void dir_rightrotate(struct vol *vol, struct dir *dir)
365 struct dir *left = dir->d_left;
367 /* whee. move the left's right tree into dir's left tree */
368 dir->d_left = left->d_right;
369 if (left->d_right != SENTINEL)
370 left->d_right->d_back = dir;
372 if (left != SENTINEL) {
373 left->d_back = dir->d_back;
377 if (!dir->d_back) /* no parent. move the left tree to the top. */
379 else if (dir == dir->d_back->d_right) /* we were on the right */
380 dir->d_back->d_right = left;
382 dir->d_back->d_left = left; /* we were on the left */
384 /* re-insert dir on the right tree */
390 /* recolor after a removal */
391 static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
395 while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
396 /* are we on the left tree? */
397 if (dir == dir->d_back->d_left) {
398 leaf = dir->d_back->d_right; /* get right side */
399 if (leaf->d_color == DIRTREE_COLOR_RED) {
400 /* we're red. we need to change to black. */
401 leaf->d_color = DIRTREE_COLOR_BLACK;
402 dir->d_back->d_color = DIRTREE_COLOR_RED;
403 dir_leftrotate(vol, dir->d_back);
404 leaf = dir->d_back->d_right;
407 /* right leaf has black end nodes */
408 if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
409 (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
410 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
411 dir = dir->d_back; /* ascend */
413 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
414 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
415 leaf->d_color = DIRTREE_COLOR_RED;
416 dir_rightrotate(vol, leaf);
417 leaf = dir->d_back->d_right;
419 leaf->d_color = dir->d_back->d_color;
420 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
421 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
422 dir_leftrotate(vol, dir->d_back);
425 } else { /* right tree */
426 leaf = dir->d_back->d_left; /* left tree */
427 if (leaf->d_color == DIRTREE_COLOR_RED) {
428 leaf->d_color = DIRTREE_COLOR_BLACK;
429 dir->d_back->d_color = DIRTREE_COLOR_RED;
430 dir_rightrotate(vol, dir->d_back);
431 leaf = dir->d_back->d_left;
434 /* left leaf has black end nodes */
435 if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
436 (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
437 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
438 dir = dir->d_back; /* ascend */
440 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
441 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
442 leaf->d_color = DIRTREE_COLOR_RED;
443 dir_leftrotate(vol, leaf);
444 leaf = dir->d_back->d_left;
446 leaf->d_color = dir->d_back->d_color;
447 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
448 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
449 dir_rightrotate(vol, dir->d_back);
454 dir->d_color = DIRTREE_COLOR_BLACK;
460 /* --------------------- */
461 static void dir_hash_del(const struct vol *vol, struct dir *dir)
465 hn = hash_lookup(vol->v_hash, dir);
467 LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
470 hash_delete(vol->v_hash, hn);
474 /* remove the node from the tree. this is just like insertion, but
475 * different. actually, it has to worry about a bunch of things that
476 * insertion doesn't care about. */
478 static void dir_remove( struct vol *vol, struct dir *dir)
481 struct ofork *of, *last;
482 struct dir *node, *leaf;
483 #endif /* REMOVE_NODES */
485 if (!dir || (dir == SENTINEL))
488 /* i'm not sure if it really helps to delete stuff. */
489 dir_hash_del(vol, dir);
490 vol->v_curdir = NULL;
493 dir->d_m_name = NULL;
494 dir->d_u_name = NULL;
495 dir->d_m_name_ucs2 = NULL;
496 #else /* ! REMOVE_NODES */
498 /* go searching for a node with at most one child */
499 if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
503 while (node->d_left != SENTINEL)
508 leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
511 leaf->d_back = node->d_back;
514 } else if (node == node->d_back->d_left) { /* left tree */
515 node->d_back->d_left = leaf;
517 node->d_back->d_right = leaf;
520 /* we want to free node, but we also want to free the data in dir.
521 * currently, that's d_name and the directory traversal bits.
522 * we just copy the necessary bits and then fix up all the
523 * various pointers to the directory. needless to say, there are
524 * a bunch of places that store the directory struct. */
526 struct dir save, *tmp;
528 memcpy(&save, dir, sizeof(save));
529 memcpy(dir, node, sizeof(struct dir));
531 /* restore the red-black bits */
532 dir->d_left = save.d_left;
533 dir->d_right = save.d_right;
534 dir->d_back = save.d_back;
535 dir->d_color = save.d_color;
537 if (node == vol->v_dir) {/* we may need to fix up this pointer */
539 rootpar.d_child = vol->v_dir;
541 /* if we aren't the root directory, we have parents and
542 * siblings to worry about */
543 if (dir->d_parent->d_child == node)
544 dir->d_parent->d_child = dir;
545 dir->d_next->d_prev = dir;
546 dir->d_prev->d_next = dir;
549 /* fix up children. */
553 tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
556 if (node == curdir) /* another pointer to fixup */
559 /* we also need to fix up oforks. bleah */
560 if ((of = dir->d_ofork)) {
561 last = of->of_d_prev;
564 of = (last == of) ? NULL : of->of_d_next;
568 /* set the node's d_name */
569 node->d_m_name = save.d_m_name;
570 node->d_u_name = save.d_u_name;
571 node->d_m_name_ucs2 = save.d_m_name_ucs2;
574 if (node->d_color == DIRTREE_COLOR_BLACK)
575 dir_rmrecolor(vol, leaf);
577 if (node->d_m_name_ucs2)
578 free(node->d_u_name_ucs2);
579 if (node->d_u_name != node->d_m_name) {
580 free(node->d_u_name);
582 free(node->d_m_name);
584 #endif /* ! REMOVE_NODES */
587 /* ---------------------------------------
588 * remove the node and its childs from the tree
590 * FIXME what about opened forks with refs to it?
591 * it's an afp specs violation because you can't delete
592 * an opened forks. Now afpd doesn't care about forks opened by other
593 * process. It's fixable within afpd if fnctl_lock, doable with smb and
594 * next to impossible for nfs and local filesystem access.
596 static void dir_invalidate( struct vol *vol, struct dir *dir)
599 /* v_root can't be deleted */
600 if (movecwd(vol, vol->v_root) < 0) {
601 LOG(log_error, logtype_afpd, "cname can't chdir to : %s", vol->v_root);
605 dirchildremove(dir->d_parent, dir);
606 dir_remove( vol, dir );
609 /* ------------------------------------ */
610 static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
614 pdir = vol_tree_root(vol, dir->d_did);
615 while (pdir->d_did != dir->d_did ) {
616 if ( pdir->d_did > dir->d_did ) {
617 if ( pdir->d_left == SENTINEL ) {
624 if ( pdir->d_right == SENTINEL ) {
629 pdir = pdir->d_right;
635 #define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/"
638 caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
643 static u_int32_t did = 0;
644 static char cname[MAXPATHLEN];
645 static char lname[MAXPATHLEN];
646 ucs2_t u2_path[MAXPATHLEN];
647 ucs2_t u2_dename[MAXPATHLEN];
648 char *tmp, *savepath;
650 if (!(vol->v_flags & AFPVOL_CASEINSEN))
653 if (veto_file(ENUMVETO, path->u_name))
656 savepath = path->u_name;
658 /* very simple cache */
659 if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
660 path->u_name = cname;
662 if (of_stat( path ) == 0 ) {
665 /* something changed, we cannot stat ... */
669 if (NULL == ( dp = opendir( "." )) ) {
670 LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name);
675 /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
676 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) )
677 LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
679 /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
681 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
682 if (NULL == check_dirent(vol, de->d_name))
685 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) )
688 if (strcasecmp_w( u2_path, u2_dename) == 0) {
690 strlcpy(cname, de->d_name, sizeof(cname));
691 path->u_name = cname;
693 if (of_stat( path ) == 0 ) {
694 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
695 strlcpy(lname, tmp, sizeof(lname));
708 /* invalidate cache */
711 path->u_name = savepath;
713 /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */
719 * attempt to extend the current dir. tree to include path
720 * as a side-effect, movecwd to that point and return the new dir
723 extenddir(struct vol *vol, struct dir *dir, struct path *path)
727 if ( path->u_name == NULL) {
728 afp_errno = AFPERR_PARAM;
732 if (check_name(vol, path->u_name)) {
733 /* the name is illegal */
734 LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name);
736 afp_errno = AFPERR_PARAM;
740 if (of_stat( path ) != 0 ) {
741 if (!(vol->v_flags & AFPVOL_CASEINSEN))
743 else if(caseenumerate(vol, path, dir) != 0)
747 if (!S_ISDIR(path->st.st_mode)) {
751 /* mac name is always with the right encoding (from cname()) */
752 if (( dir = adddir( vol, dir, path)) == NULL ) {
757 if ( movecwd( vol, dir ) < 0 ) {
764 /* -------------------------
765 appledouble mkdir afp error code.
767 static int netatalk_mkdir(const struct vol *vol, const char *name)
772 if (vol->v_flags & AFPVOL_UNIX_PRIV) {
773 if (lstat(".", &st) < 0)
775 int mode = (DIRBITS & (~S_ISGID & st.st_mode)) | (0777 & ~vol->v_umask);
776 LOG(log_maxdebug, logtype_afpd, "netatalk_mkdir(\"%s\") {parent mode: %04o, vol umask: %04o}",
777 name, st.st_mode, vol->v_umask);
779 ret = mkdir(name, mode);
781 ret = ad_mkdir(name, DIRBITS | 0777);
787 return( AFPERR_NOOBJ );
789 return( AFPERR_VLOCK );
792 return( AFPERR_ACCESS );
794 return( AFPERR_EXIST );
797 return( AFPERR_DFULL );
799 return( AFPERR_PARAM );
805 /* ------------------- */
806 static int deletedir(int dirfd, char *dir)
808 char path[MAXPATHLEN + 1];
816 if ((len = strlen(dir)) +2 > sizeof(path))
820 if ((dp = opendirat(dirfd, dir)) == NULL)
826 remain = sizeof(path) -len -1;
827 while ((de = readdir(dp)) && err == AFP_OK) {
828 /* skip this and previous directory */
829 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
832 if (strlen(de->d_name) > remain) {
836 strcpy(path + len, de->d_name);
837 if (lstatat(dirfd, path, &st)) {
840 if (S_ISDIR(st.st_mode)) {
841 err = deletedir(dirfd, path);
843 err = netatalk_unlinkat(dirfd, path);
848 /* okay. the directory is empty. delete it. note: we already got rid
851 err = netatalk_rmdir(dirfd, dir);
856 /* do a recursive copy. */
857 static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
859 char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
868 /* doesn't exist or the path is too long. */
869 if (((slen = strlen(src)) > sizeof(spath) - 2) ||
870 ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
871 ((dp = opendirat(dirfd, src)) == NULL))
874 /* try to create the destination directory */
875 if (AFP_OK != (err = netatalk_mkdir(vol, dst)) ) {
880 /* set things up to copy */
884 srem = sizeof(spath) - slen -1;
889 drem = sizeof(dpath) - dlen -1;
892 while ((de = readdir(dp))) {
893 /* skip this and previous directory */
894 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
897 if (strlen(de->d_name) > srem) {
901 strcpy(spath + slen, de->d_name);
903 if (lstatat(dirfd, spath, &st) == 0) {
904 if (strlen(de->d_name) > drem) {
908 strcpy(dpath + dlen, de->d_name);
910 if (S_ISDIR(st.st_mode)) {
911 if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath)))
913 } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) {
917 /* keep the same time stamp. */
918 ut.actime = ut.modtime = st.st_mtime;
924 /* keep the same time stamp. */
925 if (lstatat(dirfd, src, &st) == 0) {
926 ut.actime = ut.modtime = st.st_mtime;
936 /* --- public functions follow --- */
938 /* NOTE: we start off with at least one node (the root directory). */
939 static struct dir *dirinsert(struct vol *vol, struct dir *dir)
943 if ((node = dir_insert(vol, dir)))
946 /* recolor the tree. the current node is red. */
947 dir->d_color = DIRTREE_COLOR_RED;
949 /* parent of this node has to be black. if the parent node
950 * is red, then we have a grandparent. */
951 while ((dir != vol->v_root) &&
952 (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
953 /* are we on the left tree? */
954 if (dir->d_back == dir->d_back->d_back->d_left) {
955 node = dir->d_back->d_back->d_right; /* get the right node */
956 if (node->d_color == DIRTREE_COLOR_RED) {
957 /* we're red. we need to change to black. */
958 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
959 node->d_color = DIRTREE_COLOR_BLACK;
960 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
961 dir = dir->d_back->d_back; /* finished. go up. */
963 if (dir == dir->d_back->d_right) {
965 dir_leftrotate(vol, dir);
967 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
968 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
969 dir_rightrotate(vol, dir->d_back->d_back);
972 node = dir->d_back->d_back->d_left;
973 if (node->d_color == DIRTREE_COLOR_RED) {
974 /* we're red. we need to change to black. */
975 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
976 node->d_color = DIRTREE_COLOR_BLACK;
977 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
978 dir = dir->d_back->d_back; /* finished. ascend */
980 if (dir == dir->d_back->d_left) {
982 dir_rightrotate(vol, dir);
984 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
985 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
986 dir_leftrotate(vol, dir->d_back->d_back);
991 vol->v_root->d_color = DIRTREE_COLOR_BLACK;
995 /* ---------------------------- */
997 adddir(struct vol *vol, struct dir *dir, struct path *path)
999 struct dir *cdir, *edir;
1006 struct adouble *adp = NULL;
1009 upath = path->u_name;
1011 upathlen = strlen(upath);
1013 /* get_id needs adp for reading CNID from adouble file */
1014 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1015 if ((ad_open_metadata(upath, ADFLAGS_DIR, 0, &ad)) == 0)
1018 id = get_id(vol, adp, st, dir->d_did, upath, upathlen);
1021 ad_close_metadata(adp);
1026 if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
1029 name = path->m_name;
1030 if ((cdir = dirnew(name, upath)) == NULL) {
1031 LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
1034 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)) {
1035 LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
1036 cdir->d_m_name_ucs2 = NULL;
1041 if ((edir = dirinsert( vol, cdir ))) {
1042 /* it's not possible with LASTDID
1044 - someone else have moved the directory.
1045 - it's a symlink inside the share.
1046 - it's an ID reused, the old directory was deleted but not
1047 the cnid record and the server've reused the inode for
1049 for HASH (we should get ride of HASH)
1050 - someone else have moved the directory.
1051 - it's an ID reused as above
1052 - it's a hash duplicate and we are in big trouble
1054 deleted = (edir->d_m_name == NULL);
1056 dir_hash_del(vol, edir);
1058 edir->d_m_name = cdir->d_m_name;
1059 edir->d_u_name = cdir->d_u_name;
1060 edir->d_m_name_ucs2 = cdir->d_m_name_ucs2;
1063 LOG(log_error, logtype_afpd, "adddir: insert %s", edir->d_m_name);
1064 if (!cdir->d_parent || (cdir->d_parent == dir && !deleted)) {
1065 hash_alloc_insert(vol->v_hash, cdir, cdir);
1068 /* the old was not in the same folder */
1070 dirchildremove(cdir->d_parent, cdir);
1073 /* parent/child directories */
1074 cdir->d_parent = dir;
1075 dirchildadd(vol, dir, cdir);
1079 /* --- public functions follow --- */
1080 /* free everything down. we don't bother to recolor as this is only
1081 * called to free the entire tree */
1082 void dirfreename(struct dir *dir)
1084 if (dir->d_u_name != dir->d_m_name) {
1085 free(dir->d_u_name);
1087 if (dir->d_m_name_ucs2)
1088 free(dir->d_m_name_ucs2);
1089 free(dir->d_m_name);
1092 void dirfree(struct dir *dir)
1094 if (!dir || (dir == SENTINEL))
1097 if ( dir->d_left != SENTINEL ) {
1098 dirfree( dir->d_left );
1100 if ( dir->d_right != SENTINEL ) {
1101 dirfree( dir->d_right );
1104 if (dir != SENTINEL) {
1110 /* --------------------------------------------
1111 * most of the time mac name and unix name are the same
1113 struct dir *dirnew(const char *m_name, const char *u_name)
1117 dir = (struct dir *) calloc(1, sizeof( struct dir ));
1121 if ((dir->d_m_name = strdup(m_name)) == NULL) {
1126 if (m_name == u_name || !strcmp(m_name, u_name)) {
1127 dir->d_u_name = dir->d_m_name;
1129 else if ((dir->d_u_name = strdup(u_name)) == NULL) {
1130 free(dir->d_m_name);
1135 dir->d_m_name_ucs2 = NULL;
1136 dir->d_left = dir->d_right = SENTINEL;
1137 dir->d_next = dir->d_prev = dir;
1142 /* ------------------ */
1143 static hash_val_t hash_fun_dir(const void *key)
1145 const struct dir *k = key;
1147 static unsigned long randbox[] = {
1148 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
1149 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
1150 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
1151 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
1154 const unsigned char *str = (unsigned char *)(k->d_u_name);
1155 hash_val_t acc = k->d_parent->d_did;
1158 acc ^= randbox[(*str + acc) & 0xf];
1159 acc = (acc << 1) | (acc >> 31);
1161 acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
1162 acc = (acc << 2) | (acc >> 30);
1170 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
1171 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
1172 #define get16bits(d) (*((const uint16_t *) (d)))
1175 #if !defined (get16bits)
1176 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
1177 +(uint32_t)(((const uint8_t *)(d))[0]) )
1180 static hash_val_t hash_fun2_dir(const void *key)
1182 const struct dir *k = key;
1183 const char *data = k->d_u_name;
1184 int len = strlen(k->d_u_name);
1185 hash_val_t hash = k->d_parent->d_did, tmp;
1191 for (;len > 0; len--) {
1192 hash += get16bits (data);
1193 tmp = (get16bits (data+2) << 11) ^ hash;
1194 hash = (hash << 16) ^ tmp;
1195 data += 2*sizeof (uint16_t);
1199 /* Handle end cases */
1201 case 3: hash += get16bits (data);
1203 hash ^= data[sizeof (uint16_t)] << 18;
1206 case 2: hash += get16bits (data);
1210 case 1: hash += *data;
1215 /* Force "avalanching" of final 127 bits */
1226 /* ---------------- */
1227 static int hash_comp_dir(const void *key1, const void *key2)
1229 const struct dir *k1 = key1;
1230 const struct dir *k2 = key2;
1232 return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
1235 /* ---------------- */
1239 return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
1242 /* ------------------ */
1243 static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
1246 movecwd failed some of dir path are not there anymore.
1247 FIXME Is it true with other errors?
1248 so we remove dir from the cache
1250 if (dir->d_did == DIRDID_ROOT_PARENT)
1252 if (afp_errno == AFPERR_ACCESS) {
1253 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1256 /* FIXME should we set these?, don't need to call stat() after:
1258 ret->st_errno = EACCES;
1260 ret->m_name = dir->d_m_name;
1261 ret->u_name = dir->d_u_name;
1264 } else if (afp_errno == AFPERR_NOOBJ) {
1265 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1268 strcpy(ret->m_name, dir->d_m_name);
1269 if (dir->d_m_name == dir->d_u_name) {
1270 ret->u_name = ret->m_name;
1273 size_t tp = strlen(ret->m_name)+1;
1275 ret->u_name = ret->m_name +tp;
1276 strcpy(ret->u_name, dir->d_u_name);
1278 /* FIXME should we set :
1280 ret->st_errno = ENOENT;
1282 dir_invalidate(vol, dir);
1285 dir_invalidate(vol, dir);
1289 /* -------------------------------------------------- */
1295 stat the file or errno
1298 curdir: filename parent directory
1304 stat the dir or errno
1308 curdir: dir parent directory
1316 curdir: dir parent directory
1323 cname(struct vol *vol, struct dir *dir, char **cpath)
1325 struct dir *cdir, *scdir=NULL;
1326 static char path[ MAXPATHLEN + 1];
1327 static struct path ret;
1339 afp_errno = AFPERR_NOOBJ;
1340 memset(&ret, 0, sizeof(ret));
1341 switch (ret.m_type = *data) { /* path type */
1344 len = (unsigned char) *data++;
1347 if (afp_version >= 30) {
1353 if (afp_version >= 30) {
1355 memcpy(&hint, data, sizeof(hint));
1357 data += sizeof(hint);
1359 memcpy(&len16, data, sizeof(len16));
1366 /* else it's an error */
1368 afp_errno = AFPERR_PARAM;
1371 *cpath += len + size;
1376 if (movecwd( vol, dir ) < 0 ) {
1377 return invalidate(vol, dir, &ret );
1379 if (*path == '\0') {
1386 if (*data == sep ) {
1390 while (*data == sep && len > 0 ) {
1391 if ( dir->d_parent == NULL ) {
1394 dir = dir->d_parent;
1399 /* would this be faster with strlen + strncpy? */
1401 while ( *data != sep && len > 0 ) {
1403 if (p > &path[ MAXPATHLEN]) {
1404 afp_errno = AFPERR_PARAM;
1410 /* short cut bits by chopping off a trailing \0. this also
1411 makes the traversal happy w/ filenames at the end of the
1418 if ( p == path ) { /* end of the name parameter */
1422 if (afp_version >= 30) {
1427 static char temp[ MAXPATHLEN + 1];
1429 if (dir->d_did == DIRDID_ROOT_PARENT) {
1431 With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
1432 So we compare it with the longname from the current volume and if they match
1433 we overwrite the requested path with the utf8 volume name so that the following
1436 ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
1437 if (strcasecmp( path, temp) == 0)
1438 ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
1441 if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
1442 afp_errno = AFPERR_PARAM;
1448 /* check for OS X mangled filename :( */
1450 t = demangle_osx(vol, path, dir->d_did, &fileid);
1453 /* duplicate work but we can't reuse all convert_char we did in demangle_osx
1454 * flags weren't the same
1456 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
1457 /* at last got our view of mac name */
1462 if (ret.u_name == NULL) {
1463 if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
1464 afp_errno = AFPERR_PARAM;
1470 cdir = dir->d_child;
1472 if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
1473 (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
1474 CH_UCS2, path, -1, (char **)&tmpname) )
1477 if (!cdir->d_m_name_ucs2) {
1478 LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
1479 /* this shouldn't happen !!!! */
1483 if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1486 if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1489 cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
1495 if (dir->d_did == DIRDID_ROOT_PARENT) {
1497 root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
1498 must check against the volume name.
1500 if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
1506 cdir = dirsearch_byname(vol, dir, ret.u_name);
1510 if (cdir == NULL && scdir != NULL) {
1512 /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
1515 if ( cdir == NULL ) {
1517 /* if dir == curdir it always succeed,
1518 even if curdir is deleted.
1519 it's not a pb because it will fail in extenddir
1521 if ( movecwd( vol, dir ) < 0 ) {
1522 /* dir is not valid anymore
1523 we delete dir from the cache and abort.
1525 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1526 afp_errno = AFPERR_NOOBJ;
1529 if (afp_errno == AFPERR_ACCESS)
1531 dir_invalidate(vol, dir);
1534 cdir = extenddir( vol, dir, &ret );
1538 cdir = extenddir( vol, dir, &ret );
1539 } /* if (!extend) */
1541 if ( cdir == NULL ) {
1543 if ( len > 0 || !ret.u_name ) {
1555 * Move curdir to dir, with a possible chdir()
1557 int movecwd(struct vol *vol, struct dir *dir)
1559 char path[MAXPATHLEN + 1];
1565 if ( dir == curdir ) {
1568 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1569 afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
1573 p = path + sizeof(path) - 1;
1575 for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
1578 /* parent directory is deleted */
1579 afp_errno = AFPERR_NOOBJ;
1583 if (p -n -1 < path) {
1584 afp_errno = AFPERR_PARAM;
1591 if ( d != curdir ) {
1592 n = strlen( vol->v_path );
1593 if (p -n -1 < path) {
1594 afp_errno = AFPERR_PARAM;
1599 memcpy( p, vol->v_path, n );
1601 if ( (ret = lchdir(p )) != 0 ) {
1602 LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
1605 /* p is a symlink or getcwd failed */
1606 afp_errno = AFPERR_BADTYPE;
1607 vol->v_curdir = curdir = vol->v_dir;
1608 if (chdir(vol->v_path ) < 0) {
1609 LOG(log_debug, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
1610 /* XXX what do we do here? */
1617 afp_errno = AFPERR_ACCESS;
1620 afp_errno = AFPERR_NOOBJ;
1625 vol->v_curdir = curdir = dir;
1630 * We can't use unix file's perm to support Apple's inherited protection modes.
1631 * If we aren't the file's owner we can't change its perms when moving it and smb
1632 * nfs,... don't even try.
1634 #define AFP_CHECK_ACCESS
1636 int check_access(char *path, int mode)
1638 #ifdef AFP_CHECK_ACCESS
1646 accessmode(p, &ma, curdir, NULL);
1647 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1649 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1655 /* --------------------- */
1656 int file_access(struct path *path, int mode)
1660 accessmode(path->u_name, &ma, curdir, &path->st);
1661 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1663 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1669 /* --------------------- */
1670 void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
1672 dir->offcnt = count;
1673 dir->ctime = st->st_ctime;
1674 dir->d_flags &= ~DIRF_CNID;
1677 /* ---------------------
1678 * is our cached offspring count valid?
1681 static int diroffcnt(struct dir *dir, struct stat *st)
1683 return st->st_ctime == dir->ctime;
1686 /* ---------------------
1687 * is our cached also for reenumerate id?
1690 int dirreenumerate(struct dir *dir, struct stat *st)
1692 return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
1695 /* --------------------- */
1696 static int invisible_dots(const struct vol *vol, const char *name)
1698 return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
1701 /* ------------------------------
1703 (name, dir) with curdir:name == dir, from afp_enumerate
1706 int getdirparams(const struct vol *vol,
1707 u_int16_t bitmap, struct path *s_path,
1709 char *buf, size_t *buflen )
1713 char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
1714 int bit = 0, isad = 0;
1720 struct stat *st = &s_path->st;
1721 char *upath = s_path->u_name;
1723 if ((bitmap & ((1 << DIRPBIT_ATTR) |
1724 (1 << DIRPBIT_CDATE) |
1725 (1 << DIRPBIT_MDATE) |
1726 (1 << DIRPBIT_BDATE) |
1727 (1 << DIRPBIT_FINFO)))) {
1729 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1730 if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
1732 if (ad.ad_md->adf_flags & O_CREAT) {
1733 /* We just created it */
1734 ad_setname(&ad, s_path->m_name);
1739 dir->d_parent->d_did,
1746 if ( dir->d_did == DIRDID_ROOT) {
1747 pdid = DIRDID_ROOT_PARENT;
1748 } else if (dir->d_did == DIRDID_ROOT_PARENT) {
1751 pdid = dir->d_parent->d_did;
1755 while ( bitmap != 0 ) {
1756 while (( bitmap & 1 ) == 0 ) {
1764 ad_getattr(&ad, &ashort);
1765 } else if (invisible_dots(vol, dir->d_u_name)) {
1766 ashort = htons(ATTRBIT_INVISIBLE);
1769 ashort |= htons(ATTRBIT_SHARED);
1770 memcpy( data, &ashort, sizeof( ashort ));
1771 data += sizeof( ashort );
1775 memcpy( data, &pdid, sizeof( pdid ));
1776 data += sizeof( pdid );
1779 case DIRPBIT_CDATE :
1780 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1781 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1782 memcpy( data, &aint, sizeof( aint ));
1783 data += sizeof( aint );
1786 case DIRPBIT_MDATE :
1787 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1788 memcpy( data, &aint, sizeof( aint ));
1789 data += sizeof( aint );
1792 case DIRPBIT_BDATE :
1793 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
1794 aint = AD_DATE_START;
1795 memcpy( data, &aint, sizeof( aint ));
1796 data += sizeof( aint );
1799 case DIRPBIT_FINFO :
1801 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
1802 } else { /* no appledouble */
1803 memset( data, 0, 32 );
1804 /* set default view -- this also gets done in ad_open() */
1805 ashort = htons(FINDERINFO_CLOSEDVIEW);
1806 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
1808 /* dot files are by default visible */
1809 if (invisible_dots(vol, dir->d_u_name)) {
1810 ashort = htons(FINDERINFO_INVISIBLE);
1811 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
1817 case DIRPBIT_LNAME :
1818 if (dir->d_m_name) /* root of parent can have a null name */
1821 memset(data, 0, sizeof(u_int16_t));
1822 data += sizeof( u_int16_t );
1825 case DIRPBIT_SNAME :
1826 memset(data, 0, sizeof(u_int16_t));
1827 data += sizeof( u_int16_t );
1831 memcpy( data, &dir->d_did, sizeof( aint ));
1832 data += sizeof( aint );
1835 case DIRPBIT_OFFCNT :
1837 /* this needs to handle current directory access rights */
1838 if (diroffcnt(dir, st)) {
1839 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1841 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
1842 setdiroffcnt(dir, st, ret);
1843 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1845 ashort = htons( ashort );
1846 memcpy( data, &ashort, sizeof( ashort ));
1847 data += sizeof( ashort );
1851 aint = htonl(st->st_uid);
1852 memcpy( data, &aint, sizeof( aint ));
1853 data += sizeof( aint );
1857 aint = htonl(st->st_gid);
1858 memcpy( data, &aint, sizeof( aint ));
1859 data += sizeof( aint );
1862 case DIRPBIT_ACCESS :
1863 accessmode( upath, &ma, dir , st);
1865 *data++ = ma.ma_user;
1866 *data++ = ma.ma_world;
1867 *data++ = ma.ma_group;
1868 *data++ = ma.ma_owner;
1871 /* Client has requested the ProDOS information block.
1872 Just pass back the same basic block for all
1873 directories. <shirsch@ibm.net> */
1874 case DIRPBIT_PDINFO :
1875 if (afp_version >= 30) { /* UTF8 name */
1876 utf8 = kTextEncodingUTF8;
1877 if (dir->d_m_name) /* root of parent can have a null name */
1880 memset(data, 0, sizeof(u_int16_t));
1881 data += sizeof( u_int16_t );
1883 memcpy(data, &aint, sizeof( aint ));
1884 data += sizeof( aint );
1886 else { /* ProDOS Info Block */
1889 ashort = htons( 0x0200 );
1890 memcpy( data, &ashort, sizeof( ashort ));
1891 data += sizeof( ashort );
1892 memset( data, 0, sizeof( ashort ));
1893 data += sizeof( ashort );
1897 case DIRPBIT_UNIXPR :
1898 aint = htonl(st->st_uid);
1899 memcpy( data, &aint, sizeof( aint ));
1900 data += sizeof( aint );
1901 aint = htonl(st->st_gid);
1902 memcpy( data, &aint, sizeof( aint ));
1903 data += sizeof( aint );
1906 aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
1907 memcpy( data, &aint, sizeof( aint ));
1908 data += sizeof( aint );
1910 accessmode( upath, &ma, dir , st);
1912 *data++ = ma.ma_user;
1913 *data++ = ma.ma_world;
1914 *data++ = ma.ma_group;
1915 *data++ = ma.ma_owner;
1920 ad_close_metadata( &ad );
1922 return( AFPERR_BITMAP );
1928 ashort = htons( data - buf );
1929 memcpy( l_nameoff, &ashort, sizeof( ashort ));
1930 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, 0);
1932 if ( utf_nameoff ) {
1933 ashort = htons( data - buf );
1934 memcpy( utf_nameoff, &ashort, sizeof( ashort ));
1935 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, utf8);
1938 ad_close_metadata( &ad );
1940 *buflen = data - buf;
1944 /* ----------------------------- */
1945 int path_error(struct path *path, int error)
1947 /* - a dir with access error
1948 * - no error it's a file
1951 if (path_isadir(path))
1953 if (path->st_valid && path->st_errno)
1955 return AFPERR_BADTYPE ;
1958 /* ----------------------------- */
1959 int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1964 u_int16_t vid, bitmap;
1970 memcpy( &vid, ibuf, sizeof( vid ));
1971 ibuf += sizeof( vid );
1973 if (NULL == ( vol = getvolbyvid( vid )) ) {
1974 return( AFPERR_PARAM );
1977 if (vol->v_flags & AFPVOL_RO)
1978 return AFPERR_VLOCK;
1980 memcpy( &did, ibuf, sizeof( did ));
1981 ibuf += sizeof( int );
1983 if (NULL == ( dir = dirlookup( vol, did )) ) {
1987 memcpy( &bitmap, ibuf, sizeof( bitmap ));
1988 bitmap = ntohs( bitmap );
1989 ibuf += sizeof( bitmap );
1991 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1992 return get_afp_errno(AFPERR_NOOBJ);
1995 if ( *path->m_name != '\0' ) {
1996 rc = path_error(path, AFPERR_NOOBJ);
1997 /* maybe we are trying to set perms back */
1998 if (rc != AFPERR_ACCESS)
2003 * If ibuf is odd, make it even.
2005 if ((u_long)ibuf & 1 ) {
2009 if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
2010 setvoltime(obj, vol );
2016 * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
2018 * assume path == '\0' eg. it's a directory in canonical form
2021 struct path Cur_Path = {
2024 ".", /* unix name */
2026 NULL,/* struct dir */
2027 0, /* stat is not set */
2030 /* ------------------ */
2031 static int set_dir_errors(struct path *path, const char *where, int err)
2036 return AFPERR_ACCESS;
2038 return AFPERR_VLOCK;
2040 LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
2041 return AFPERR_PARAM;
2044 /* ------------------ */
2045 int setdirparams(struct vol *vol,
2046 struct path *path, u_int16_t d_bitmap, char *buf )
2058 u_int16_t ashort, bshort, oshort;
2060 int change_mdate = 0;
2061 int change_parent_mdate = 0;
2063 u_int16_t bitmap = d_bitmap;
2064 u_char finder_buf[32];
2067 u_int16_t upriv_bit = 0;
2070 upath = path->u_name;
2072 while ( bitmap != 0 ) {
2073 while (( bitmap & 1 ) == 0 ) {
2081 memcpy( &ashort, buf, sizeof( ashort ));
2082 buf += sizeof( ashort );
2084 case DIRPBIT_CDATE :
2086 memcpy(&cdate, buf, sizeof(cdate));
2087 buf += sizeof( cdate );
2089 case DIRPBIT_MDATE :
2090 memcpy(&newdate, buf, sizeof(newdate));
2091 buf += sizeof( newdate );
2093 case DIRPBIT_BDATE :
2095 memcpy(&bdate, buf, sizeof(bdate));
2096 buf += sizeof( bdate );
2098 case DIRPBIT_FINFO :
2100 memcpy( finder_buf, buf, 32 );
2103 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2104 change_parent_mdate = 1;
2105 memcpy( &owner, buf, sizeof(owner));
2106 buf += sizeof( owner );
2109 change_parent_mdate = 1;
2110 memcpy( &group, buf, sizeof( group ));
2111 buf += sizeof( group );
2113 case DIRPBIT_ACCESS :
2115 change_parent_mdate = 1;
2116 ma.ma_user = *buf++;
2117 ma.ma_world = *buf++;
2118 ma.ma_group = *buf++;
2119 ma.ma_owner = *buf++;
2120 mpriv = mtoumode( &ma ) | vol->v_dperm;
2121 if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2122 err = set_dir_errors(path, "setdirmode", errno);
2126 /* Ignore what the client thinks we should do to the
2127 ProDOS information block. Skip over the data and
2128 report nothing amiss. <shirsch@ibm.net> */
2129 case DIRPBIT_PDINFO :
2130 if (afp_version < 30) {
2134 err = AFPERR_BITMAP;
2138 case DIRPBIT_UNIXPR :
2139 if (vol_unix_priv(vol)) {
2140 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
2141 buf += sizeof( owner );
2142 memcpy( &group, buf, sizeof( group ));
2143 buf += sizeof( group );
2146 change_parent_mdate = 1;
2147 memcpy( &upriv, buf, sizeof( upriv ));
2148 buf += sizeof( upriv );
2149 upriv = ntohl (upriv) | vol->v_dperm;
2150 if (dir_rx_set(upriv)) {
2151 /* maybe we are trying to set perms back */
2152 if ( setdirunixmode(vol, upath, upriv) < 0 ) {
2154 err = set_dir_errors(path, "setdirunixmode", errno);
2165 err = AFPERR_BITMAP;
2173 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2175 if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
2177 * Check to see what we're trying to set. If it's anything
2178 * but ACCESS, UID, or GID, give an error. If it's any of those
2179 * three, we don't need the ad to be open, so just continue.
2181 * note: we also don't need to worry about mdate. also, be quiet
2182 * if we're using the noadouble option.
2184 if (!vol_noadouble(vol) && (d_bitmap &
2185 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
2186 (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
2187 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
2188 return AFPERR_ACCESS;
2194 * Check to see if a create was necessary. If it was, we'll want
2195 * to set our name, etc.
2197 if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
2198 ad_setname(&ad, curdir->d_m_name);
2204 while ( bitmap != 0 ) {
2205 while (( bitmap & 1 ) == 0 ) {
2213 ad_getattr(&ad, &bshort);
2215 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
2216 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
2220 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
2221 change_parent_mdate = 1;
2222 ad_setattr(&ad, bshort);
2225 case DIRPBIT_CDATE :
2227 ad_setdate(&ad, AD_DATE_CREATE, cdate);
2230 case DIRPBIT_MDATE :
2232 case DIRPBIT_BDATE :
2234 ad_setdate(&ad, AD_DATE_BACKUP, bdate);
2237 case DIRPBIT_FINFO :
2239 /* Fixes #2802236 */
2240 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
2241 *fflags &= htons(~FINDERINFO_ISHARED);
2243 if ( dir->d_did == DIRDID_ROOT ) {
2245 * Alright, we admit it, this is *really* sick!
2246 * The 4 bytes that we don't copy, when we're dealing
2247 * with the root of a volume, are the directory's
2248 * location information. This eliminates that annoying
2249 * behavior one sees when mounting above another mount
2252 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
2253 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
2255 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
2259 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2260 if ( (dir->d_did == DIRDID_ROOT) &&
2261 (setdeskowner( ntohl(owner), -1 ) < 0)) {
2262 err = set_dir_errors(path, "setdeskowner", errno);
2263 if (isad && err == AFPERR_PARAM) {
2264 err = AFP_OK; /* ???*/
2267 goto setdirparam_done;
2270 if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
2271 err = set_dir_errors(path, "setdirowner", errno);
2272 goto setdirparam_done;
2276 if (dir->d_did == DIRDID_ROOT)
2277 setdeskowner( -1, ntohl(group) );
2278 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2279 err = set_dir_errors(path, "setdirowner", errno);
2280 goto setdirparam_done;
2283 case DIRPBIT_ACCESS :
2284 if (dir->d_did == DIRDID_ROOT) {
2286 if (!dir_rx_set(mpriv)) {
2287 /* we can't remove read and search for owner on volume root */
2288 err = AFPERR_ACCESS;
2289 goto setdirparam_done;
2293 if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2294 err = set_dir_errors(path, "setdirmode", errno);
2295 goto setdirparam_done;
2298 case DIRPBIT_PDINFO :
2299 if (afp_version >= 30) {
2300 err = AFPERR_BITMAP;
2301 goto setdirparam_done;
2304 case DIRPBIT_UNIXPR :
2305 if (vol_unix_priv(vol)) {
2306 if (dir->d_did == DIRDID_ROOT) {
2307 if (!dir_rx_set(upriv)) {
2308 /* we can't remove read and search for owner on volume root */
2309 err = AFPERR_ACCESS;
2310 goto setdirparam_done;
2312 setdeskowner( -1, ntohl(group) );
2313 setdeskmode( upriv );
2315 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2316 err = set_dir_errors(path, "setdirowner", errno);
2317 goto setdirparam_done;
2320 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
2321 err = set_dir_errors(path, "setdirunixmode", errno);
2322 goto setdirparam_done;
2326 err = AFPERR_BITMAP;
2327 goto setdirparam_done;
2331 err = AFPERR_BITMAP;
2332 goto setdirparam_done;
2341 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
2342 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2346 ad_setdate(&ad, AD_DATE_MODIFY, newdate);
2347 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
2352 if (path->st_valid && !path->st_errno) {
2353 struct stat *st = &path->st;
2355 if (dir && dir->d_parent) {
2356 ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_parent->d_did, vol->v_stamp);
2360 ad_close_metadata( &ad);
2363 if (change_parent_mdate && dir->d_did != DIRDID_ROOT
2364 && gettimeofday(&tv, NULL) == 0) {
2365 if (!movecwd(vol, dir->d_parent)) {
2366 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2367 /* be careful with bitmap because now dir is null */
2368 bitmap = 1<<DIRPBIT_MDATE;
2369 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
2370 /* should we reset curdir ?*/
2377 int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2391 memcpy( &vid, ibuf, sizeof( vid ));
2392 ibuf += sizeof( vid );
2393 if (NULL == (vol = getvolbyvid( vid )) ) {
2394 return( AFPERR_PARAM );
2397 memcpy( &did, ibuf, sizeof( did ));
2398 ibuf += sizeof( did );
2402 * if it's CNID 2 our only choice to meet the specs is call sync.
2403 * For any other CNID just sync that dir. To my knowledge the
2404 * intended use of FPSyncDir is to sync the volume so all we're
2405 * ever going to see here is probably CNID 2. Anyway, we' prepared.
2408 if ( ntohl(did) == 2 ) {
2411 if (NULL == ( dir = dirlookup( vol, did )) ) {
2412 return afp_errno; /* was AFPERR_NOOBJ */
2415 if (movecwd( vol, dir ) < 0 )
2416 return ( AFPERR_NOOBJ );
2419 * Assuming only OSens that have dirfd also may require fsyncing directories
2420 * in order to flush metadata e.g. Linux.
2424 if (NULL == ( dp = opendir( "." )) ) {
2427 return( AFPERR_NOOBJ );
2429 return( AFPERR_ACCESS );
2431 return( AFPERR_PARAM );
2435 LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
2438 if ( fsync ( dfd ) < 0 )
2439 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2440 dir->d_u_name, strerror(errno) );
2441 closedir(dp); /* closes dfd too */
2444 if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
2447 return( AFPERR_NOOBJ );
2449 return( AFPERR_ACCESS );
2451 return( AFPERR_PARAM );
2455 LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
2456 vol->ad_path(".", ADFLAGS_DIR) );
2458 if ( fsync(dfd) < 0 )
2459 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2460 vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
2467 int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2473 struct path *s_path;
2481 memcpy( &vid, ibuf, sizeof( vid ));
2482 ibuf += sizeof( vid );
2483 if (NULL == ( vol = getvolbyvid( vid )) ) {
2484 return( AFPERR_PARAM );
2487 if (vol->v_flags & AFPVOL_RO)
2488 return AFPERR_VLOCK;
2490 memcpy( &did, ibuf, sizeof( did ));
2491 ibuf += sizeof( did );
2492 if (NULL == ( dir = dirlookup( vol, did )) ) {
2493 return afp_errno; /* was AFPERR_NOOBJ */
2495 /* for concurrent access we need to be sure we are not in the
2496 * folder we want to create...
2500 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
2501 return get_afp_errno(AFPERR_PARAM);
2503 /* cname was able to move curdir to it! */
2504 if (*s_path->m_name == '\0')
2505 return AFPERR_EXIST;
2507 upath = s_path->u_name;
2509 if (AFP_OK != (err = netatalk_mkdir(vol, upath))) {
2513 if (of_stat(s_path) < 0) {
2517 if ((dir = adddir( vol, curdir, s_path)) == NULL) {
2521 if ( movecwd( vol, dir ) < 0 ) {
2522 return( AFPERR_PARAM );
2525 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2526 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
2527 if (vol_noadouble(vol))
2528 goto createdir_done;
2529 return( AFPERR_ACCESS );
2531 ad_setname(&ad, s_path->m_name);
2532 ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
2534 fce_register_new_dir(s_path);
2537 ad_close_metadata( &ad);
2540 #ifdef HAVE_NFSv4_ACLS
2541 /* FIXME: are we really inside the created dir? */
2542 addir_inherit_acl(vol);
2545 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
2546 *rbuflen = sizeof( u_int32_t );
2547 setvoltime(obj, vol );
2552 * dst new unix filename (not a pathname)
2553 * newname new mac name
2555 * dirfd -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd
2557 int renamedir(const struct vol *vol,
2562 struct dir *newparent,
2570 /* existence check moved to afp_moveandrename */
2571 if ( unix_rename(dirfd, src, -1, dst ) < 0 ) {
2574 return( AFPERR_NOOBJ );
2576 return( AFPERR_ACCESS );
2578 return AFPERR_VLOCK;
2580 /* tried to move directory into a subdirectory of itself */
2581 return AFPERR_CANTMOVE;
2583 /* this needs to copy and delete. bleah. that means we have
2584 * to deal with entire directory hierarchies. */
2585 if ((err = copydir(vol, dirfd, src, dst)) < 0) {
2589 if ((err = deletedir(dirfd, src)) < 0)
2593 return( AFPERR_PARAM );
2597 vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
2599 len = strlen( newname );
2600 /* rename() succeeded so we need to update our tree even if we can't open
2604 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2606 if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
2607 ad_setname(&ad, newname);
2609 ad_close_metadata( &ad);
2612 dir_hash_del(vol, dir);
2613 if (dir->d_m_name == dir->d_u_name)
2614 dir->d_u_name = NULL;
2616 if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
2617 LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
2618 /* FIXME : fatal ? */
2621 dir->d_m_name = buf;
2622 strcpy( dir->d_m_name, newname );
2624 if (newname == dst) {
2625 free(dir->d_u_name);
2626 dir->d_u_name = dir->d_m_name;
2629 if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
2630 LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
2633 dir->d_u_name = buf;
2634 strcpy( dir->d_u_name, dst );
2637 if (dir->d_m_name_ucs2)
2638 free(dir->d_m_name_ucs2);
2640 dir->d_m_name_ucs2 = NULL;
2641 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))
2642 dir->d_m_name_ucs2 = NULL;
2644 if (( parent = dir->d_parent ) == NULL ) {
2647 if ( parent == newparent ) {
2648 hash_alloc_insert(vol->v_hash, dir, dir);
2652 /* detach from old parent and add to new one. */
2653 dirchildremove(parent, dir);
2654 dir->d_parent = newparent;
2655 dirchildadd(vol, newparent, dir);
2659 /* delete an empty directory */
2660 int deletecurdir(struct vol *vol)
2670 if ( curdir->d_parent == NULL ) {
2671 return( AFPERR_ACCESS );
2676 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2677 /* we never want to create a resource fork here, we are going to delete it */
2678 if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
2680 ad_getattr(&ad, &ashort);
2681 ad_close_metadata(&ad);
2682 if ((ashort & htons(ATTRBIT_NODELETE))) {
2683 return AFPERR_OLOCK;
2686 err = vol->vfs->vfs_deletecurdir(vol);
2691 /* now get rid of dangling symlinks */
2692 if ((dp = opendir("."))) {
2693 while ((de = readdir(dp))) {
2694 /* skip this and previous directory */
2695 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2698 /* bail if it's not a symlink */
2699 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
2701 return AFPERR_DIRNEMPT;
2704 if ((err = netatalk_unlink(de->d_name))) {
2711 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
2716 err = netatalk_rmdir_all_errors(-1, fdir->d_u_name);
2717 if ( err == AFP_OK || err == AFPERR_NOOBJ) {
2718 dirchildremove(curdir, fdir);
2719 cnid_delete(vol->v_cdb, fdir->d_did);
2720 dir_remove( vol, fdir );
2724 /* inode is used as key for cnid.
2725 * Close the descriptor only after cnid_delete
2733 int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2743 sfunc = (unsigned char) *ibuf++;
2747 if (sfunc >= 3 && sfunc <= 6) {
2748 if (afp_version < 30) {
2749 return( AFPERR_PARAM );
2756 case 3 :/* unicode */
2757 memcpy( &id, ibuf, sizeof( id ));
2760 if (( pw = getpwuid( id )) == NULL ) {
2761 return( AFPERR_NOITEM );
2763 len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
2764 pw->pw_name, -1, &name);
2771 case 4 : /* unicode */
2772 memcpy( &id, ibuf, sizeof( id ));
2775 if (NULL == ( gr = (struct group *)getgrgid( id ))) {
2776 return( AFPERR_NOITEM );
2778 len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
2779 gr->gr_name, -1, &name);
2785 #ifdef HAVE_NFSv4_ACLS
2786 case 5 : /* UUID -> username */
2787 case 6 : /* UUID -> groupname */
2788 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2789 return AFPERR_PARAM;
2790 LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
2792 len = getnamefromuuid( ibuf, &name, &type);
2793 if (len != 0) /* its a error code, not len */
2794 return AFPERR_NOITEM;
2795 if (type == UUID_USER) {
2796 if (( pw = getpwnam( name )) == NULL )
2797 return( AFPERR_NOITEM );
2798 LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
2799 id = htonl(UUID_USER);
2800 memcpy( rbuf, &id, sizeof( id ));
2801 id = htonl( pw->pw_uid);
2802 rbuf += sizeof( id );
2803 memcpy( rbuf, &id, sizeof( id ));
2804 rbuf += sizeof( id );
2805 *rbuflen = 2 * sizeof( id );
2806 } else { /* type == UUID_GROUP */
2807 if (( gr = getgrnam( name )) == NULL )
2808 return( AFPERR_NOITEM );
2809 LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
2810 id = htonl(UUID_GROUP);
2811 memcpy( rbuf, &id, sizeof( id ));
2812 rbuf += sizeof( id );
2813 id = htonl( gr->gr_gid);
2814 memcpy( rbuf, &id, sizeof( id ));
2815 rbuf += sizeof( id );
2816 *rbuflen = 2 * sizeof( id );
2821 return( AFPERR_PARAM );
2825 len = strlen( name );
2828 u_int16_t tp = htons(len);
2829 memcpy(rbuf, &tp, sizeof(tp));
2838 memcpy( rbuf, name, len );
2846 int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2855 sfunc = (unsigned char) *ibuf++;
2857 LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
2860 case 2 : /* unicode */
2861 if (afp_version < 30) {
2862 return( AFPERR_PARAM );
2864 memcpy(&ulen, ibuf, sizeof(ulen));
2867 LOG(log_debug, logtype_afpd, "afp_mapname: alive");
2871 len = (unsigned char) *ibuf++;
2873 #ifdef HAVE_NFSv4_ACLS
2874 case 5 : /* username -> UUID */
2875 case 6 : /* groupname -> UUID */
2876 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2877 return AFPERR_PARAM;
2878 memcpy(&ulen, ibuf, sizeof(ulen));
2884 return( AFPERR_PARAM );
2890 return AFPERR_PARAM;
2893 case 1 : /* unicode */
2895 if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) {
2896 return( AFPERR_NOITEM );
2900 memcpy( rbuf, &id, sizeof( id ));
2901 *rbuflen = sizeof( id );
2904 case 2 : /* unicode */
2906 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
2907 if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
2908 return( AFPERR_NOITEM );
2911 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
2913 memcpy( rbuf, &id, sizeof( id ));
2914 *rbuflen = sizeof( id );
2916 #ifdef HAVE_NFSv4_ACLS
2917 case 5 : /* username -> UUID */
2918 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2919 if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
2920 return AFPERR_NOITEM;
2921 *rbuflen = UUID_BINSIZE;
2923 case 6 : /* groupname -> UUID */
2924 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2925 if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
2926 return AFPERR_NOITEM;
2927 *rbuflen = UUID_BINSIZE;
2935 /* ------------------------------------
2936 variable DID support
2938 int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2949 /* do nothing as dids are static for the life of the process. */
2953 memcpy(&vid, ibuf, sizeof( vid ));
2954 ibuf += sizeof( vid );
2955 if (( vol = getvolbyvid( vid )) == NULL ) {
2956 return( AFPERR_PARAM );
2959 memcpy( &did, ibuf, sizeof( did ));
2960 ibuf += sizeof( did );
2961 if (( dir = dirlookup( vol, did )) == NULL ) {
2962 return( AFPERR_PARAM );
2965 /* dir_remove -- deletedid */
2971 /* did creation gets done automatically
2972 * there's a pb again with case but move it to cname
2974 int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2977 struct dir *parentdir;
2985 memcpy(&vid, ibuf, sizeof(vid));
2986 ibuf += sizeof( vid );
2988 if (NULL == ( vol = getvolbyvid( vid )) ) {
2989 return( AFPERR_PARAM );
2992 memcpy(&did, ibuf, sizeof(did));
2993 ibuf += sizeof(did);
2995 if (NULL == ( parentdir = dirlookup( vol, did )) ) {
2999 if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
3000 return get_afp_errno(AFPERR_PARAM);
3003 if ( *path->m_name != '\0' ) {
3004 return path_error(path, AFPERR_NOOBJ);
3007 if ( !path->st_valid && of_stat(path ) < 0 ) {
3008 return( AFPERR_NOOBJ );
3010 if ( path->st_errno ) {
3011 return( AFPERR_NOOBJ );
3014 memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did));
3015 *rbuflen = sizeof(curdir->d_did);