2 * $Id: directory.c,v 1.140 2010-03-12 15:16:49 franklahm Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
7 * 19 jan 2000 implemented red-black trees for directory lookups
13 #endif /* HAVE_CONFIG_H */
18 #else /* STDC_HEADERS */
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
25 #define memcpy(d,s,n) bcopy ((s), (d), (n))
26 #define memmove(d,s,n) bcopy ((s), (d), (n))
27 #endif /* ! HAVE_MEMCPY */
28 #endif /* STDC_HEADERS */
37 #include <sys/param.h>
41 #include <atalk/adouble.h>
42 #include <atalk/vfs.h>
43 #include <atalk/afp.h>
44 #include <atalk/util.h>
45 #include <atalk/cnid.h>
46 #include <atalk/logger.h>
47 #include <atalk/uuid.h>
48 #include <atalk/unix.h>
50 #include "directory.h"
61 #ifdef HAVE_NFSv4_ACLS
62 extern void addir_inherit_acl(const struct vol *vol);
69 * There are currently two cache structures where afpd caches directory information
70 * a) a DID/dirname cache in a hashtable
71 * b) a (red-black) tree with CNIDs as key
73 * a) is for searching by DID/dirname
74 * b) is for searching by CNID
76 * Through additional parent, child, previous and next pointers, b) is also used to
77 * represent the on-disk layout of the filesystem. parent and child point to parent
78 * and child directory respectively, linking 2 or more subdirectories in one
79 * directory with previous and next pointers.
81 * Usage examples, highlighting the main functions:
83 * a) is eg used in enumerate():
85 * dir = dirsearch_byname() // search in cache
86 * if (dir == NULL) // not found
87 * dir = adddir() // add to cache
90 * b) is eg used in afp_getfildirparams()
91 * dirlookup() // wrapper for cache and db search
92 * => dir = dirsearch() // search in cache
96 * cnid_resolve() // resolve with CNID database
97 * cname() // add to cache
103 #define SENTINEL (&sentinel)
104 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
105 DIRTREE_COLOR_BLACK, /* color */
106 NULL, NULL, /* parent, child */
107 NULL, NULL, /* previous, next */
108 NULL, 0, 0, /* oforks, did, flags */
109 0, 0, /* ctime, offcnt */
110 NULL, NULL, NULL}; /* mname, uname, ucs2-name */
111 static struct dir rootpar = { SENTINEL, SENTINEL, NULL,
119 /* (from IM: Toolbox Essentials)
120 * dirFinderInfo (DInfo) fields:
122 * frRect 8 folder's window rectangle
124 * frLocation 4 folder's location in window
125 * frView 2 folder's view (default == closedView (256))
127 * extended dirFinderInfo (DXInfo) fields:
128 * frScroll 4 scroll position
129 * frOpenChain: 4 directory ID chain of open folders
130 * frScript: 1 script flag and code
131 * frXFlags: 1 reserved
132 * frComment: 2 comment ID
133 * frPutAway: 4 home directory ID
137 vol_tree_root(const struct vol *vol, u_int32_t did)
141 if (vol->v_curdir && vol->v_curdir->d_did == did) {
151 * redid did assignment for directories. now we use red-black trees.
155 dirsearch(const struct vol *vol, u_int32_t did)
160 /* check for 0 did */
162 afp_errno = AFPERR_PARAM;
165 if ( did == DIRDID_ROOT_PARENT ) {
167 rootpar.d_did = DIRDID_ROOT_PARENT;
168 rootpar.d_child = vol->v_dir;
172 dir = vol_tree_root(vol, did);
174 afp_errno = AFPERR_NOOBJ;
175 while ( dir != SENTINEL ) {
176 if (dir->d_did == did)
177 return dir->d_m_name ? dir : NULL;
178 dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
183 /* ------------------- */
184 int get_afp_errno(const int param)
186 if (afp_errno != AFPERR_DID1)
191 /* ------------------- */
193 dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
195 struct dir *dir = NULL;
197 if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
203 hn = hash_lookup(vol->v_hash, &key);
211 /* -----------------------------------------
212 * if did is not in the cache resolve it with cnid
215 * OSX call it with bogus id, ie file ID not folder ID,
216 * and we are really bad in this case.
219 dirlookup( struct vol *vol, u_int32_t did)
224 static char path[MAXPATHLEN + 1];
227 static char buffer[12 + MAXPATHLEN + 1];
228 int buflen = 12 + MAXPATHLEN + 1;
233 ret = dirsearch(vol, did);
234 if (ret != NULL || afp_errno == AFPERR_PARAM)
237 utf8 = utf8_encoding();
238 maxpath = (utf8)?MAXPATHLEN -7:255;
240 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
241 afp_errno = AFPERR_NOOBJ;
244 ptr = path + MAXPATHLEN;
245 if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
246 afp_errno = AFPERR_NOOBJ;
250 pathlen = len; /* no 0 in the last part */
252 strcpy(ptr - len, mpath);
255 ret = dirsearch(vol,id);
260 if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
262 NULL == (mpath = utompath(vol, upath, cnid, utf8))
264 afp_errno = AFPERR_NOOBJ;
268 len = strlen(mpath) + 1;
270 if (pathlen > maxpath) {
271 afp_errno = AFPERR_PARAM;
274 strcpy(ptr - len, mpath);
278 /* fill the cache, another place where we know about the path type */
284 temp16 = htons(pathlen);
285 memcpy(ptr, &temp16, sizeof(temp16));
287 temp = htonl(kTextEncodingUTF8);
289 memcpy(ptr, &temp, sizeof(temp));
295 *ptr = (unsigned char)pathlen;
299 /* cname is not efficient */
300 if (cname( vol, ret, &ptr ) == NULL )
303 return dirsearch(vol, did);
306 /* child addition/removal */
307 static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
312 b->d_next = a->d_child;
313 b->d_prev = b->d_next->d_prev;
314 b->d_next->d_prev = b;
315 b->d_prev->d_next = b;
317 if (!hash_alloc_insert(vol->v_hash, b, b)) {
318 LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
322 static void dirchildremove(struct dir *a,struct dir *b)
325 a->d_child = (b == b->d_next) ? NULL : b->d_next;
326 b->d_next->d_prev = b->d_prev;
327 b->d_prev->d_next = b->d_next;
328 b->d_next = b->d_prev = b;
331 /* --------------------------- */
332 /* rotate the tree to the left */
333 static void dir_leftrotate(struct vol *vol, struct dir *dir)
335 struct dir *right = dir->d_right;
337 /* whee. move the right's left tree into dir's right tree */
338 dir->d_right = right->d_left;
339 if (right->d_left != SENTINEL)
340 right->d_left->d_back = dir;
342 if (right != SENTINEL) {
343 right->d_back = dir->d_back;
347 if (!dir->d_back) /* no parent. move the right tree to the top. */
349 else if (dir == dir->d_back->d_left) /* we were on the left */
350 dir->d_back->d_left = right;
352 dir->d_back->d_right = right; /* we were on the right */
354 /* re-insert dir on the left tree */
361 /* rotate the tree to the right */
362 static void dir_rightrotate(struct vol *vol, struct dir *dir)
364 struct dir *left = dir->d_left;
366 /* whee. move the left's right tree into dir's left tree */
367 dir->d_left = left->d_right;
368 if (left->d_right != SENTINEL)
369 left->d_right->d_back = dir;
371 if (left != SENTINEL) {
372 left->d_back = dir->d_back;
376 if (!dir->d_back) /* no parent. move the left tree to the top. */
378 else if (dir == dir->d_back->d_right) /* we were on the right */
379 dir->d_back->d_right = left;
381 dir->d_back->d_left = left; /* we were on the left */
383 /* re-insert dir on the right tree */
389 /* recolor after a removal */
390 static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
394 while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
395 /* are we on the left tree? */
396 if (dir == dir->d_back->d_left) {
397 leaf = dir->d_back->d_right; /* get right side */
398 if (leaf->d_color == DIRTREE_COLOR_RED) {
399 /* we're red. we need to change to black. */
400 leaf->d_color = DIRTREE_COLOR_BLACK;
401 dir->d_back->d_color = DIRTREE_COLOR_RED;
402 dir_leftrotate(vol, dir->d_back);
403 leaf = dir->d_back->d_right;
406 /* right leaf has black end nodes */
407 if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
408 (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
409 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
410 dir = dir->d_back; /* ascend */
412 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
413 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
414 leaf->d_color = DIRTREE_COLOR_RED;
415 dir_rightrotate(vol, leaf);
416 leaf = dir->d_back->d_right;
418 leaf->d_color = dir->d_back->d_color;
419 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
420 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
421 dir_leftrotate(vol, dir->d_back);
424 } else { /* right tree */
425 leaf = dir->d_back->d_left; /* left tree */
426 if (leaf->d_color == DIRTREE_COLOR_RED) {
427 leaf->d_color = DIRTREE_COLOR_BLACK;
428 dir->d_back->d_color = DIRTREE_COLOR_RED;
429 dir_rightrotate(vol, dir->d_back);
430 leaf = dir->d_back->d_left;
433 /* left leaf has black end nodes */
434 if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
435 (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
436 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
437 dir = dir->d_back; /* ascend */
439 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
440 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
441 leaf->d_color = DIRTREE_COLOR_RED;
442 dir_leftrotate(vol, leaf);
443 leaf = dir->d_back->d_left;
445 leaf->d_color = dir->d_back->d_color;
446 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
447 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
448 dir_rightrotate(vol, dir->d_back);
453 dir->d_color = DIRTREE_COLOR_BLACK;
459 /* --------------------- */
460 static void dir_hash_del(const struct vol *vol, struct dir *dir)
464 hn = hash_lookup(vol->v_hash, dir);
466 LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
469 hash_delete(vol->v_hash, hn);
473 /* remove the node from the tree. this is just like insertion, but
474 * different. actually, it has to worry about a bunch of things that
475 * insertion doesn't care about. */
477 static void dir_remove( struct vol *vol, struct dir *dir)
480 struct ofork *of, *last;
481 struct dir *node, *leaf;
482 #endif /* REMOVE_NODES */
484 if (!dir || (dir == SENTINEL))
487 /* i'm not sure if it really helps to delete stuff. */
488 dir_hash_del(vol, dir);
489 vol->v_curdir = NULL;
492 dir->d_m_name = NULL;
493 dir->d_u_name = NULL;
494 dir->d_m_name_ucs2 = NULL;
495 #else /* ! REMOVE_NODES */
497 /* go searching for a node with at most one child */
498 if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
502 while (node->d_left != SENTINEL)
507 leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
510 leaf->d_back = node->d_back;
513 } else if (node == node->d_back->d_left) { /* left tree */
514 node->d_back->d_left = leaf;
516 node->d_back->d_right = leaf;
519 /* we want to free node, but we also want to free the data in dir.
520 * currently, that's d_name and the directory traversal bits.
521 * we just copy the necessary bits and then fix up all the
522 * various pointers to the directory. needless to say, there are
523 * a bunch of places that store the directory struct. */
525 struct dir save, *tmp;
527 memcpy(&save, dir, sizeof(save));
528 memcpy(dir, node, sizeof(struct dir));
530 /* restore the red-black bits */
531 dir->d_left = save.d_left;
532 dir->d_right = save.d_right;
533 dir->d_back = save.d_back;
534 dir->d_color = save.d_color;
536 if (node == vol->v_dir) {/* we may need to fix up this pointer */
538 rootpar.d_child = vol->v_dir;
540 /* if we aren't the root directory, we have parents and
541 * siblings to worry about */
542 if (dir->d_parent->d_child == node)
543 dir->d_parent->d_child = dir;
544 dir->d_next->d_prev = dir;
545 dir->d_prev->d_next = dir;
548 /* fix up children. */
552 tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
555 if (node == curdir) /* another pointer to fixup */
558 /* we also need to fix up oforks. bleah */
559 if ((of = dir->d_ofork)) {
560 last = of->of_d_prev;
563 of = (last == of) ? NULL : of->of_d_next;
567 /* set the node's d_name */
568 node->d_m_name = save.d_m_name;
569 node->d_u_name = save.d_u_name;
570 node->d_m_name_ucs2 = save.d_m_name_ucs2;
573 if (node->d_color == DIRTREE_COLOR_BLACK)
574 dir_rmrecolor(vol, leaf);
576 if (node->d_m_name_ucs2)
577 free(node->d_u_name_ucs2);
578 if (node->d_u_name != node->d_m_name) {
579 free(node->d_u_name);
581 free(node->d_m_name);
583 #endif /* ! REMOVE_NODES */
586 /* ---------------------------------------
587 * remove the node and its childs from the tree
589 * FIXME what about opened forks with refs to it?
590 * it's an afp specs violation because you can't delete
591 * an opened forks. Now afpd doesn't care about forks opened by other
592 * process. It's fixable within afpd if fnctl_lock, doable with smb and
593 * next to impossible for nfs and local filesystem access.
595 static void dir_invalidate( struct vol *vol, struct dir *dir)
598 /* v_root can't be deleted */
599 if (movecwd(vol, vol->v_root) < 0) {
600 LOG(log_error, logtype_afpd, "cname can't chdir to : %s", vol->v_root);
604 dirchildremove(dir->d_parent, dir);
605 dir_remove( vol, dir );
608 /* ------------------------------------ */
609 static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
613 pdir = vol_tree_root(vol, dir->d_did);
614 while (pdir->d_did != dir->d_did ) {
615 if ( pdir->d_did > dir->d_did ) {
616 if ( pdir->d_left == SENTINEL ) {
623 if ( pdir->d_right == SENTINEL ) {
628 pdir = pdir->d_right;
634 #define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/"
637 caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
642 static u_int32_t did = 0;
643 static char cname[MAXPATHLEN];
644 static char lname[MAXPATHLEN];
645 ucs2_t u2_path[MAXPATHLEN];
646 ucs2_t u2_dename[MAXPATHLEN];
647 char *tmp, *savepath;
649 if (!(vol->v_flags & AFPVOL_CASEINSEN))
652 if (veto_file(ENUMVETO, path->u_name))
655 savepath = path->u_name;
657 /* very simple cache */
658 if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
659 path->u_name = cname;
661 if (of_stat( path ) == 0 ) {
664 /* something changed, we cannot stat ... */
668 if (NULL == ( dp = opendir( "." )) ) {
669 LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name);
674 /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
675 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) )
676 LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
678 /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
680 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
681 if (NULL == check_dirent(vol, de->d_name))
684 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) )
687 if (strcasecmp_w( u2_path, u2_dename) == 0) {
689 strlcpy(cname, de->d_name, sizeof(cname));
690 path->u_name = cname;
692 if (of_stat( path ) == 0 ) {
693 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
694 strlcpy(lname, tmp, sizeof(lname));
707 /* invalidate cache */
710 path->u_name = savepath;
712 /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */
718 * attempt to extend the current dir. tree to include path
719 * as a side-effect, movecwd to that point and return the new dir
722 extenddir(struct vol *vol, struct dir *dir, struct path *path)
726 if ( path->u_name == NULL) {
727 afp_errno = AFPERR_PARAM;
731 if (check_name(vol, path->u_name)) {
732 /* the name is illegal */
733 LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name);
735 afp_errno = AFPERR_PARAM;
739 if (of_stat( path ) != 0 ) {
740 if (!(vol->v_flags & AFPVOL_CASEINSEN))
742 else if(caseenumerate(vol, path, dir) != 0)
746 if (!S_ISDIR(path->st.st_mode)) {
750 /* mac name is always with the right encoding (from cname()) */
751 if (( dir = adddir( vol, dir, path)) == NULL ) {
756 if ( movecwd( vol, dir ) < 0 ) {
763 /* -------------------------
764 appledouble mkdir afp error code.
766 static int netatalk_mkdir(const struct vol *vol, const char *name)
771 if (vol->v_flags & AFPVOL_UNIX_PRIV) {
772 if (lstat(".", &st) < 0)
774 int mode = (DIRBITS & (~S_ISGID & st.st_mode)) | (0777 & ~vol->v_umask);
775 LOG(log_maxdebug, logtype_afpd, "netatalk_mkdir(\"%s\") {parent mode: %04o, vol umask: %04o}",
776 name, st.st_mode, vol->v_umask);
778 ret = mkdir(name, mode);
780 ret = ad_mkdir(name, DIRBITS | 0777);
786 return( AFPERR_NOOBJ );
788 return( AFPERR_VLOCK );
791 return( AFPERR_ACCESS );
793 return( AFPERR_EXIST );
796 return( AFPERR_DFULL );
798 return( AFPERR_PARAM );
804 /* ------------------- */
805 static int deletedir(int dirfd, char *dir)
807 char path[MAXPATHLEN + 1];
815 if ((len = strlen(dir)) +2 > sizeof(path))
819 if ((dp = opendirat(dirfd, dir)) == NULL)
825 remain = sizeof(path) -len -1;
826 while ((de = readdir(dp)) && err == AFP_OK) {
827 /* skip this and previous directory */
828 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
831 if (strlen(de->d_name) > remain) {
835 strcpy(path + len, de->d_name);
836 if (lstatat(dirfd, path, &st)) {
839 if (S_ISDIR(st.st_mode)) {
840 err = deletedir(dirfd, path);
842 err = netatalk_unlinkat(dirfd, path);
847 /* okay. the directory is empty. delete it. note: we already got rid
850 err = netatalk_rmdir(dirfd, dir);
855 /* do a recursive copy. */
856 static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
858 char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
867 /* doesn't exist or the path is too long. */
868 if (((slen = strlen(src)) > sizeof(spath) - 2) ||
869 ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
870 ((dp = opendirat(dirfd, src)) == NULL))
873 /* try to create the destination directory */
874 if (AFP_OK != (err = netatalk_mkdir(vol, dst)) ) {
879 /* set things up to copy */
883 srem = sizeof(spath) - slen -1;
888 drem = sizeof(dpath) - dlen -1;
891 while ((de = readdir(dp))) {
892 /* skip this and previous directory */
893 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
896 if (strlen(de->d_name) > srem) {
900 strcpy(spath + slen, de->d_name);
902 if (lstatat(dirfd, spath, &st) == 0) {
903 if (strlen(de->d_name) > drem) {
907 strcpy(dpath + dlen, de->d_name);
909 if (S_ISDIR(st.st_mode)) {
910 if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath)))
912 } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) {
916 /* keep the same time stamp. */
917 ut.actime = ut.modtime = st.st_mtime;
923 /* keep the same time stamp. */
924 if (lstatat(dirfd, src, &st) == 0) {
925 ut.actime = ut.modtime = st.st_mtime;
935 /* --- public functions follow --- */
937 /* NOTE: we start off with at least one node (the root directory). */
938 static struct dir *dirinsert(struct vol *vol, struct dir *dir)
942 if ((node = dir_insert(vol, dir)))
945 /* recolor the tree. the current node is red. */
946 dir->d_color = DIRTREE_COLOR_RED;
948 /* parent of this node has to be black. if the parent node
949 * is red, then we have a grandparent. */
950 while ((dir != vol->v_root) &&
951 (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
952 /* are we on the left tree? */
953 if (dir->d_back == dir->d_back->d_back->d_left) {
954 node = dir->d_back->d_back->d_right; /* get the right node */
955 if (node->d_color == DIRTREE_COLOR_RED) {
956 /* we're red. we need to change to black. */
957 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
958 node->d_color = DIRTREE_COLOR_BLACK;
959 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
960 dir = dir->d_back->d_back; /* finished. go up. */
962 if (dir == dir->d_back->d_right) {
964 dir_leftrotate(vol, dir);
966 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
967 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
968 dir_rightrotate(vol, dir->d_back->d_back);
971 node = dir->d_back->d_back->d_left;
972 if (node->d_color == DIRTREE_COLOR_RED) {
973 /* we're red. we need to change to black. */
974 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
975 node->d_color = DIRTREE_COLOR_BLACK;
976 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
977 dir = dir->d_back->d_back; /* finished. ascend */
979 if (dir == dir->d_back->d_left) {
981 dir_rightrotate(vol, dir);
983 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
984 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
985 dir_leftrotate(vol, dir->d_back->d_back);
990 vol->v_root->d_color = DIRTREE_COLOR_BLACK;
994 /* ---------------------------- */
996 adddir(struct vol *vol, struct dir *dir, struct path *path)
998 struct dir *cdir, *edir;
1005 struct adouble *adp = NULL;
1008 upath = path->u_name;
1010 upathlen = strlen(upath);
1012 /* get_id needs adp for reading CNID from adouble file */
1013 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1014 if ((ad_open_metadata(upath, ADFLAGS_DIR, 0, &ad)) == 0)
1017 id = get_id(vol, adp, st, dir->d_did, upath, upathlen);
1020 ad_close_metadata(adp);
1025 if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
1028 name = path->m_name;
1029 if ((cdir = dirnew(name, upath)) == NULL) {
1030 LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
1033 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)) {
1034 LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
1035 cdir->d_m_name_ucs2 = NULL;
1040 if ((edir = dirinsert( vol, cdir ))) {
1041 /* it's not possible with LASTDID
1043 - someone else have moved the directory.
1044 - it's a symlink inside the share.
1045 - it's an ID reused, the old directory was deleted but not
1046 the cnid record and the server've reused the inode for
1048 for HASH (we should get ride of HASH)
1049 - someone else have moved the directory.
1050 - it's an ID reused as above
1051 - it's a hash duplicate and we are in big trouble
1053 deleted = (edir->d_m_name == NULL);
1055 dir_hash_del(vol, edir);
1057 edir->d_m_name = cdir->d_m_name;
1058 edir->d_u_name = cdir->d_u_name;
1059 edir->d_m_name_ucs2 = cdir->d_m_name_ucs2;
1062 LOG(log_error, logtype_afpd, "adddir: insert %s", edir->d_m_name);
1063 if (!cdir->d_parent || (cdir->d_parent == dir && !deleted)) {
1064 hash_alloc_insert(vol->v_hash, cdir, cdir);
1067 /* the old was not in the same folder */
1069 dirchildremove(cdir->d_parent, cdir);
1072 /* parent/child directories */
1073 cdir->d_parent = dir;
1074 dirchildadd(vol, dir, cdir);
1078 /* --- public functions follow --- */
1079 /* free everything down. we don't bother to recolor as this is only
1080 * called to free the entire tree */
1081 void dirfreename(struct dir *dir)
1083 if (dir->d_u_name != dir->d_m_name) {
1084 free(dir->d_u_name);
1086 if (dir->d_m_name_ucs2)
1087 free(dir->d_m_name_ucs2);
1088 free(dir->d_m_name);
1091 void dirfree(struct dir *dir)
1093 if (!dir || (dir == SENTINEL))
1096 if ( dir->d_left != SENTINEL ) {
1097 dirfree( dir->d_left );
1099 if ( dir->d_right != SENTINEL ) {
1100 dirfree( dir->d_right );
1103 if (dir != SENTINEL) {
1109 /* --------------------------------------------
1110 * most of the time mac name and unix name are the same
1112 struct dir *dirnew(const char *m_name, const char *u_name)
1116 dir = (struct dir *) calloc(1, sizeof( struct dir ));
1120 if ((dir->d_m_name = strdup(m_name)) == NULL) {
1125 if (m_name == u_name || !strcmp(m_name, u_name)) {
1126 dir->d_u_name = dir->d_m_name;
1128 else if ((dir->d_u_name = strdup(u_name)) == NULL) {
1129 free(dir->d_m_name);
1134 dir->d_m_name_ucs2 = NULL;
1135 dir->d_left = dir->d_right = SENTINEL;
1136 dir->d_next = dir->d_prev = dir;
1141 /* ------------------ */
1142 static hash_val_t hash_fun_dir(const void *key)
1144 const struct dir *k = key;
1146 static unsigned long randbox[] = {
1147 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
1148 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
1149 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
1150 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
1153 const unsigned char *str = (unsigned char *)(k->d_u_name);
1154 hash_val_t acc = k->d_parent->d_did;
1157 acc ^= randbox[(*str + acc) & 0xf];
1158 acc = (acc << 1) | (acc >> 31);
1160 acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
1161 acc = (acc << 2) | (acc >> 30);
1169 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
1170 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
1171 #define get16bits(d) (*((const uint16_t *) (d)))
1174 #if !defined (get16bits)
1175 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
1176 +(uint32_t)(((const uint8_t *)(d))[0]) )
1179 static hash_val_t hash_fun2_dir(const void *key)
1181 const struct dir *k = key;
1182 const char *data = k->d_u_name;
1183 int len = strlen(k->d_u_name);
1184 hash_val_t hash = k->d_parent->d_did, tmp;
1190 for (;len > 0; len--) {
1191 hash += get16bits (data);
1192 tmp = (get16bits (data+2) << 11) ^ hash;
1193 hash = (hash << 16) ^ tmp;
1194 data += 2*sizeof (uint16_t);
1198 /* Handle end cases */
1200 case 3: hash += get16bits (data);
1202 hash ^= data[sizeof (uint16_t)] << 18;
1205 case 2: hash += get16bits (data);
1209 case 1: hash += *data;
1214 /* Force "avalanching" of final 127 bits */
1225 /* ---------------- */
1226 static int hash_comp_dir(const void *key1, const void *key2)
1228 const struct dir *k1 = key1;
1229 const struct dir *k2 = key2;
1231 return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
1234 /* ---------------- */
1238 return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
1241 /* ------------------ */
1242 static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
1245 movecwd failed some of dir path are not there anymore.
1246 FIXME Is it true with other errors?
1247 so we remove dir from the cache
1249 if (dir->d_did == DIRDID_ROOT_PARENT)
1251 if (afp_errno == AFPERR_ACCESS) {
1252 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1255 /* FIXME should we set these?, don't need to call stat() after:
1257 ret->st_errno = EACCES;
1259 ret->m_name = dir->d_m_name;
1260 ret->u_name = dir->d_u_name;
1263 } else if (afp_errno == AFPERR_NOOBJ) {
1264 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1267 strcpy(ret->m_name, dir->d_m_name);
1268 if (dir->d_m_name == dir->d_u_name) {
1269 ret->u_name = ret->m_name;
1272 size_t tp = strlen(ret->m_name)+1;
1274 ret->u_name = ret->m_name +tp;
1275 strcpy(ret->u_name, dir->d_u_name);
1277 /* FIXME should we set :
1279 ret->st_errno = ENOENT;
1281 dir_invalidate(vol, dir);
1284 dir_invalidate(vol, dir);
1288 /* -------------------------------------------------- */
1294 stat the file or errno
1297 curdir: filename parent directory
1303 stat the dir or errno
1307 curdir: dir parent directory
1315 curdir: dir parent directory
1322 cname(struct vol *vol, struct dir *dir, char **cpath)
1324 struct dir *cdir, *scdir=NULL;
1325 static char path[ MAXPATHLEN + 1];
1326 static struct path ret;
1338 afp_errno = AFPERR_NOOBJ;
1339 memset(&ret, 0, sizeof(ret));
1340 switch (ret.m_type = *data) { /* path type */
1343 len = (unsigned char) *data++;
1346 if (afp_version >= 30) {
1352 if (afp_version >= 30) {
1354 memcpy(&hint, data, sizeof(hint));
1356 data += sizeof(hint);
1358 memcpy(&len16, data, sizeof(len16));
1365 /* else it's an error */
1367 afp_errno = AFPERR_PARAM;
1370 *cpath += len + size;
1375 if (movecwd( vol, dir ) < 0 ) {
1376 return invalidate(vol, dir, &ret );
1378 if (*path == '\0') {
1385 if (*data == sep ) {
1389 while (*data == sep && len > 0 ) {
1390 if ( dir->d_parent == NULL ) {
1393 dir = dir->d_parent;
1398 /* would this be faster with strlen + strncpy? */
1400 while ( *data != sep && len > 0 ) {
1402 if (p > &path[ MAXPATHLEN]) {
1403 afp_errno = AFPERR_PARAM;
1409 /* short cut bits by chopping off a trailing \0. this also
1410 makes the traversal happy w/ filenames at the end of the
1417 if ( p == path ) { /* end of the name parameter */
1421 if (afp_version >= 30) {
1426 static char temp[ MAXPATHLEN + 1];
1428 if (dir->d_did == DIRDID_ROOT_PARENT) {
1430 With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
1431 So we compare it with the longname from the current volume and if they match
1432 we overwrite the requested path with the utf8 volume name so that the following
1435 ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
1436 if (strcasecmp( path, temp) == 0)
1437 ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
1440 if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
1441 afp_errno = AFPERR_PARAM;
1447 /* check for OS X mangled filename :( */
1449 t = demangle_osx(vol, path, dir->d_did, &fileid);
1452 /* duplicate work but we can't reuse all convert_char we did in demangle_osx
1453 * flags weren't the same
1455 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
1456 /* at last got our view of mac name */
1461 if (ret.u_name == NULL) {
1462 if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
1463 afp_errno = AFPERR_PARAM;
1469 cdir = dir->d_child;
1471 if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
1472 (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
1473 CH_UCS2, path, -1, (char **)&tmpname) )
1476 if (!cdir->d_m_name_ucs2) {
1477 LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
1478 /* this shouldn't happen !!!! */
1482 if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1485 if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1488 cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
1494 if (dir->d_did == DIRDID_ROOT_PARENT) {
1496 root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
1497 must check against the volume name.
1499 if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
1505 cdir = dirsearch_byname(vol, dir, ret.u_name);
1509 if (cdir == NULL && scdir != NULL) {
1511 /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
1514 if ( cdir == NULL ) {
1516 /* if dir == curdir it always succeed,
1517 even if curdir is deleted.
1518 it's not a pb because it will fail in extenddir
1520 if ( movecwd( vol, dir ) < 0 ) {
1521 /* dir is not valid anymore
1522 we delete dir from the cache and abort.
1524 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1525 afp_errno = AFPERR_NOOBJ;
1528 if (afp_errno == AFPERR_ACCESS)
1530 dir_invalidate(vol, dir);
1533 cdir = extenddir( vol, dir, &ret );
1537 cdir = extenddir( vol, dir, &ret );
1538 } /* if (!extend) */
1540 if ( cdir == NULL ) {
1542 if ( len > 0 || !ret.u_name ) {
1554 * Move curdir to dir, with a possible chdir()
1556 int movecwd(struct vol *vol, struct dir *dir)
1558 char path[MAXPATHLEN + 1];
1564 if ( dir == curdir ) {
1567 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1568 afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
1572 p = path + sizeof(path) - 1;
1574 for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
1577 /* parent directory is deleted */
1578 afp_errno = AFPERR_NOOBJ;
1582 if (p -n -1 < path) {
1583 afp_errno = AFPERR_PARAM;
1590 if ( d != curdir ) {
1591 n = strlen( vol->v_path );
1592 if (p -n -1 < path) {
1593 afp_errno = AFPERR_PARAM;
1598 memcpy( p, vol->v_path, n );
1600 if ( (ret = lchdir(p )) != 0 ) {
1601 LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
1604 /* p is a symlink or getcwd failed */
1605 afp_errno = AFPERR_BADTYPE;
1606 vol->v_curdir = curdir = vol->v_dir;
1607 if (chdir(vol->v_path ) < 0) {
1608 LOG(log_debug, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
1609 /* XXX what do we do here? */
1616 afp_errno = AFPERR_ACCESS;
1619 afp_errno = AFPERR_NOOBJ;
1624 vol->v_curdir = curdir = dir;
1629 * We can't use unix file's perm to support Apple's inherited protection modes.
1630 * If we aren't the file's owner we can't change its perms when moving it and smb
1631 * nfs,... don't even try.
1633 #define AFP_CHECK_ACCESS
1635 int check_access(char *path, int mode)
1637 #ifdef AFP_CHECK_ACCESS
1645 accessmode(p, &ma, curdir, NULL);
1646 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1648 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1654 /* --------------------- */
1655 int file_access(struct path *path, int mode)
1659 accessmode(path->u_name, &ma, curdir, &path->st);
1660 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1662 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1668 /* --------------------- */
1669 void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
1671 dir->offcnt = count;
1672 dir->ctime = st->st_ctime;
1673 dir->d_flags &= ~DIRF_CNID;
1676 /* ---------------------
1677 * is our cached offspring count valid?
1680 static int diroffcnt(struct dir *dir, struct stat *st)
1682 return st->st_ctime == dir->ctime;
1685 /* ---------------------
1686 * is our cached also for reenumerate id?
1689 int dirreenumerate(struct dir *dir, struct stat *st)
1691 return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
1694 /* --------------------- */
1695 static int invisible_dots(const struct vol *vol, const char *name)
1697 return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
1700 /* ------------------------------
1702 (name, dir) with curdir:name == dir, from afp_enumerate
1705 int getdirparams(const struct vol *vol,
1706 u_int16_t bitmap, struct path *s_path,
1708 char *buf, size_t *buflen )
1712 char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
1713 int bit = 0, isad = 0;
1719 struct stat *st = &s_path->st;
1720 char *upath = s_path->u_name;
1722 if ((bitmap & ((1 << DIRPBIT_ATTR) |
1723 (1 << DIRPBIT_CDATE) |
1724 (1 << DIRPBIT_MDATE) |
1725 (1 << DIRPBIT_BDATE) |
1726 (1 << DIRPBIT_FINFO)))) {
1728 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1729 if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
1731 if (ad.ad_md->adf_flags & O_CREAT) {
1732 /* We just created it */
1733 ad_setname(&ad, s_path->m_name);
1738 dir->d_parent->d_did,
1745 if ( dir->d_did == DIRDID_ROOT) {
1746 pdid = DIRDID_ROOT_PARENT;
1747 } else if (dir->d_did == DIRDID_ROOT_PARENT) {
1750 pdid = dir->d_parent->d_did;
1754 while ( bitmap != 0 ) {
1755 while (( bitmap & 1 ) == 0 ) {
1763 ad_getattr(&ad, &ashort);
1764 } else if (invisible_dots(vol, dir->d_u_name)) {
1765 ashort = htons(ATTRBIT_INVISIBLE);
1768 ashort |= htons(ATTRBIT_SHARED);
1769 memcpy( data, &ashort, sizeof( ashort ));
1770 data += sizeof( ashort );
1774 memcpy( data, &pdid, sizeof( pdid ));
1775 data += sizeof( pdid );
1778 case DIRPBIT_CDATE :
1779 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1780 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1781 memcpy( data, &aint, sizeof( aint ));
1782 data += sizeof( aint );
1785 case DIRPBIT_MDATE :
1786 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1787 memcpy( data, &aint, sizeof( aint ));
1788 data += sizeof( aint );
1791 case DIRPBIT_BDATE :
1792 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
1793 aint = AD_DATE_START;
1794 memcpy( data, &aint, sizeof( aint ));
1795 data += sizeof( aint );
1798 case DIRPBIT_FINFO :
1800 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
1801 } else { /* no appledouble */
1802 memset( data, 0, 32 );
1803 /* set default view -- this also gets done in ad_open() */
1804 ashort = htons(FINDERINFO_CLOSEDVIEW);
1805 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
1807 /* dot files are by default visible */
1808 if (invisible_dots(vol, dir->d_u_name)) {
1809 ashort = htons(FINDERINFO_INVISIBLE);
1810 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
1816 case DIRPBIT_LNAME :
1817 if (dir->d_m_name) /* root of parent can have a null name */
1820 memset(data, 0, sizeof(u_int16_t));
1821 data += sizeof( u_int16_t );
1824 case DIRPBIT_SNAME :
1825 memset(data, 0, sizeof(u_int16_t));
1826 data += sizeof( u_int16_t );
1830 memcpy( data, &dir->d_did, sizeof( aint ));
1831 data += sizeof( aint );
1834 case DIRPBIT_OFFCNT :
1836 /* this needs to handle current directory access rights */
1837 if (diroffcnt(dir, st)) {
1838 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1840 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
1841 setdiroffcnt(dir, st, ret);
1842 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1844 ashort = htons( ashort );
1845 memcpy( data, &ashort, sizeof( ashort ));
1846 data += sizeof( ashort );
1850 aint = htonl(st->st_uid);
1851 memcpy( data, &aint, sizeof( aint ));
1852 data += sizeof( aint );
1856 aint = htonl(st->st_gid);
1857 memcpy( data, &aint, sizeof( aint ));
1858 data += sizeof( aint );
1861 case DIRPBIT_ACCESS :
1862 accessmode( upath, &ma, dir , st);
1864 *data++ = ma.ma_user;
1865 *data++ = ma.ma_world;
1866 *data++ = ma.ma_group;
1867 *data++ = ma.ma_owner;
1870 /* Client has requested the ProDOS information block.
1871 Just pass back the same basic block for all
1872 directories. <shirsch@ibm.net> */
1873 case DIRPBIT_PDINFO :
1874 if (afp_version >= 30) { /* UTF8 name */
1875 utf8 = kTextEncodingUTF8;
1876 if (dir->d_m_name) /* root of parent can have a null name */
1879 memset(data, 0, sizeof(u_int16_t));
1880 data += sizeof( u_int16_t );
1882 memcpy(data, &aint, sizeof( aint ));
1883 data += sizeof( aint );
1885 else { /* ProDOS Info Block */
1888 ashort = htons( 0x0200 );
1889 memcpy( data, &ashort, sizeof( ashort ));
1890 data += sizeof( ashort );
1891 memset( data, 0, sizeof( ashort ));
1892 data += sizeof( ashort );
1896 case DIRPBIT_UNIXPR :
1897 aint = htonl(st->st_uid);
1898 memcpy( data, &aint, sizeof( aint ));
1899 data += sizeof( aint );
1900 aint = htonl(st->st_gid);
1901 memcpy( data, &aint, sizeof( aint ));
1902 data += sizeof( aint );
1905 aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
1906 memcpy( data, &aint, sizeof( aint ));
1907 data += sizeof( aint );
1909 accessmode( upath, &ma, dir , st);
1911 *data++ = ma.ma_user;
1912 *data++ = ma.ma_world;
1913 *data++ = ma.ma_group;
1914 *data++ = ma.ma_owner;
1919 ad_close_metadata( &ad );
1921 return( AFPERR_BITMAP );
1927 ashort = htons( data - buf );
1928 memcpy( l_nameoff, &ashort, sizeof( ashort ));
1929 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, 0);
1931 if ( utf_nameoff ) {
1932 ashort = htons( data - buf );
1933 memcpy( utf_nameoff, &ashort, sizeof( ashort ));
1934 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, utf8);
1937 ad_close_metadata( &ad );
1939 *buflen = data - buf;
1943 /* ----------------------------- */
1944 int path_error(struct path *path, int error)
1946 /* - a dir with access error
1947 * - no error it's a file
1950 if (path_isadir(path))
1952 if (path->st_valid && path->st_errno)
1954 return AFPERR_BADTYPE ;
1957 /* ----------------------------- */
1958 int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1963 u_int16_t vid, bitmap;
1969 memcpy( &vid, ibuf, sizeof( vid ));
1970 ibuf += sizeof( vid );
1972 if (NULL == ( vol = getvolbyvid( vid )) ) {
1973 return( AFPERR_PARAM );
1976 if (vol->v_flags & AFPVOL_RO)
1977 return AFPERR_VLOCK;
1979 memcpy( &did, ibuf, sizeof( did ));
1980 ibuf += sizeof( int );
1982 if (NULL == ( dir = dirlookup( vol, did )) ) {
1986 memcpy( &bitmap, ibuf, sizeof( bitmap ));
1987 bitmap = ntohs( bitmap );
1988 ibuf += sizeof( bitmap );
1990 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1991 return get_afp_errno(AFPERR_NOOBJ);
1994 if ( *path->m_name != '\0' ) {
1995 rc = path_error(path, AFPERR_NOOBJ);
1996 /* maybe we are trying to set perms back */
1997 if (rc != AFPERR_ACCESS)
2002 * If ibuf is odd, make it even.
2004 if ((u_long)ibuf & 1 ) {
2008 if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
2009 setvoltime(obj, vol );
2015 * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
2017 * assume path == '\0' eg. it's a directory in canonical form
2020 struct path Cur_Path = {
2023 ".", /* unix name */
2025 NULL,/* struct dir */
2026 0, /* stat is not set */
2029 /* ------------------ */
2030 static int set_dir_errors(struct path *path, const char *where, int err)
2035 return AFPERR_ACCESS;
2037 return AFPERR_VLOCK;
2039 LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
2040 return AFPERR_PARAM;
2043 /* ------------------ */
2044 int setdirparams(struct vol *vol,
2045 struct path *path, u_int16_t d_bitmap, char *buf )
2057 u_int16_t ashort, bshort, oshort;
2059 int change_mdate = 0;
2060 int change_parent_mdate = 0;
2062 u_int16_t bitmap = d_bitmap;
2063 u_char finder_buf[32];
2066 u_int16_t upriv_bit = 0;
2069 upath = path->u_name;
2071 while ( bitmap != 0 ) {
2072 while (( bitmap & 1 ) == 0 ) {
2080 memcpy( &ashort, buf, sizeof( ashort ));
2081 buf += sizeof( ashort );
2083 case DIRPBIT_CDATE :
2085 memcpy(&cdate, buf, sizeof(cdate));
2086 buf += sizeof( cdate );
2088 case DIRPBIT_MDATE :
2089 memcpy(&newdate, buf, sizeof(newdate));
2090 buf += sizeof( newdate );
2092 case DIRPBIT_BDATE :
2094 memcpy(&bdate, buf, sizeof(bdate));
2095 buf += sizeof( bdate );
2097 case DIRPBIT_FINFO :
2099 memcpy( finder_buf, buf, 32 );
2102 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2103 change_parent_mdate = 1;
2104 memcpy( &owner, buf, sizeof(owner));
2105 buf += sizeof( owner );
2108 change_parent_mdate = 1;
2109 memcpy( &group, buf, sizeof( group ));
2110 buf += sizeof( group );
2112 case DIRPBIT_ACCESS :
2114 change_parent_mdate = 1;
2115 ma.ma_user = *buf++;
2116 ma.ma_world = *buf++;
2117 ma.ma_group = *buf++;
2118 ma.ma_owner = *buf++;
2119 mpriv = mtoumode( &ma ) | vol->v_dperm;
2120 if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2121 err = set_dir_errors(path, "setdirmode", errno);
2125 /* Ignore what the client thinks we should do to the
2126 ProDOS information block. Skip over the data and
2127 report nothing amiss. <shirsch@ibm.net> */
2128 case DIRPBIT_PDINFO :
2129 if (afp_version < 30) {
2133 err = AFPERR_BITMAP;
2137 case DIRPBIT_UNIXPR :
2138 if (vol_unix_priv(vol)) {
2139 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
2140 buf += sizeof( owner );
2141 memcpy( &group, buf, sizeof( group ));
2142 buf += sizeof( group );
2145 change_parent_mdate = 1;
2146 memcpy( &upriv, buf, sizeof( upriv ));
2147 buf += sizeof( upriv );
2148 upriv = ntohl (upriv) | vol->v_dperm;
2149 if (dir_rx_set(upriv)) {
2150 /* maybe we are trying to set perms back */
2151 if ( setdirunixmode(vol, upath, upriv) < 0 ) {
2153 err = set_dir_errors(path, "setdirunixmode", errno);
2164 err = AFPERR_BITMAP;
2172 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2174 if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
2176 * Check to see what we're trying to set. If it's anything
2177 * but ACCESS, UID, or GID, give an error. If it's any of those
2178 * three, we don't need the ad to be open, so just continue.
2180 * note: we also don't need to worry about mdate. also, be quiet
2181 * if we're using the noadouble option.
2183 if (!vol_noadouble(vol) && (d_bitmap &
2184 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
2185 (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
2186 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
2187 return AFPERR_ACCESS;
2193 * Check to see if a create was necessary. If it was, we'll want
2194 * to set our name, etc.
2196 if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
2197 ad_setname(&ad, curdir->d_m_name);
2203 while ( bitmap != 0 ) {
2204 while (( bitmap & 1 ) == 0 ) {
2212 ad_getattr(&ad, &bshort);
2214 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
2215 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
2219 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
2220 change_parent_mdate = 1;
2221 ad_setattr(&ad, bshort);
2224 case DIRPBIT_CDATE :
2226 ad_setdate(&ad, AD_DATE_CREATE, cdate);
2229 case DIRPBIT_MDATE :
2231 case DIRPBIT_BDATE :
2233 ad_setdate(&ad, AD_DATE_BACKUP, bdate);
2236 case DIRPBIT_FINFO :
2238 /* Fixes #2802236 */
2239 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
2240 *fflags &= htons(~FINDERINFO_ISHARED);
2242 if ( dir->d_did == DIRDID_ROOT ) {
2244 * Alright, we admit it, this is *really* sick!
2245 * The 4 bytes that we don't copy, when we're dealing
2246 * with the root of a volume, are the directory's
2247 * location information. This eliminates that annoying
2248 * behavior one sees when mounting above another mount
2251 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
2252 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
2254 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
2258 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2259 if ( (dir->d_did == DIRDID_ROOT) &&
2260 (setdeskowner( ntohl(owner), -1 ) < 0)) {
2261 err = set_dir_errors(path, "setdeskowner", errno);
2262 if (isad && err == AFPERR_PARAM) {
2263 err = AFP_OK; /* ???*/
2266 goto setdirparam_done;
2269 if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
2270 err = set_dir_errors(path, "setdirowner", errno);
2271 goto setdirparam_done;
2275 if (dir->d_did == DIRDID_ROOT)
2276 setdeskowner( -1, ntohl(group) );
2277 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2278 err = set_dir_errors(path, "setdirowner", errno);
2279 goto setdirparam_done;
2282 case DIRPBIT_ACCESS :
2283 if (dir->d_did == DIRDID_ROOT) {
2285 if (!dir_rx_set(mpriv)) {
2286 /* we can't remove read and search for owner on volume root */
2287 err = AFPERR_ACCESS;
2288 goto setdirparam_done;
2292 if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2293 err = set_dir_errors(path, "setdirmode", errno);
2294 goto setdirparam_done;
2297 case DIRPBIT_PDINFO :
2298 if (afp_version >= 30) {
2299 err = AFPERR_BITMAP;
2300 goto setdirparam_done;
2303 case DIRPBIT_UNIXPR :
2304 if (vol_unix_priv(vol)) {
2305 if (dir->d_did == DIRDID_ROOT) {
2306 if (!dir_rx_set(upriv)) {
2307 /* we can't remove read and search for owner on volume root */
2308 err = AFPERR_ACCESS;
2309 goto setdirparam_done;
2311 setdeskowner( -1, ntohl(group) );
2312 setdeskmode( upriv );
2314 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2315 err = set_dir_errors(path, "setdirowner", errno);
2316 goto setdirparam_done;
2319 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
2320 err = set_dir_errors(path, "setdirunixmode", errno);
2321 goto setdirparam_done;
2325 err = AFPERR_BITMAP;
2326 goto setdirparam_done;
2330 err = AFPERR_BITMAP;
2331 goto setdirparam_done;
2340 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
2341 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2345 ad_setdate(&ad, AD_DATE_MODIFY, newdate);
2346 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
2351 if (path->st_valid && !path->st_errno) {
2352 struct stat *st = &path->st;
2354 if (dir && dir->d_parent) {
2355 ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_parent->d_did, vol->v_stamp);
2359 ad_close_metadata( &ad);
2362 if (change_parent_mdate && dir->d_did != DIRDID_ROOT
2363 && gettimeofday(&tv, NULL) == 0) {
2364 if (!movecwd(vol, dir->d_parent)) {
2365 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2366 /* be careful with bitmap because now dir is null */
2367 bitmap = 1<<DIRPBIT_MDATE;
2368 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
2369 /* should we reset curdir ?*/
2376 int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2390 memcpy( &vid, ibuf, sizeof( vid ));
2391 ibuf += sizeof( vid );
2392 if (NULL == (vol = getvolbyvid( vid )) ) {
2393 return( AFPERR_PARAM );
2396 memcpy( &did, ibuf, sizeof( did ));
2397 ibuf += sizeof( did );
2401 * if it's CNID 2 our only choice to meet the specs is call sync.
2402 * For any other CNID just sync that dir. To my knowledge the
2403 * intended use of FPSyncDir is to sync the volume so all we're
2404 * ever going to see here is probably CNID 2. Anyway, we' prepared.
2407 if ( ntohl(did) == 2 ) {
2410 if (NULL == ( dir = dirlookup( vol, did )) ) {
2411 return afp_errno; /* was AFPERR_NOOBJ */
2414 if (movecwd( vol, dir ) < 0 )
2415 return ( AFPERR_NOOBJ );
2418 * Assuming only OSens that have dirfd also may require fsyncing directories
2419 * in order to flush metadata e.g. Linux.
2423 if (NULL == ( dp = opendir( "." )) ) {
2426 return( AFPERR_NOOBJ );
2428 return( AFPERR_ACCESS );
2430 return( AFPERR_PARAM );
2434 LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
2437 if ( fsync ( dfd ) < 0 )
2438 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2439 dir->d_u_name, strerror(errno) );
2440 closedir(dp); /* closes dfd too */
2443 if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
2446 return( AFPERR_NOOBJ );
2448 return( AFPERR_ACCESS );
2450 return( AFPERR_PARAM );
2454 LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
2455 vol->ad_path(".", ADFLAGS_DIR) );
2457 if ( fsync(dfd) < 0 )
2458 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2459 vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
2466 int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2472 struct path *s_path;
2480 memcpy( &vid, ibuf, sizeof( vid ));
2481 ibuf += sizeof( vid );
2482 if (NULL == ( vol = getvolbyvid( vid )) ) {
2483 return( AFPERR_PARAM );
2486 if (vol->v_flags & AFPVOL_RO)
2487 return AFPERR_VLOCK;
2489 memcpy( &did, ibuf, sizeof( did ));
2490 ibuf += sizeof( did );
2491 if (NULL == ( dir = dirlookup( vol, did )) ) {
2492 return afp_errno; /* was AFPERR_NOOBJ */
2494 /* for concurrent access we need to be sure we are not in the
2495 * folder we want to create...
2499 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
2500 return get_afp_errno(AFPERR_PARAM);
2502 /* cname was able to move curdir to it! */
2503 if (*s_path->m_name == '\0')
2504 return AFPERR_EXIST;
2506 upath = s_path->u_name;
2508 if (AFP_OK != (err = netatalk_mkdir(vol, upath))) {
2512 if (of_stat(s_path) < 0) {
2516 if ((dir = adddir( vol, curdir, s_path)) == NULL) {
2520 if ( movecwd( vol, dir ) < 0 ) {
2521 return( AFPERR_PARAM );
2524 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2525 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
2526 if (vol_noadouble(vol))
2527 goto createdir_done;
2528 return( AFPERR_ACCESS );
2530 ad_setname(&ad, s_path->m_name);
2531 ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
2534 ad_close_metadata( &ad);
2537 #ifdef HAVE_NFSv4_ACLS
2538 /* FIXME: are we really inside the created dir? */
2539 addir_inherit_acl(vol);
2542 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
2543 *rbuflen = sizeof( u_int32_t );
2544 setvoltime(obj, vol );
2549 * dst new unix filename (not a pathname)
2550 * newname new mac name
2552 * dirfd -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd
2554 int renamedir(const struct vol *vol,
2559 struct dir *newparent,
2567 /* existence check moved to afp_moveandrename */
2568 if ( unix_rename(dirfd, src, -1, dst ) < 0 ) {
2571 return( AFPERR_NOOBJ );
2573 return( AFPERR_ACCESS );
2575 return AFPERR_VLOCK;
2577 /* tried to move directory into a subdirectory of itself */
2578 return AFPERR_CANTMOVE;
2580 /* this needs to copy and delete. bleah. that means we have
2581 * to deal with entire directory hierarchies. */
2582 if ((err = copydir(vol, dirfd, src, dst)) < 0) {
2586 if ((err = deletedir(dirfd, src)) < 0)
2590 return( AFPERR_PARAM );
2594 vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
2596 len = strlen( newname );
2597 /* rename() succeeded so we need to update our tree even if we can't open
2601 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2603 if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
2604 ad_setname(&ad, newname);
2606 ad_close_metadata( &ad);
2609 dir_hash_del(vol, dir);
2610 if (dir->d_m_name == dir->d_u_name)
2611 dir->d_u_name = NULL;
2613 if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
2614 LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
2615 /* FIXME : fatal ? */
2618 dir->d_m_name = buf;
2619 strcpy( dir->d_m_name, newname );
2621 if (newname == dst) {
2622 free(dir->d_u_name);
2623 dir->d_u_name = dir->d_m_name;
2626 if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
2627 LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
2630 dir->d_u_name = buf;
2631 strcpy( dir->d_u_name, dst );
2634 if (dir->d_m_name_ucs2)
2635 free(dir->d_m_name_ucs2);
2637 dir->d_m_name_ucs2 = NULL;
2638 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))
2639 dir->d_m_name_ucs2 = NULL;
2641 if (( parent = dir->d_parent ) == NULL ) {
2644 if ( parent == newparent ) {
2645 hash_alloc_insert(vol->v_hash, dir, dir);
2649 /* detach from old parent and add to new one. */
2650 dirchildremove(parent, dir);
2651 dir->d_parent = newparent;
2652 dirchildadd(vol, newparent, dir);
2656 /* delete an empty directory */
2657 int deletecurdir(struct vol *vol)
2667 if ( curdir->d_parent == NULL ) {
2668 return( AFPERR_ACCESS );
2673 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2674 /* we never want to create a resource fork here, we are going to delete it */
2675 if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
2677 ad_getattr(&ad, &ashort);
2678 ad_close_metadata(&ad);
2679 if ((ashort & htons(ATTRBIT_NODELETE))) {
2680 return AFPERR_OLOCK;
2683 err = vol->vfs->vfs_deletecurdir(vol);
2688 /* now get rid of dangling symlinks */
2689 if ((dp = opendir("."))) {
2690 while ((de = readdir(dp))) {
2691 /* skip this and previous directory */
2692 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2695 /* bail if it's not a symlink */
2696 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
2698 return AFPERR_DIRNEMPT;
2701 if ((err = netatalk_unlink(de->d_name))) {
2708 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
2713 err = netatalk_rmdir_all_errors(-1, fdir->d_u_name);
2714 if ( err == AFP_OK || err == AFPERR_NOOBJ) {
2715 dirchildremove(curdir, fdir);
2716 cnid_delete(vol->v_cdb, fdir->d_did);
2717 dir_remove( vol, fdir );
2721 /* inode is used as key for cnid.
2722 * Close the descriptor only after cnid_delete
2730 int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2740 sfunc = (unsigned char) *ibuf++;
2744 if (sfunc >= 3 && sfunc <= 6) {
2745 if (afp_version < 30) {
2746 return( AFPERR_PARAM );
2753 case 3 :/* unicode */
2754 memcpy( &id, ibuf, sizeof( id ));
2757 if (( pw = getpwuid( id )) == NULL ) {
2758 return( AFPERR_NOITEM );
2760 len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
2761 pw->pw_name, -1, &name);
2768 case 4 : /* unicode */
2769 memcpy( &id, ibuf, sizeof( id ));
2772 if (NULL == ( gr = (struct group *)getgrgid( id ))) {
2773 return( AFPERR_NOITEM );
2775 len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
2776 gr->gr_name, -1, &name);
2782 #ifdef HAVE_NFSv4_ACLS
2783 case 5 : /* UUID -> username */
2784 case 6 : /* UUID -> groupname */
2785 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2786 return AFPERR_PARAM;
2787 LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
2789 len = getnamefromuuid( ibuf, &name, &type);
2790 if (len != 0) /* its a error code, not len */
2791 return AFPERR_NOITEM;
2792 if (type == UUID_USER) {
2793 if (( pw = getpwnam( name )) == NULL )
2794 return( AFPERR_NOITEM );
2795 LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
2796 id = htonl(UUID_USER);
2797 memcpy( rbuf, &id, sizeof( id ));
2798 id = htonl( pw->pw_uid);
2799 rbuf += sizeof( id );
2800 memcpy( rbuf, &id, sizeof( id ));
2801 rbuf += sizeof( id );
2802 *rbuflen = 2 * sizeof( id );
2803 } else { /* type == UUID_GROUP */
2804 if (( gr = getgrnam( name )) == NULL )
2805 return( AFPERR_NOITEM );
2806 LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
2807 id = htonl(UUID_GROUP);
2808 memcpy( rbuf, &id, sizeof( id ));
2809 rbuf += sizeof( id );
2810 id = htonl( gr->gr_gid);
2811 memcpy( rbuf, &id, sizeof( id ));
2812 rbuf += sizeof( id );
2813 *rbuflen = 2 * sizeof( id );
2818 return( AFPERR_PARAM );
2822 len = strlen( name );
2825 u_int16_t tp = htons(len);
2826 memcpy(rbuf, &tp, sizeof(tp));
2835 memcpy( rbuf, name, len );
2843 int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2852 sfunc = (unsigned char) *ibuf++;
2854 LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
2857 case 2 : /* unicode */
2858 if (afp_version < 30) {
2859 return( AFPERR_PARAM );
2861 memcpy(&ulen, ibuf, sizeof(ulen));
2864 LOG(log_debug, logtype_afpd, "afp_mapname: alive");
2868 len = (unsigned char) *ibuf++;
2870 #ifdef HAVE_NFSv4_ACLS
2871 case 5 : /* username -> UUID */
2872 case 6 : /* groupname -> UUID */
2873 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2874 return AFPERR_PARAM;
2875 memcpy(&ulen, ibuf, sizeof(ulen));
2881 return( AFPERR_PARAM );
2887 return AFPERR_PARAM;
2890 case 1 : /* unicode */
2892 if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) {
2893 return( AFPERR_NOITEM );
2897 memcpy( rbuf, &id, sizeof( id ));
2898 *rbuflen = sizeof( id );
2901 case 2 : /* unicode */
2903 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
2904 if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
2905 return( AFPERR_NOITEM );
2908 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
2910 memcpy( rbuf, &id, sizeof( id ));
2911 *rbuflen = sizeof( id );
2913 #ifdef HAVE_NFSv4_ACLS
2914 case 5 : /* username -> UUID */
2915 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2916 if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
2917 return AFPERR_NOITEM;
2918 *rbuflen = UUID_BINSIZE;
2920 case 6 : /* groupname -> UUID */
2921 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2922 if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
2923 return AFPERR_NOITEM;
2924 *rbuflen = UUID_BINSIZE;
2932 /* ------------------------------------
2933 variable DID support
2935 int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2946 /* do nothing as dids are static for the life of the process. */
2950 memcpy(&vid, ibuf, sizeof( vid ));
2951 ibuf += sizeof( vid );
2952 if (( vol = getvolbyvid( vid )) == NULL ) {
2953 return( AFPERR_PARAM );
2956 memcpy( &did, ibuf, sizeof( did ));
2957 ibuf += sizeof( did );
2958 if (( dir = dirlookup( vol, did )) == NULL ) {
2959 return( AFPERR_PARAM );
2962 /* dir_remove -- deletedid */
2968 /* did creation gets done automatically
2969 * there's a pb again with case but move it to cname
2971 int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2974 struct dir *parentdir;
2982 memcpy(&vid, ibuf, sizeof(vid));
2983 ibuf += sizeof( vid );
2985 if (NULL == ( vol = getvolbyvid( vid )) ) {
2986 return( AFPERR_PARAM );
2989 memcpy(&did, ibuf, sizeof(did));
2990 ibuf += sizeof(did);
2992 if (NULL == ( parentdir = dirlookup( vol, did )) ) {
2996 if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
2997 return get_afp_errno(AFPERR_PARAM);
3000 if ( *path->m_name != '\0' ) {
3001 return path_error(path, AFPERR_NOOBJ);
3004 if ( !path->st_valid && of_stat(path ) < 0 ) {
3005 return( AFPERR_NOOBJ );
3007 if ( path->st_errno ) {
3008 return( AFPERR_NOOBJ );
3011 memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did));
3012 *rbuflen = sizeof(curdir->d_did);