2 * $Id: directory.c,v 1.132 2010-02-10 14:05:37 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 * @brief symlink safe chdir replacement
139 * Only chdirs to dir if it doesn't contain symlinks.
141 * @returns 1 if a path element is a symlink, 0 otherwise, -1 on syserror
143 static int lchdir(const char *dir)
146 char buf[MAXPATHLEN+1];
147 #ifdef REALPATH_TAKES_NULL
150 char rpath[MAXPATHLEN+1];
153 /* dir might be an relative or an absolute path */
155 /* absolute path, just make sure buf is prepared for strlcat */
158 /* relative path, push cwd int buf */
159 if (getcwd(buf, MAXPATHLEN) == NULL)
161 if (strlcat(buf, "/", MAXPATHLEN) >= MAXPATHLEN)
165 if (strlcat(buf, dir, MAXPATHLEN) >= MAXPATHLEN)
168 #ifdef REALPATH_TAKES_NULL
169 if ((rpath = realpath(dir, NULL)) == NULL) {
171 if (realpath(dir, rpath) == NULL) {
179 * chdir request | realpath result | ret
180 * (after getwcwd) | |
181 * =======================================
184 * /a/b/. | /c/d/e/f | 1
187 for (int i = 0; rpath[i]; i++) {
188 if (buf[i] != rpath[i]) {
194 if (chdir(dir) != 0) {
200 #ifdef REALPATH_TAKES_NULL
207 vol_tree_root(const struct vol *vol, u_int32_t did)
211 if (vol->v_curdir && vol->v_curdir->d_did == did) {
221 * redid did assignment for directories. now we use red-black trees.
225 dirsearch(const struct vol *vol, u_int32_t did)
230 /* check for 0 did */
232 afp_errno = AFPERR_PARAM;
235 if ( did == DIRDID_ROOT_PARENT ) {
237 rootpar.d_did = DIRDID_ROOT_PARENT;
238 rootpar.d_child = vol->v_dir;
242 dir = vol_tree_root(vol, did);
244 afp_errno = AFPERR_NOOBJ;
245 while ( dir != SENTINEL ) {
246 if (dir->d_did == did)
247 return dir->d_m_name ? dir : NULL;
248 dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
253 /* ------------------- */
254 int get_afp_errno(const int param)
256 if (afp_errno != AFPERR_DID1)
261 /* ------------------- */
263 dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
265 struct dir *dir = NULL;
267 if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
273 hn = hash_lookup(vol->v_hash, &key);
281 /* -----------------------------------------
282 * if did is not in the cache resolve it with cnid
285 * OSX call it with bogus id, ie file ID not folder ID,
286 * and we are really bad in this case.
289 dirlookup( struct vol *vol, u_int32_t did)
294 static char path[MAXPATHLEN + 1];
297 static char buffer[12 + MAXPATHLEN + 1];
298 int buflen = 12 + MAXPATHLEN + 1;
303 ret = dirsearch(vol, did);
304 if (ret != NULL || afp_errno == AFPERR_PARAM)
307 utf8 = utf8_encoding();
308 maxpath = (utf8)?MAXPATHLEN -7:255;
310 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
311 afp_errno = AFPERR_NOOBJ;
314 ptr = path + MAXPATHLEN;
315 if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
316 afp_errno = AFPERR_NOOBJ;
320 pathlen = len; /* no 0 in the last part */
322 strcpy(ptr - len, mpath);
325 ret = dirsearch(vol,id);
330 if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
332 NULL == (mpath = utompath(vol, upath, cnid, utf8))
334 afp_errno = AFPERR_NOOBJ;
338 len = strlen(mpath) + 1;
340 if (pathlen > maxpath) {
341 afp_errno = AFPERR_PARAM;
344 strcpy(ptr - len, mpath);
348 /* fill the cache, another place where we know about the path type */
354 temp16 = htons(pathlen);
355 memcpy(ptr, &temp16, sizeof(temp16));
357 temp = htonl(kTextEncodingUTF8);
359 memcpy(ptr, &temp, sizeof(temp));
365 *ptr = (unsigned char)pathlen;
369 /* cname is not efficient */
370 if (cname( vol, ret, &ptr ) == NULL )
373 return dirsearch(vol, did);
376 /* child addition/removal */
377 static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
382 b->d_next = a->d_child;
383 b->d_prev = b->d_next->d_prev;
384 b->d_next->d_prev = b;
385 b->d_prev->d_next = b;
387 if (!hash_alloc_insert(vol->v_hash, b, b)) {
388 LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
392 static void dirchildremove(struct dir *a,struct dir *b)
395 a->d_child = (b == b->d_next) ? NULL : b->d_next;
396 b->d_next->d_prev = b->d_prev;
397 b->d_prev->d_next = b->d_next;
398 b->d_next = b->d_prev = b;
401 /* --------------------------- */
402 /* rotate the tree to the left */
403 static void dir_leftrotate(struct vol *vol, struct dir *dir)
405 struct dir *right = dir->d_right;
407 /* whee. move the right's left tree into dir's right tree */
408 dir->d_right = right->d_left;
409 if (right->d_left != SENTINEL)
410 right->d_left->d_back = dir;
412 if (right != SENTINEL) {
413 right->d_back = dir->d_back;
417 if (!dir->d_back) /* no parent. move the right tree to the top. */
419 else if (dir == dir->d_back->d_left) /* we were on the left */
420 dir->d_back->d_left = right;
422 dir->d_back->d_right = right; /* we were on the right */
424 /* re-insert dir on the left tree */
431 /* rotate the tree to the right */
432 static void dir_rightrotate(struct vol *vol, struct dir *dir)
434 struct dir *left = dir->d_left;
436 /* whee. move the left's right tree into dir's left tree */
437 dir->d_left = left->d_right;
438 if (left->d_right != SENTINEL)
439 left->d_right->d_back = dir;
441 if (left != SENTINEL) {
442 left->d_back = dir->d_back;
446 if (!dir->d_back) /* no parent. move the left tree to the top. */
448 else if (dir == dir->d_back->d_right) /* we were on the right */
449 dir->d_back->d_right = left;
451 dir->d_back->d_left = left; /* we were on the left */
453 /* re-insert dir on the right tree */
459 /* recolor after a removal */
460 static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
464 while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
465 /* are we on the left tree? */
466 if (dir == dir->d_back->d_left) {
467 leaf = dir->d_back->d_right; /* get right side */
468 if (leaf->d_color == DIRTREE_COLOR_RED) {
469 /* we're red. we need to change to black. */
470 leaf->d_color = DIRTREE_COLOR_BLACK;
471 dir->d_back->d_color = DIRTREE_COLOR_RED;
472 dir_leftrotate(vol, dir->d_back);
473 leaf = dir->d_back->d_right;
476 /* right leaf has black end nodes */
477 if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
478 (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
479 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
480 dir = dir->d_back; /* ascend */
482 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
483 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
484 leaf->d_color = DIRTREE_COLOR_RED;
485 dir_rightrotate(vol, leaf);
486 leaf = dir->d_back->d_right;
488 leaf->d_color = dir->d_back->d_color;
489 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
490 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
491 dir_leftrotate(vol, dir->d_back);
494 } else { /* right tree */
495 leaf = dir->d_back->d_left; /* left tree */
496 if (leaf->d_color == DIRTREE_COLOR_RED) {
497 leaf->d_color = DIRTREE_COLOR_BLACK;
498 dir->d_back->d_color = DIRTREE_COLOR_RED;
499 dir_rightrotate(vol, dir->d_back);
500 leaf = dir->d_back->d_left;
503 /* left leaf has black end nodes */
504 if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
505 (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
506 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
507 dir = dir->d_back; /* ascend */
509 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
510 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
511 leaf->d_color = DIRTREE_COLOR_RED;
512 dir_leftrotate(vol, leaf);
513 leaf = dir->d_back->d_left;
515 leaf->d_color = dir->d_back->d_color;
516 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
517 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
518 dir_rightrotate(vol, dir->d_back);
523 dir->d_color = DIRTREE_COLOR_BLACK;
529 /* --------------------- */
530 static void dir_hash_del(const struct vol *vol, struct dir *dir)
534 hn = hash_lookup(vol->v_hash, dir);
536 LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
539 hash_delete(vol->v_hash, hn);
543 /* remove the node from the tree. this is just like insertion, but
544 * different. actually, it has to worry about a bunch of things that
545 * insertion doesn't care about. */
547 static void dir_remove( struct vol *vol, struct dir *dir)
550 struct ofork *of, *last;
551 struct dir *node, *leaf;
552 #endif /* REMOVE_NODES */
554 if (!dir || (dir == SENTINEL))
557 /* i'm not sure if it really helps to delete stuff. */
558 dir_hash_del(vol, dir);
559 vol->v_curdir = NULL;
562 dir->d_m_name = NULL;
563 dir->d_u_name = NULL;
564 dir->d_m_name_ucs2 = NULL;
565 #else /* ! REMOVE_NODES */
567 /* go searching for a node with at most one child */
568 if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
572 while (node->d_left != SENTINEL)
577 leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
580 leaf->d_back = node->d_back;
583 } else if (node == node->d_back->d_left) { /* left tree */
584 node->d_back->d_left = leaf;
586 node->d_back->d_right = leaf;
589 /* we want to free node, but we also want to free the data in dir.
590 * currently, that's d_name and the directory traversal bits.
591 * we just copy the necessary bits and then fix up all the
592 * various pointers to the directory. needless to say, there are
593 * a bunch of places that store the directory struct. */
595 struct dir save, *tmp;
597 memcpy(&save, dir, sizeof(save));
598 memcpy(dir, node, sizeof(struct dir));
600 /* restore the red-black bits */
601 dir->d_left = save.d_left;
602 dir->d_right = save.d_right;
603 dir->d_back = save.d_back;
604 dir->d_color = save.d_color;
606 if (node == vol->v_dir) {/* we may need to fix up this pointer */
608 rootpar.d_child = vol->v_dir;
610 /* if we aren't the root directory, we have parents and
611 * siblings to worry about */
612 if (dir->d_parent->d_child == node)
613 dir->d_parent->d_child = dir;
614 dir->d_next->d_prev = dir;
615 dir->d_prev->d_next = dir;
618 /* fix up children. */
622 tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
625 if (node == curdir) /* another pointer to fixup */
628 /* we also need to fix up oforks. bleah */
629 if ((of = dir->d_ofork)) {
630 last = of->of_d_prev;
633 of = (last == of) ? NULL : of->of_d_next;
637 /* set the node's d_name */
638 node->d_m_name = save.d_m_name;
639 node->d_u_name = save.d_u_name;
640 node->d_m_name_ucs2 = save.d_m_name_ucs2;
643 if (node->d_color == DIRTREE_COLOR_BLACK)
644 dir_rmrecolor(vol, leaf);
646 if (node->d_m_name_ucs2)
647 free(node->d_u_name_ucs2);
648 if (node->d_u_name != node->d_m_name) {
649 free(node->d_u_name);
651 free(node->d_m_name);
653 #endif /* ! REMOVE_NODES */
656 /* ---------------------------------------
657 * remove the node and its childs from the tree
659 * FIXME what about opened forks with refs to it?
660 * it's an afp specs violation because you can't delete
661 * an opened forks. Now afpd doesn't care about forks opened by other
662 * process. It's fixable within afpd if fnctl_lock, doable with smb and
663 * next to impossible for nfs and local filesystem access.
665 static void dir_invalidate( struct vol *vol, struct dir *dir)
668 /* v_root can't be deleted */
669 if (movecwd(vol, vol->v_root) < 0) {
670 LOG(log_error, logtype_afpd, "cname can't chdir to : %s", vol->v_root);
674 dirchildremove(dir->d_parent, dir);
675 dir_remove( vol, dir );
678 /* ------------------------------------ */
679 static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
683 pdir = vol_tree_root(vol, dir->d_did);
684 while (pdir->d_did != dir->d_did ) {
685 if ( pdir->d_did > dir->d_did ) {
686 if ( pdir->d_left == SENTINEL ) {
693 if ( pdir->d_right == SENTINEL ) {
698 pdir = pdir->d_right;
704 #define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/"
707 caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
712 static u_int32_t did = 0;
713 static char cname[MAXPATHLEN];
714 static char lname[MAXPATHLEN];
715 ucs2_t u2_path[MAXPATHLEN];
716 ucs2_t u2_dename[MAXPATHLEN];
717 char *tmp, *savepath;
719 if (!(vol->v_flags & AFPVOL_CASEINSEN))
722 if (veto_file(ENUMVETO, path->u_name))
725 savepath = path->u_name;
727 /* very simple cache */
728 if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
729 path->u_name = cname;
731 if (of_stat( path ) == 0 ) {
734 /* something changed, we cannot stat ... */
738 if (NULL == ( dp = opendir( "." )) ) {
739 LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name);
744 /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
745 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) )
746 LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
748 /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
750 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
751 if (NULL == check_dirent(vol, de->d_name))
754 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) )
757 if (strcasecmp_w( u2_path, u2_dename) == 0) {
759 strlcpy(cname, de->d_name, sizeof(cname));
760 path->u_name = cname;
762 if (of_stat( path ) == 0 ) {
763 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
764 strlcpy(lname, tmp, sizeof(lname));
777 /* invalidate cache */
780 path->u_name = savepath;
782 /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */
788 * attempt to extend the current dir. tree to include path
789 * as a side-effect, movecwd to that point and return the new dir
792 extenddir(struct vol *vol, struct dir *dir, struct path *path)
796 if ( path->u_name == NULL) {
797 afp_errno = AFPERR_PARAM;
801 if (check_name(vol, path->u_name)) {
802 /* the name is illegal */
803 LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name);
805 afp_errno = AFPERR_PARAM;
809 if (of_stat( path ) != 0 ) {
810 if (!(vol->v_flags & AFPVOL_CASEINSEN))
812 else if(caseenumerate(vol, path, dir) != 0)
816 if (!S_ISDIR(path->st.st_mode)) {
820 /* mac name is always with the right encoding (from cname()) */
821 if (( dir = adddir( vol, dir, path)) == NULL ) {
826 if ( movecwd( vol, dir ) < 0 ) {
833 /* -------------------------
834 appledouble mkdir afp error code.
836 static int netatalk_mkdir(const char *name)
838 if (ad_mkdir(name, DIRBITS | 0777) < 0) {
841 return( AFPERR_NOOBJ );
843 return( AFPERR_VLOCK );
846 return( AFPERR_ACCESS );
848 return( AFPERR_EXIST );
851 return( AFPERR_DFULL );
853 return( AFPERR_PARAM );
859 /* ------------------- */
860 static int deletedir(char *dir)
862 char path[MAXPATHLEN + 1];
870 if ((len = strlen(dir)) +2 > sizeof(path))
874 if ((dp = opendir(dir)) == NULL)
880 remain = sizeof(path) -len -1;
881 while ((de = readdir(dp)) && err == AFP_OK) {
882 /* skip this and previous directory */
883 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
886 if (strlen(de->d_name) > remain) {
890 strcpy(path + len, de->d_name);
891 if (lstat(path, &st)) {
894 if (S_ISDIR(st.st_mode)) {
895 err = deletedir(path);
897 err = netatalk_unlink(path);
902 /* okay. the directory is empty. delete it. note: we already got rid
905 err = netatalk_rmdir(dir);
910 /* do a recursive copy. */
911 static int copydir(const struct vol *vol, char *src, char *dst)
913 char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
922 /* doesn't exist or the path is too long. */
923 if (((slen = strlen(src)) > sizeof(spath) - 2) ||
924 ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
925 ((dp = opendir(src)) == NULL))
928 /* try to create the destination directory */
929 if (AFP_OK != (err = netatalk_mkdir(dst)) ) {
934 /* set things up to copy */
938 srem = sizeof(spath) - slen -1;
943 drem = sizeof(dpath) - dlen -1;
946 while ((de = readdir(dp))) {
947 /* skip this and previous directory */
948 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
951 if (strlen(de->d_name) > srem) {
955 strcpy(spath + slen, de->d_name);
957 if (lstat(spath, &st) == 0) {
958 if (strlen(de->d_name) > drem) {
962 strcpy(dpath + dlen, de->d_name);
964 if (S_ISDIR(st.st_mode)) {
965 if (AFP_OK != (err = copydir(vol, spath, dpath)))
967 } else if (AFP_OK != (err = copyfile(vol, vol, spath, dpath, NULL, NULL))) {
971 /* keep the same time stamp. */
972 ut.actime = ut.modtime = st.st_mtime;
978 /* keep the same time stamp. */
979 if (lstat(src, &st) == 0) {
980 ut.actime = ut.modtime = st.st_mtime;
990 /* --- public functions follow --- */
992 /* NOTE: we start off with at least one node (the root directory). */
993 static struct dir *dirinsert(struct vol *vol, struct dir *dir)
997 if ((node = dir_insert(vol, dir)))
1000 /* recolor the tree. the current node is red. */
1001 dir->d_color = DIRTREE_COLOR_RED;
1003 /* parent of this node has to be black. if the parent node
1004 * is red, then we have a grandparent. */
1005 while ((dir != vol->v_root) &&
1006 (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
1007 /* are we on the left tree? */
1008 if (dir->d_back == dir->d_back->d_back->d_left) {
1009 node = dir->d_back->d_back->d_right; /* get the right node */
1010 if (node->d_color == DIRTREE_COLOR_RED) {
1011 /* we're red. we need to change to black. */
1012 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
1013 node->d_color = DIRTREE_COLOR_BLACK;
1014 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
1015 dir = dir->d_back->d_back; /* finished. go up. */
1017 if (dir == dir->d_back->d_right) {
1019 dir_leftrotate(vol, dir);
1021 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
1022 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
1023 dir_rightrotate(vol, dir->d_back->d_back);
1026 node = dir->d_back->d_back->d_left;
1027 if (node->d_color == DIRTREE_COLOR_RED) {
1028 /* we're red. we need to change to black. */
1029 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
1030 node->d_color = DIRTREE_COLOR_BLACK;
1031 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
1032 dir = dir->d_back->d_back; /* finished. ascend */
1034 if (dir == dir->d_back->d_left) {
1036 dir_rightrotate(vol, dir);
1038 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
1039 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
1040 dir_leftrotate(vol, dir->d_back->d_back);
1045 vol->v_root->d_color = DIRTREE_COLOR_BLACK;
1049 /* ---------------------------- */
1051 adddir(struct vol *vol, struct dir *dir, struct path *path)
1053 struct dir *cdir, *edir;
1060 struct adouble *adp = NULL;
1063 upath = path->u_name;
1065 upathlen = strlen(upath);
1067 /* get_id needs adp for reading CNID from adouble file */
1068 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1069 if ((ad_open_metadata(upath, ADFLAGS_DIR, 0, &ad)) == 0)
1072 id = get_id(vol, adp, st, dir->d_did, upath, upathlen);
1075 ad_close_metadata(adp);
1080 if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
1083 name = path->m_name;
1084 if ((cdir = dirnew(name, upath)) == NULL) {
1085 LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
1088 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)) {
1089 LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
1090 cdir->d_m_name_ucs2 = NULL;
1095 if ((edir = dirinsert( vol, cdir ))) {
1096 /* it's not possible with LASTDID
1098 - someone else have moved the directory.
1099 - it's a symlink inside the share.
1100 - it's an ID reused, the old directory was deleted but not
1101 the cnid record and the server've reused the inode for
1103 for HASH (we should get ride of HASH)
1104 - someone else have moved the directory.
1105 - it's an ID reused as above
1106 - it's a hash duplicate and we are in big trouble
1108 deleted = (edir->d_m_name == NULL);
1110 dir_hash_del(vol, edir);
1112 edir->d_m_name = cdir->d_m_name;
1113 edir->d_u_name = cdir->d_u_name;
1114 edir->d_m_name_ucs2 = cdir->d_m_name_ucs2;
1117 LOG(log_error, logtype_afpd, "adddir: insert %s", edir->d_m_name);
1118 if (!cdir->d_parent || (cdir->d_parent == dir && !deleted)) {
1119 hash_alloc_insert(vol->v_hash, cdir, cdir);
1122 /* the old was not in the same folder */
1124 dirchildremove(cdir->d_parent, cdir);
1127 /* parent/child directories */
1128 cdir->d_parent = dir;
1129 dirchildadd(vol, dir, cdir);
1133 /* --- public functions follow --- */
1134 /* free everything down. we don't bother to recolor as this is only
1135 * called to free the entire tree */
1136 void dirfreename(struct dir *dir)
1138 if (dir->d_u_name != dir->d_m_name) {
1139 free(dir->d_u_name);
1141 if (dir->d_m_name_ucs2)
1142 free(dir->d_m_name_ucs2);
1143 free(dir->d_m_name);
1146 void dirfree(struct dir *dir)
1148 if (!dir || (dir == SENTINEL))
1151 if ( dir->d_left != SENTINEL ) {
1152 dirfree( dir->d_left );
1154 if ( dir->d_right != SENTINEL ) {
1155 dirfree( dir->d_right );
1158 if (dir != SENTINEL) {
1164 /* --------------------------------------------
1165 * most of the time mac name and unix name are the same
1167 struct dir *dirnew(const char *m_name, const char *u_name)
1171 dir = (struct dir *) calloc(1, sizeof( struct dir ));
1175 if ((dir->d_m_name = strdup(m_name)) == NULL) {
1180 if (m_name == u_name || !strcmp(m_name, u_name)) {
1181 dir->d_u_name = dir->d_m_name;
1183 else if ((dir->d_u_name = strdup(u_name)) == NULL) {
1184 free(dir->d_m_name);
1189 dir->d_m_name_ucs2 = NULL;
1190 dir->d_left = dir->d_right = SENTINEL;
1191 dir->d_next = dir->d_prev = dir;
1195 /* ------------------ */
1196 static hash_val_t hash_fun_dir(const void *key)
1198 const struct dir *k = key;
1200 static unsigned long randbox[] = {
1201 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
1202 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
1203 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
1204 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
1207 const unsigned char *str = (unsigned char *)(k->d_u_name);
1208 hash_val_t acc = k->d_parent->d_did;
1211 acc ^= randbox[(*str + acc) & 0xf];
1212 acc = (acc << 1) | (acc >> 31);
1214 acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
1215 acc = (acc << 2) | (acc >> 30);
1222 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
1223 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
1224 #define get16bits(d) (*((const uint16_t *) (d)))
1227 #if !defined (get16bits)
1228 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
1229 +(uint32_t)(((const uint8_t *)(d))[0]) )
1232 static hash_val_t hash_fun2_dir(const void *key)
1234 const struct dir *k = key;
1235 const char *data = k->d_u_name;
1236 int len = strlen(k->d_u_name);
1237 hash_val_t hash = k->d_parent->d_did, tmp;
1243 for (;len > 0; len--) {
1244 hash += get16bits (data);
1245 tmp = (get16bits (data+2) << 11) ^ hash;
1246 hash = (hash << 16) ^ tmp;
1247 data += 2*sizeof (uint16_t);
1251 /* Handle end cases */
1253 case 3: hash += get16bits (data);
1255 hash ^= data[sizeof (uint16_t)] << 18;
1258 case 2: hash += get16bits (data);
1262 case 1: hash += *data;
1267 /* Force "avalanching" of final 127 bits */
1278 /* ---------------- */
1279 static int hash_comp_dir(const void *key1, const void *key2)
1281 const struct dir *k1 = key1;
1282 const struct dir *k2 = key2;
1284 return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
1287 /* ---------------- */
1291 return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
1294 /* ------------------ */
1295 static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
1298 movecwd failed some of dir path are not there anymore.
1299 FIXME Is it true with other errors?
1300 so we remove dir from the cache
1302 if (dir->d_did == DIRDID_ROOT_PARENT)
1304 if (afp_errno == AFPERR_ACCESS) {
1305 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1308 /* FIXME should we set these?, don't need to call stat() after:
1310 ret->st_errno = EACCES;
1312 ret->m_name = dir->d_m_name;
1313 ret->u_name = dir->d_u_name;
1316 } else if (afp_errno == AFPERR_NOOBJ) {
1317 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1320 strcpy(ret->m_name, dir->d_m_name);
1321 if (dir->d_m_name == dir->d_u_name) {
1322 ret->u_name = ret->m_name;
1325 size_t tp = strlen(ret->m_name)+1;
1327 ret->u_name = ret->m_name +tp;
1328 strcpy(ret->u_name, dir->d_u_name);
1330 /* FIXME should we set :
1332 ret->st_errno = ENOENT;
1334 dir_invalidate(vol, dir);
1337 dir_invalidate(vol, dir);
1341 /* -------------------------------------------------- */
1347 stat the file or errno
1350 curdir: filename parent directory
1356 stat the dir or errno
1360 curdir: dir parent directory
1368 curdir: dir parent directory
1375 cname(struct vol *vol, struct dir *dir, char **cpath)
1377 struct dir *cdir, *scdir=NULL;
1378 static char path[ MAXPATHLEN + 1];
1379 static struct path ret;
1391 afp_errno = AFPERR_NOOBJ;
1392 memset(&ret, 0, sizeof(ret));
1393 switch (ret.m_type = *data) { /* path type */
1396 len = (unsigned char) *data++;
1399 if (afp_version >= 30) {
1405 if (afp_version >= 30) {
1407 memcpy(&hint, data, sizeof(hint));
1409 data += sizeof(hint);
1411 memcpy(&len16, data, sizeof(len16));
1418 /* else it's an error */
1420 afp_errno = AFPERR_PARAM;
1423 *cpath += len + size;
1428 if (movecwd( vol, dir ) < 0 ) {
1429 return invalidate(vol, dir, &ret );
1431 if (*path == '\0') {
1438 if (*data == sep ) {
1442 while (*data == sep && len > 0 ) {
1443 if ( dir->d_parent == NULL ) {
1446 dir = dir->d_parent;
1451 /* would this be faster with strlen + strncpy? */
1453 while ( *data != sep && len > 0 ) {
1455 if (p > &path[ MAXPATHLEN]) {
1456 afp_errno = AFPERR_PARAM;
1462 /* short cut bits by chopping off a trailing \0. this also
1463 makes the traversal happy w/ filenames at the end of the
1470 if ( p == path ) { /* end of the name parameter */
1474 if (afp_version >= 30) {
1479 static char temp[ MAXPATHLEN + 1];
1481 if (dir->d_did == DIRDID_ROOT_PARENT) {
1483 With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
1484 So we compare it with the longname from the current volume and if they match
1485 we overwrite the requested path with the utf8 volume name so that the following
1488 ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
1489 if (strcasecmp( path, temp) == 0)
1490 ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
1493 if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
1494 afp_errno = AFPERR_PARAM;
1500 /* check for OS X mangled filename :( */
1502 t = demangle_osx(vol, path, dir->d_did, &fileid);
1505 /* duplicate work but we can't reuse all convert_char we did in demangle_osx
1506 * flags weren't the same
1508 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
1509 /* at last got our view of mac name */
1514 if (ret.u_name == NULL) {
1515 if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
1516 afp_errno = AFPERR_PARAM;
1522 cdir = dir->d_child;
1524 if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
1525 (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
1526 CH_UCS2, path, -1, (char **)&tmpname) )
1529 if (!cdir->d_m_name_ucs2) {
1530 LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
1531 /* this shouldn't happen !!!! */
1535 if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1538 if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1541 cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
1547 if (dir->d_did == DIRDID_ROOT_PARENT) {
1549 root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
1550 must check against the volume name.
1552 if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
1558 cdir = dirsearch_byname(vol, dir, ret.u_name);
1562 if (cdir == NULL && scdir != NULL) {
1564 /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
1567 if ( cdir == NULL ) {
1569 /* if dir == curdir it always succeed,
1570 even if curdir is deleted.
1571 it's not a pb because it will fail in extenddir
1573 if ( movecwd( vol, dir ) < 0 ) {
1574 /* dir is not valid anymore
1575 we delete dir from the cache and abort.
1577 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1578 afp_errno = AFPERR_NOOBJ;
1581 if (afp_errno == AFPERR_ACCESS)
1583 dir_invalidate(vol, dir);
1586 cdir = extenddir( vol, dir, &ret );
1590 cdir = extenddir( vol, dir, &ret );
1591 } /* if (!extend) */
1593 if ( cdir == NULL ) {
1595 if ( len > 0 || !ret.u_name ) {
1607 * Move curdir to dir, with a possible chdir()
1609 int movecwd(struct vol *vol, struct dir *dir)
1611 char path[MAXPATHLEN + 1];
1617 if ( dir == curdir ) {
1620 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1621 afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
1625 p = path + sizeof(path) - 1;
1628 for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
1631 /* parent directory is deleted */
1632 afp_errno = AFPERR_NOOBJ;
1636 if (p -n -1 < path) {
1637 afp_errno = AFPERR_PARAM;
1644 if ( d != curdir ) {
1645 n = strlen( vol->v_path );
1646 if (p -n -1 < path) {
1647 afp_errno = AFPERR_PARAM;
1652 memcpy( p, vol->v_path, n );
1654 if ( (ret = lchdir( p )) != 0 ) {
1655 LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
1658 /* p is a symlink */
1659 afp_errno = AFPERR_BADTYPE;
1665 afp_errno = AFPERR_ACCESS;
1668 afp_errno = AFPERR_NOOBJ;
1673 vol->v_curdir = curdir = dir;
1678 * We can't use unix file's perm to support Apple's inherited protection modes.
1679 * If we aren't the file's owner we can't change its perms when moving it and smb
1680 * nfs,... don't even try.
1682 #define AFP_CHECK_ACCESS
1684 int check_access(char *path, int mode)
1686 #ifdef AFP_CHECK_ACCESS
1694 accessmode(p, &ma, curdir, NULL);
1695 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1697 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1703 /* --------------------- */
1704 int file_access(struct path *path, int mode)
1708 accessmode(path->u_name, &ma, curdir, &path->st);
1709 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1711 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1717 /* --------------------- */
1718 void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
1720 dir->offcnt = count;
1721 dir->ctime = st->st_ctime;
1722 dir->d_flags &= ~DIRF_CNID;
1725 /* ---------------------
1726 * is our cached offspring count valid?
1729 static int diroffcnt(struct dir *dir, struct stat *st)
1731 return st->st_ctime == dir->ctime;
1734 /* ---------------------
1735 * is our cached also for reenumerate id?
1738 int dirreenumerate(struct dir *dir, struct stat *st)
1740 return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
1743 /* --------------------- */
1744 static int invisible_dots(const struct vol *vol, const char *name)
1746 return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
1749 /* ------------------------------
1751 (name, dir) with curdir:name == dir, from afp_enumerate
1754 int getdirparams(const struct vol *vol,
1755 u_int16_t bitmap, struct path *s_path,
1757 char *buf, size_t *buflen )
1761 char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
1762 int bit = 0, isad = 0;
1768 struct stat *st = &s_path->st;
1769 char *upath = s_path->u_name;
1771 if ((bitmap & ((1 << DIRPBIT_ATTR) |
1772 (1 << DIRPBIT_CDATE) |
1773 (1 << DIRPBIT_MDATE) |
1774 (1 << DIRPBIT_BDATE) |
1775 (1 << DIRPBIT_FINFO)))) {
1777 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1778 if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
1780 if (ad.ad_md->adf_flags & O_CREAT) {
1781 /* We just created it */
1782 ad_setname(&ad, s_path->m_name);
1787 dir->d_parent->d_did,
1794 if ( dir->d_did == DIRDID_ROOT) {
1795 pdid = DIRDID_ROOT_PARENT;
1796 } else if (dir->d_did == DIRDID_ROOT_PARENT) {
1799 pdid = dir->d_parent->d_did;
1803 while ( bitmap != 0 ) {
1804 while (( bitmap & 1 ) == 0 ) {
1812 ad_getattr(&ad, &ashort);
1813 } else if (invisible_dots(vol, dir->d_u_name)) {
1814 ashort = htons(ATTRBIT_INVISIBLE);
1817 ashort |= htons(ATTRBIT_SHARED);
1818 memcpy( data, &ashort, sizeof( ashort ));
1819 data += sizeof( ashort );
1823 memcpy( data, &pdid, sizeof( pdid ));
1824 data += sizeof( pdid );
1827 case DIRPBIT_CDATE :
1828 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1829 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1830 memcpy( data, &aint, sizeof( aint ));
1831 data += sizeof( aint );
1834 case DIRPBIT_MDATE :
1835 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1836 memcpy( data, &aint, sizeof( aint ));
1837 data += sizeof( aint );
1840 case DIRPBIT_BDATE :
1841 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
1842 aint = AD_DATE_START;
1843 memcpy( data, &aint, sizeof( aint ));
1844 data += sizeof( aint );
1847 case DIRPBIT_FINFO :
1849 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
1850 } else { /* no appledouble */
1851 memset( data, 0, 32 );
1852 /* set default view -- this also gets done in ad_open() */
1853 ashort = htons(FINDERINFO_CLOSEDVIEW);
1854 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
1856 /* dot files are by default visible */
1857 if (invisible_dots(vol, dir->d_u_name)) {
1858 ashort = htons(FINDERINFO_INVISIBLE);
1859 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
1865 case DIRPBIT_LNAME :
1866 if (dir->d_m_name) /* root of parent can have a null name */
1869 memset(data, 0, sizeof(u_int16_t));
1870 data += sizeof( u_int16_t );
1873 case DIRPBIT_SNAME :
1874 memset(data, 0, sizeof(u_int16_t));
1875 data += sizeof( u_int16_t );
1879 memcpy( data, &dir->d_did, sizeof( aint ));
1880 data += sizeof( aint );
1883 case DIRPBIT_OFFCNT :
1885 /* this needs to handle current directory access rights */
1886 if (diroffcnt(dir, st)) {
1887 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1889 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
1890 setdiroffcnt(dir, st, ret);
1891 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1893 ashort = htons( ashort );
1894 memcpy( data, &ashort, sizeof( ashort ));
1895 data += sizeof( ashort );
1899 aint = htonl(st->st_uid);
1900 memcpy( data, &aint, sizeof( aint ));
1901 data += sizeof( aint );
1905 aint = htonl(st->st_gid);
1906 memcpy( data, &aint, sizeof( aint ));
1907 data += sizeof( aint );
1910 case DIRPBIT_ACCESS :
1911 accessmode( upath, &ma, dir , st);
1913 *data++ = ma.ma_user;
1914 *data++ = ma.ma_world;
1915 *data++ = ma.ma_group;
1916 *data++ = ma.ma_owner;
1919 /* Client has requested the ProDOS information block.
1920 Just pass back the same basic block for all
1921 directories. <shirsch@ibm.net> */
1922 case DIRPBIT_PDINFO :
1923 if (afp_version >= 30) { /* UTF8 name */
1924 utf8 = kTextEncodingUTF8;
1925 if (dir->d_m_name) /* root of parent can have a null name */
1928 memset(data, 0, sizeof(u_int16_t));
1929 data += sizeof( u_int16_t );
1931 memcpy(data, &aint, sizeof( aint ));
1932 data += sizeof( aint );
1934 else { /* ProDOS Info Block */
1937 ashort = htons( 0x0200 );
1938 memcpy( data, &ashort, sizeof( ashort ));
1939 data += sizeof( ashort );
1940 memset( data, 0, sizeof( ashort ));
1941 data += sizeof( ashort );
1945 case DIRPBIT_UNIXPR :
1946 aint = htonl(st->st_uid);
1947 memcpy( data, &aint, sizeof( aint ));
1948 data += sizeof( aint );
1949 aint = htonl(st->st_gid);
1950 memcpy( data, &aint, sizeof( aint ));
1951 data += sizeof( aint );
1954 aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
1955 memcpy( data, &aint, sizeof( aint ));
1956 data += sizeof( aint );
1958 accessmode( upath, &ma, dir , st);
1960 *data++ = ma.ma_user;
1961 *data++ = ma.ma_world;
1962 *data++ = ma.ma_group;
1963 *data++ = ma.ma_owner;
1968 ad_close_metadata( &ad );
1970 return( AFPERR_BITMAP );
1976 ashort = htons( data - buf );
1977 memcpy( l_nameoff, &ashort, sizeof( ashort ));
1978 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, 0);
1980 if ( utf_nameoff ) {
1981 ashort = htons( data - buf );
1982 memcpy( utf_nameoff, &ashort, sizeof( ashort ));
1983 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, utf8);
1986 ad_close_metadata( &ad );
1988 *buflen = data - buf;
1992 /* ----------------------------- */
1993 int path_error(struct path *path, int error)
1995 /* - a dir with access error
1996 * - no error it's a file
1999 if (path_isadir(path))
2001 if (path->st_valid && path->st_errno)
2003 return AFPERR_BADTYPE ;
2006 /* ----------------------------- */
2007 int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2012 u_int16_t vid, bitmap;
2018 memcpy( &vid, ibuf, sizeof( vid ));
2019 ibuf += sizeof( vid );
2021 if (NULL == ( vol = getvolbyvid( vid )) ) {
2022 return( AFPERR_PARAM );
2025 if (vol->v_flags & AFPVOL_RO)
2026 return AFPERR_VLOCK;
2028 memcpy( &did, ibuf, sizeof( did ));
2029 ibuf += sizeof( int );
2031 if (NULL == ( dir = dirlookup( vol, did )) ) {
2035 memcpy( &bitmap, ibuf, sizeof( bitmap ));
2036 bitmap = ntohs( bitmap );
2037 ibuf += sizeof( bitmap );
2039 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
2040 return get_afp_errno(AFPERR_NOOBJ);
2043 if ( *path->m_name != '\0' ) {
2044 rc = path_error(path, AFPERR_NOOBJ);
2045 /* maybe we are trying to set perms back */
2046 if (rc != AFPERR_ACCESS)
2051 * If ibuf is odd, make it even.
2053 if ((u_long)ibuf & 1 ) {
2057 if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
2058 setvoltime(obj, vol );
2064 * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
2066 * assume path == '\0' eg. it's a directory in canonical form
2069 struct path Cur_Path = {
2072 ".", /* unix name */
2074 NULL,/* struct dir */
2075 0, /* stat is not set */
2078 /* ------------------ */
2079 static int set_dir_errors(struct path *path, const char *where, int err)
2084 return AFPERR_ACCESS;
2086 return AFPERR_VLOCK;
2088 LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
2089 return AFPERR_PARAM;
2092 /* ------------------ */
2093 int setdirparams(struct vol *vol,
2094 struct path *path, u_int16_t d_bitmap, char *buf )
2106 u_int16_t ashort, bshort, oshort;
2108 int change_mdate = 0;
2109 int change_parent_mdate = 0;
2111 u_int16_t bitmap = d_bitmap;
2112 u_char finder_buf[32];
2115 u_int16_t upriv_bit = 0;
2118 upath = path->u_name;
2120 while ( bitmap != 0 ) {
2121 while (( bitmap & 1 ) == 0 ) {
2129 memcpy( &ashort, buf, sizeof( ashort ));
2130 buf += sizeof( ashort );
2132 case DIRPBIT_CDATE :
2134 memcpy(&cdate, buf, sizeof(cdate));
2135 buf += sizeof( cdate );
2137 case DIRPBIT_MDATE :
2138 memcpy(&newdate, buf, sizeof(newdate));
2139 buf += sizeof( newdate );
2141 case DIRPBIT_BDATE :
2143 memcpy(&bdate, buf, sizeof(bdate));
2144 buf += sizeof( bdate );
2146 case DIRPBIT_FINFO :
2148 memcpy( finder_buf, buf, 32 );
2151 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2152 change_parent_mdate = 1;
2153 memcpy( &owner, buf, sizeof(owner));
2154 buf += sizeof( owner );
2157 change_parent_mdate = 1;
2158 memcpy( &group, buf, sizeof( group ));
2159 buf += sizeof( group );
2161 case DIRPBIT_ACCESS :
2163 change_parent_mdate = 1;
2164 ma.ma_user = *buf++;
2165 ma.ma_world = *buf++;
2166 ma.ma_group = *buf++;
2167 ma.ma_owner = *buf++;
2168 mpriv = mtoumode( &ma ) | vol->v_dperm;
2169 if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2170 err = set_dir_errors(path, "setdirmode", errno);
2174 /* Ignore what the client thinks we should do to the
2175 ProDOS information block. Skip over the data and
2176 report nothing amiss. <shirsch@ibm.net> */
2177 case DIRPBIT_PDINFO :
2178 if (afp_version < 30) {
2182 err = AFPERR_BITMAP;
2186 case DIRPBIT_UNIXPR :
2187 if (vol_unix_priv(vol)) {
2188 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
2189 buf += sizeof( owner );
2190 memcpy( &group, buf, sizeof( group ));
2191 buf += sizeof( group );
2194 change_parent_mdate = 1;
2195 memcpy( &upriv, buf, sizeof( upriv ));
2196 buf += sizeof( upriv );
2197 upriv = ntohl (upriv) | vol->v_dperm;
2198 if (dir_rx_set(upriv)) {
2199 /* maybe we are trying to set perms back */
2200 if ( setdirunixmode(vol, upath, upriv) < 0 ) {
2202 err = set_dir_errors(path, "setdirunixmode", errno);
2213 err = AFPERR_BITMAP;
2221 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2223 if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
2225 * Check to see what we're trying to set. If it's anything
2226 * but ACCESS, UID, or GID, give an error. If it's any of those
2227 * three, we don't need the ad to be open, so just continue.
2229 * note: we also don't need to worry about mdate. also, be quiet
2230 * if we're using the noadouble option.
2232 if (!vol_noadouble(vol) && (d_bitmap &
2233 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
2234 (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
2235 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
2236 return AFPERR_ACCESS;
2242 * Check to see if a create was necessary. If it was, we'll want
2243 * to set our name, etc.
2245 if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
2246 ad_setname(&ad, curdir->d_m_name);
2252 while ( bitmap != 0 ) {
2253 while (( bitmap & 1 ) == 0 ) {
2261 ad_getattr(&ad, &bshort);
2263 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
2264 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
2268 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
2269 change_parent_mdate = 1;
2270 ad_setattr(&ad, bshort);
2273 case DIRPBIT_CDATE :
2275 ad_setdate(&ad, AD_DATE_CREATE, cdate);
2278 case DIRPBIT_MDATE :
2280 case DIRPBIT_BDATE :
2282 ad_setdate(&ad, AD_DATE_BACKUP, bdate);
2285 case DIRPBIT_FINFO :
2287 /* Fixes #2802236 */
2288 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
2289 *fflags &= htons(~FINDERINFO_ISHARED);
2291 if ( dir->d_did == DIRDID_ROOT ) {
2293 * Alright, we admit it, this is *really* sick!
2294 * The 4 bytes that we don't copy, when we're dealing
2295 * with the root of a volume, are the directory's
2296 * location information. This eliminates that annoying
2297 * behavior one sees when mounting above another mount
2300 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
2301 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
2303 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
2307 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2308 if ( (dir->d_did == DIRDID_ROOT) &&
2309 (setdeskowner( ntohl(owner), -1 ) < 0)) {
2310 err = set_dir_errors(path, "setdeskowner", errno);
2311 if (isad && err == AFPERR_PARAM) {
2312 err = AFP_OK; /* ???*/
2315 goto setdirparam_done;
2318 if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
2319 err = set_dir_errors(path, "setdirowner", errno);
2320 goto setdirparam_done;
2324 if (dir->d_did == DIRDID_ROOT)
2325 setdeskowner( -1, ntohl(group) );
2326 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2327 err = set_dir_errors(path, "setdirowner", errno);
2328 goto setdirparam_done;
2331 case DIRPBIT_ACCESS :
2332 if (dir->d_did == DIRDID_ROOT) {
2334 if (!dir_rx_set(mpriv)) {
2335 /* we can't remove read and search for owner on volume root */
2336 err = AFPERR_ACCESS;
2337 goto setdirparam_done;
2341 if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2342 err = set_dir_errors(path, "setdirmode", errno);
2343 goto setdirparam_done;
2346 case DIRPBIT_PDINFO :
2347 if (afp_version >= 30) {
2348 err = AFPERR_BITMAP;
2349 goto setdirparam_done;
2352 case DIRPBIT_UNIXPR :
2353 if (vol_unix_priv(vol)) {
2354 if (dir->d_did == DIRDID_ROOT) {
2355 if (!dir_rx_set(upriv)) {
2356 /* we can't remove read and search for owner on volume root */
2357 err = AFPERR_ACCESS;
2358 goto setdirparam_done;
2360 setdeskowner( -1, ntohl(group) );
2361 setdeskmode( upriv );
2363 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2364 err = set_dir_errors(path, "setdirowner", errno);
2365 goto setdirparam_done;
2368 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
2369 err = set_dir_errors(path, "setdirunixmode", errno);
2370 goto setdirparam_done;
2374 err = AFPERR_BITMAP;
2375 goto setdirparam_done;
2379 err = AFPERR_BITMAP;
2380 goto setdirparam_done;
2389 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
2390 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2394 ad_setdate(&ad, AD_DATE_MODIFY, newdate);
2395 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
2400 if (path->st_valid && !path->st_errno) {
2401 struct stat *st = &path->st;
2403 if (dir && dir->d_parent) {
2404 ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_parent->d_did, vol->v_stamp);
2408 ad_close_metadata( &ad);
2411 if (change_parent_mdate && dir->d_did != DIRDID_ROOT
2412 && gettimeofday(&tv, NULL) == 0) {
2413 if (!movecwd(vol, dir->d_parent)) {
2414 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2415 /* be careful with bitmap because now dir is null */
2416 bitmap = 1<<DIRPBIT_MDATE;
2417 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
2418 /* should we reset curdir ?*/
2425 int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2439 memcpy( &vid, ibuf, sizeof( vid ));
2440 ibuf += sizeof( vid );
2441 if (NULL == (vol = getvolbyvid( vid )) ) {
2442 return( AFPERR_PARAM );
2445 memcpy( &did, ibuf, sizeof( did ));
2446 ibuf += sizeof( did );
2450 * if it's CNID 2 our only choice to meet the specs is call sync.
2451 * For any other CNID just sync that dir. To my knowledge the
2452 * intended use of FPSyncDir is to sync the volume so all we're
2453 * ever going to see here is probably CNID 2. Anyway, we' prepared.
2456 if ( ntohl(did) == 2 ) {
2459 if (NULL == ( dir = dirlookup( vol, did )) ) {
2460 return afp_errno; /* was AFPERR_NOOBJ */
2463 if (movecwd( vol, dir ) < 0 )
2464 return ( AFPERR_NOOBJ );
2467 * Assuming only OSens that have dirfd also may require fsyncing directories
2468 * in order to flush metadata e.g. Linux.
2472 if (NULL == ( dp = opendir( "." )) ) {
2475 return( AFPERR_NOOBJ );
2477 return( AFPERR_ACCESS );
2479 return( AFPERR_PARAM );
2483 LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
2486 if ( fsync ( dfd ) < 0 )
2487 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2488 dir->d_u_name, strerror(errno) );
2489 closedir(dp); /* closes dfd too */
2492 if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
2495 return( AFPERR_NOOBJ );
2497 return( AFPERR_ACCESS );
2499 return( AFPERR_PARAM );
2503 LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
2504 vol->ad_path(".", ADFLAGS_DIR) );
2506 if ( fsync(dfd) < 0 )
2507 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2508 vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
2515 int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2521 struct path *s_path;
2529 memcpy( &vid, ibuf, sizeof( vid ));
2530 ibuf += sizeof( vid );
2531 if (NULL == ( vol = getvolbyvid( vid )) ) {
2532 return( AFPERR_PARAM );
2535 if (vol->v_flags & AFPVOL_RO)
2536 return AFPERR_VLOCK;
2538 memcpy( &did, ibuf, sizeof( did ));
2539 ibuf += sizeof( did );
2540 if (NULL == ( dir = dirlookup( vol, did )) ) {
2541 return afp_errno; /* was AFPERR_NOOBJ */
2543 /* for concurrent access we need to be sure we are not in the
2544 * folder we want to create...
2548 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
2549 return get_afp_errno(AFPERR_PARAM);
2551 /* cname was able to move curdir to it! */
2552 if (*s_path->m_name == '\0')
2553 return AFPERR_EXIST;
2555 upath = s_path->u_name;
2557 if (AFP_OK != (err = netatalk_mkdir( upath))) {
2561 if (of_stat(s_path) < 0) {
2565 if ((dir = adddir( vol, curdir, s_path)) == NULL) {
2569 if ( movecwd( vol, dir ) < 0 ) {
2570 return( AFPERR_PARAM );
2573 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2574 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
2575 if (vol_noadouble(vol))
2576 goto createdir_done;
2577 return( AFPERR_ACCESS );
2579 ad_setname(&ad, s_path->m_name);
2580 ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
2583 ad_close_metadata( &ad);
2586 #ifdef HAVE_NFSv4_ACLS
2587 /* FIXME: are we really inside the created dir? */
2588 addir_inherit_acl(vol);
2591 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
2592 *rbuflen = sizeof( u_int32_t );
2593 setvoltime(obj, vol );
2598 * dst new unix filename (not a pathname)
2599 * newname new mac name
2603 int renamedir(const struct vol *vol, char *src, char *dst,
2605 struct dir *newparent,
2613 /* existence check moved to afp_moveandrename */
2614 if ( unix_rename( src, dst ) < 0 ) {
2617 return( AFPERR_NOOBJ );
2619 return( AFPERR_ACCESS );
2621 return AFPERR_VLOCK;
2623 /* tried to move directory into a subdirectory of itself */
2624 return AFPERR_CANTMOVE;
2626 /* this needs to copy and delete. bleah. that means we have
2627 * to deal with entire directory hierarchies. */
2628 if ((err = copydir(vol, src, dst)) < 0) {
2632 if ((err = deletedir(src)) < 0)
2636 return( AFPERR_PARAM );
2640 vol->vfs->vfs_renamedir(vol, src, dst);
2642 len = strlen( newname );
2643 /* rename() succeeded so we need to update our tree even if we can't open
2647 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2649 if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
2650 ad_setname(&ad, newname);
2652 ad_close_metadata( &ad);
2655 dir_hash_del(vol, dir);
2656 if (dir->d_m_name == dir->d_u_name)
2657 dir->d_u_name = NULL;
2659 if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
2660 LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
2661 /* FIXME : fatal ? */
2664 dir->d_m_name = buf;
2665 strcpy( dir->d_m_name, newname );
2667 if (newname == dst) {
2668 free(dir->d_u_name);
2669 dir->d_u_name = dir->d_m_name;
2672 if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
2673 LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
2676 dir->d_u_name = buf;
2677 strcpy( dir->d_u_name, dst );
2680 if (dir->d_m_name_ucs2)
2681 free(dir->d_m_name_ucs2);
2683 dir->d_m_name_ucs2 = NULL;
2684 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))
2685 dir->d_m_name_ucs2 = NULL;
2687 if (( parent = dir->d_parent ) == NULL ) {
2690 if ( parent == newparent ) {
2691 hash_alloc_insert(vol->v_hash, dir, dir);
2695 /* detach from old parent and add to new one. */
2696 dirchildremove(parent, dir);
2697 dir->d_parent = newparent;
2698 dirchildadd(vol, newparent, dir);
2702 /* delete an empty directory */
2703 int deletecurdir(struct vol *vol)
2713 if ( curdir->d_parent == NULL ) {
2714 return( AFPERR_ACCESS );
2719 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2720 /* we never want to create a resource fork here, we are going to delete it */
2721 if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
2723 ad_getattr(&ad, &ashort);
2724 ad_close( &ad, ADFLAGS_HF );
2725 if ((ashort & htons(ATTRBIT_NODELETE))) {
2726 return AFPERR_OLOCK;
2729 err = vol->vfs->vfs_deletecurdir(vol);
2734 /* now get rid of dangling symlinks */
2735 if ((dp = opendir("."))) {
2736 while ((de = readdir(dp))) {
2737 /* skip this and previous directory */
2738 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2741 /* bail if it's not a symlink */
2742 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
2744 return AFPERR_DIRNEMPT;
2747 if ((err = netatalk_unlink(de->d_name))) {
2754 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
2759 err = netatalk_rmdir_all_errors(fdir->d_u_name);
2760 if ( err == AFP_OK || err == AFPERR_NOOBJ) {
2761 dirchildremove(curdir, fdir);
2762 cnid_delete(vol->v_cdb, fdir->d_did);
2763 dir_remove( vol, fdir );
2767 /* inode is used as key for cnid.
2768 * Close the descriptor only after cnid_delete
2776 int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2786 sfunc = (unsigned char) *ibuf++;
2790 if (sfunc >= 3 && sfunc <= 6) {
2791 if (afp_version < 30) {
2792 return( AFPERR_PARAM );
2799 case 3 :/* unicode */
2800 memcpy( &id, ibuf, sizeof( id ));
2803 if (( pw = getpwuid( id )) == NULL ) {
2804 return( AFPERR_NOITEM );
2806 len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
2807 pw->pw_name, -1, &name);
2814 case 4 : /* unicode */
2815 memcpy( &id, ibuf, sizeof( id ));
2818 if (NULL == ( gr = (struct group *)getgrgid( id ))) {
2819 return( AFPERR_NOITEM );
2821 len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
2822 gr->gr_name, -1, &name);
2828 #ifdef HAVE_NFSv4_ACLS
2829 case 5 : /* UUID -> username */
2830 case 6 : /* UUID -> groupname */
2831 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2832 return AFPERR_PARAM;
2833 LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
2835 len = getnamefromuuid( ibuf, &name, &type);
2836 if (len != 0) /* its a error code, not len */
2837 return AFPERR_NOITEM;
2838 if (type == UUID_USER) {
2839 if (( pw = getpwnam( name )) == NULL )
2840 return( AFPERR_NOITEM );
2841 LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
2842 id = htonl(UUID_USER);
2843 memcpy( rbuf, &id, sizeof( id ));
2844 id = htonl( pw->pw_uid);
2845 rbuf += sizeof( id );
2846 memcpy( rbuf, &id, sizeof( id ));
2847 rbuf += sizeof( id );
2848 *rbuflen = 2 * sizeof( id );
2849 } else { /* type == UUID_GROUP */
2850 if (( gr = getgrnam( name )) == NULL )
2851 return( AFPERR_NOITEM );
2852 LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
2853 id = htonl(UUID_GROUP);
2854 memcpy( rbuf, &id, sizeof( id ));
2855 rbuf += sizeof( id );
2856 id = htonl( gr->gr_gid);
2857 memcpy( rbuf, &id, sizeof( id ));
2858 rbuf += sizeof( id );
2859 *rbuflen = 2 * sizeof( id );
2864 return( AFPERR_PARAM );
2868 len = strlen( name );
2871 u_int16_t tp = htons(len);
2872 memcpy(rbuf, &tp, sizeof(tp));
2881 memcpy( rbuf, name, len );
2889 int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2898 sfunc = (unsigned char) *ibuf++;
2900 LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
2903 case 2 : /* unicode */
2904 if (afp_version < 30) {
2905 return( AFPERR_PARAM );
2907 memcpy(&ulen, ibuf, sizeof(ulen));
2910 LOG(log_debug, logtype_afpd, "afp_mapname: alive");
2914 len = (unsigned char) *ibuf++;
2916 #ifdef HAVE_NFSv4_ACLS
2917 case 5 : /* username -> UUID */
2918 case 6 : /* groupname -> UUID */
2919 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2920 return AFPERR_PARAM;
2921 memcpy(&ulen, ibuf, sizeof(ulen));
2927 return( AFPERR_PARAM );
2933 return AFPERR_PARAM;
2936 case 1 : /* unicode */
2938 if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) {
2939 return( AFPERR_NOITEM );
2943 memcpy( rbuf, &id, sizeof( id ));
2944 *rbuflen = sizeof( id );
2947 case 2 : /* unicode */
2949 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
2950 if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
2951 return( AFPERR_NOITEM );
2954 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
2956 memcpy( rbuf, &id, sizeof( id ));
2957 *rbuflen = sizeof( id );
2959 #ifdef HAVE_NFSv4_ACLS
2960 case 5 : /* username -> UUID */
2961 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2962 if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
2963 return AFPERR_NOITEM;
2964 *rbuflen = UUID_BINSIZE;
2966 case 6 : /* groupname -> UUID */
2967 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2968 if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
2969 return AFPERR_NOITEM;
2970 *rbuflen = UUID_BINSIZE;
2978 /* ------------------------------------
2979 variable DID support
2981 int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2992 /* do nothing as dids are static for the life of the process. */
2996 memcpy(&vid, ibuf, sizeof( vid ));
2997 ibuf += sizeof( vid );
2998 if (( vol = getvolbyvid( vid )) == NULL ) {
2999 return( AFPERR_PARAM );
3002 memcpy( &did, ibuf, sizeof( did ));
3003 ibuf += sizeof( did );
3004 if (( dir = dirlookup( vol, did )) == NULL ) {
3005 return( AFPERR_PARAM );
3008 /* dir_remove -- deletedid */
3014 /* did creation gets done automatically
3015 * there's a pb again with case but move it to cname
3017 int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
3020 struct dir *parentdir;
3028 memcpy(&vid, ibuf, sizeof(vid));
3029 ibuf += sizeof( vid );
3031 if (NULL == ( vol = getvolbyvid( vid )) ) {
3032 return( AFPERR_PARAM );
3035 memcpy(&did, ibuf, sizeof(did));
3036 ibuf += sizeof(did);
3038 if (NULL == ( parentdir = dirlookup( vol, did )) ) {
3042 if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
3043 return get_afp_errno(AFPERR_PARAM);
3046 if ( *path->m_name != '\0' ) {
3047 return path_error(path, AFPERR_NOOBJ);
3050 if ( !path->st_valid && of_stat(path ) < 0 ) {
3051 return( AFPERR_NOOBJ );
3053 if ( path->st_errno ) {
3054 return( AFPERR_NOOBJ );
3057 memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did));
3058 *rbuflen = sizeof(curdir->d_did);