2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
5 * 19 jan 2000 implemented red-black trees for directory lookups
11 #endif /* HAVE_CONFIG_H */
16 #else /* STDC_HEADERS */
20 #endif /* HAVE_STRCHR */
21 char *strchr (), *strrchr ();
23 #define memcpy(d,s,n) bcopy ((s), (d), (n))
24 #define memmove(d,s,n) bcopy ((s), (d), (n))
25 #endif /* ! HAVE_MEMCPY */
26 #endif /* STDC_HEADERS */
35 #include <sys/param.h>
39 #include <atalk/adouble.h>
40 #include <atalk/vfs.h>
41 #include <atalk/afp.h>
42 #include <atalk/util.h>
43 #include <atalk/cnid.h>
44 #include <atalk/logger.h>
45 #include <atalk/uuid.h>
46 #include <atalk/unix.h>
48 #include "directory.h"
59 #ifdef HAVE_NFSv4_ACLS
60 extern void addir_inherit_acl(const struct vol *vol);
67 * There are currently two cache structures where afpd caches directory information
68 * a) a DID/dirname cache in a hashtable
69 * b) a (red-black) tree with CNIDs as key
71 * a) is for searching by DID/dirname
72 * b) is for searching by CNID
74 * Through additional parent, child, previous and next pointers, b) is also used to
75 * represent the on-disk layout of the filesystem. parent and child point to parent
76 * and child directory respectively, linking 2 or more subdirectories in one
77 * directory with previous and next pointers.
79 * Usage examples, highlighting the main functions:
81 * a) is eg used in enumerate():
83 * dir = dirsearch_byname() // search in cache
84 * if (dir == NULL) // not found
85 * dir = adddir() // add to cache
88 * b) is eg used in afp_getfildirparams()
89 * dirlookup() // wrapper for cache and db search
90 * => dir = dirsearch() // search in cache
94 * cnid_resolve() // resolve with CNID database
95 * cname() // add to cache
101 #define SENTINEL (&sentinel)
102 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, /* left, right, back */
103 DIRTREE_COLOR_BLACK, /* color */
104 NULL, NULL, /* parent, child */
105 NULL, NULL, /* previous, next */
106 NULL, 0, 0, /* oforks, did, flags */
107 0, 0, /* ctime, offcnt */
108 NULL, NULL, NULL}; /* mname, uname, ucs2-name */
109 static struct dir rootpar = { SENTINEL, SENTINEL, NULL,
117 /* (from IM: Toolbox Essentials)
118 * dirFinderInfo (DInfo) fields:
120 * frRect 8 folder's window rectangle
122 * frLocation 4 folder's location in window
123 * frView 2 folder's view (default == closedView (256))
125 * extended dirFinderInfo (DXInfo) fields:
126 * frScroll 4 scroll position
127 * frOpenChain: 4 directory ID chain of open folders
128 * frScript: 1 script flag and code
129 * frXFlags: 1 reserved
130 * frComment: 2 comment ID
131 * frPutAway: 4 home directory ID
135 vol_tree_root(const struct vol *vol, u_int32_t did)
139 if (vol->v_curdir && vol->v_curdir->d_did == did) {
149 * redid did assignment for directories. now we use red-black trees.
153 dirsearch(const struct vol *vol, u_int32_t did)
158 /* check for 0 did */
160 afp_errno = AFPERR_PARAM;
163 if ( did == DIRDID_ROOT_PARENT ) {
165 rootpar.d_did = DIRDID_ROOT_PARENT;
166 rootpar.d_child = vol->v_dir;
170 dir = vol_tree_root(vol, did);
172 afp_errno = AFPERR_NOOBJ;
173 while ( dir != SENTINEL ) {
174 if (dir->d_did == did)
175 return dir->d_m_name ? dir : NULL;
176 dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
181 /* ------------------- */
182 int get_afp_errno(const int param)
184 if (afp_errno != AFPERR_DID1)
189 /* ------------------- */
191 dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
193 struct dir *dir = NULL;
195 if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
201 hn = hash_lookup(vol->v_hash, &key);
209 /* -----------------------------------------
210 * if did is not in the cache resolve it with cnid
213 * OSX call it with bogus id, ie file ID not folder ID,
214 * and we are really bad in this case.
217 dirlookup( struct vol *vol, u_int32_t did)
222 static char path[MAXPATHLEN + 1];
225 static char buffer[12 + MAXPATHLEN + 1];
226 int buflen = 12 + MAXPATHLEN + 1;
231 ret = dirsearch(vol, did);
232 if (ret != NULL || afp_errno == AFPERR_PARAM)
235 utf8 = utf8_encoding();
236 maxpath = (utf8)?MAXPATHLEN -7:255;
238 if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
239 afp_errno = AFPERR_NOOBJ;
242 ptr = path + MAXPATHLEN;
243 if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
244 afp_errno = AFPERR_NOOBJ;
248 pathlen = len; /* no 0 in the last part */
250 strcpy(ptr - len, mpath);
253 ret = dirsearch(vol,id);
258 if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
260 NULL == (mpath = utompath(vol, upath, cnid, utf8))
262 afp_errno = AFPERR_NOOBJ;
266 len = strlen(mpath) + 1;
268 if (pathlen > maxpath) {
269 afp_errno = AFPERR_PARAM;
272 strcpy(ptr - len, mpath);
276 /* fill the cache, another place where we know about the path type */
282 temp16 = htons(pathlen);
283 memcpy(ptr, &temp16, sizeof(temp16));
285 temp = htonl(kTextEncodingUTF8);
287 memcpy(ptr, &temp, sizeof(temp));
293 *ptr = (unsigned char)pathlen;
297 /* cname is not efficient */
298 if (cname( vol, ret, &ptr ) == NULL )
301 return dirsearch(vol, did);
304 /* child addition/removal */
305 static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
310 b->d_next = a->d_child;
311 b->d_prev = b->d_next->d_prev;
312 b->d_next->d_prev = b;
313 b->d_prev->d_next = b;
315 if (!hash_alloc_insert(vol->v_hash, b, b)) {
316 LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
320 static void dirchildremove(struct dir *a,struct dir *b)
323 a->d_child = (b == b->d_next) ? NULL : b->d_next;
324 b->d_next->d_prev = b->d_prev;
325 b->d_prev->d_next = b->d_next;
326 b->d_next = b->d_prev = b;
329 /* --------------------------- */
330 /* rotate the tree to the left */
331 static void dir_leftrotate(struct vol *vol, struct dir *dir)
333 struct dir *right = dir->d_right;
335 /* whee. move the right's left tree into dir's right tree */
336 dir->d_right = right->d_left;
337 if (right->d_left != SENTINEL)
338 right->d_left->d_back = dir;
340 if (right != SENTINEL) {
341 right->d_back = dir->d_back;
345 if (!dir->d_back) /* no parent. move the right tree to the top. */
347 else if (dir == dir->d_back->d_left) /* we were on the left */
348 dir->d_back->d_left = right;
350 dir->d_back->d_right = right; /* we were on the right */
352 /* re-insert dir on the left tree */
359 /* rotate the tree to the right */
360 static void dir_rightrotate(struct vol *vol, struct dir *dir)
362 struct dir *left = dir->d_left;
364 /* whee. move the left's right tree into dir's left tree */
365 dir->d_left = left->d_right;
366 if (left->d_right != SENTINEL)
367 left->d_right->d_back = dir;
369 if (left != SENTINEL) {
370 left->d_back = dir->d_back;
374 if (!dir->d_back) /* no parent. move the left tree to the top. */
376 else if (dir == dir->d_back->d_right) /* we were on the right */
377 dir->d_back->d_right = left;
379 dir->d_back->d_left = left; /* we were on the left */
381 /* re-insert dir on the right tree */
387 /* recolor after a removal */
388 static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
392 while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
393 /* are we on the left tree? */
394 if (dir == dir->d_back->d_left) {
395 leaf = dir->d_back->d_right; /* get right side */
396 if (leaf->d_color == DIRTREE_COLOR_RED) {
397 /* we're red. we need to change to black. */
398 leaf->d_color = DIRTREE_COLOR_BLACK;
399 dir->d_back->d_color = DIRTREE_COLOR_RED;
400 dir_leftrotate(vol, dir->d_back);
401 leaf = dir->d_back->d_right;
404 /* right leaf has black end nodes */
405 if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
406 (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
407 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
408 dir = dir->d_back; /* ascend */
410 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
411 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
412 leaf->d_color = DIRTREE_COLOR_RED;
413 dir_rightrotate(vol, leaf);
414 leaf = dir->d_back->d_right;
416 leaf->d_color = dir->d_back->d_color;
417 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
418 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
419 dir_leftrotate(vol, dir->d_back);
422 } else { /* right tree */
423 leaf = dir->d_back->d_left; /* left tree */
424 if (leaf->d_color == DIRTREE_COLOR_RED) {
425 leaf->d_color = DIRTREE_COLOR_BLACK;
426 dir->d_back->d_color = DIRTREE_COLOR_RED;
427 dir_rightrotate(vol, dir->d_back);
428 leaf = dir->d_back->d_left;
431 /* left leaf has black end nodes */
432 if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
433 (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
434 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
435 dir = dir->d_back; /* ascend */
437 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
438 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
439 leaf->d_color = DIRTREE_COLOR_RED;
440 dir_leftrotate(vol, leaf);
441 leaf = dir->d_back->d_left;
443 leaf->d_color = dir->d_back->d_color;
444 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
445 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
446 dir_rightrotate(vol, dir->d_back);
451 dir->d_color = DIRTREE_COLOR_BLACK;
457 /* --------------------- */
458 static void dir_hash_del(const struct vol *vol, struct dir *dir)
462 hn = hash_lookup(vol->v_hash, dir);
464 LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
467 hash_delete(vol->v_hash, hn);
471 /* remove the node from the tree. this is just like insertion, but
472 * different. actually, it has to worry about a bunch of things that
473 * insertion doesn't care about. */
475 static void dir_remove( struct vol *vol, struct dir *dir)
478 struct ofork *of, *last;
479 struct dir *node, *leaf;
480 #endif /* REMOVE_NODES */
482 if (!dir || (dir == SENTINEL))
485 /* i'm not sure if it really helps to delete stuff. */
486 dir_hash_del(vol, dir);
487 vol->v_curdir = NULL;
490 dir->d_m_name = NULL;
491 dir->d_u_name = NULL;
492 dir->d_m_name_ucs2 = NULL;
493 #else /* ! REMOVE_NODES */
495 /* go searching for a node with at most one child */
496 if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
500 while (node->d_left != SENTINEL)
505 leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
508 leaf->d_back = node->d_back;
511 } else if (node == node->d_back->d_left) { /* left tree */
512 node->d_back->d_left = leaf;
514 node->d_back->d_right = leaf;
517 /* we want to free node, but we also want to free the data in dir.
518 * currently, that's d_name and the directory traversal bits.
519 * we just copy the necessary bits and then fix up all the
520 * various pointers to the directory. needless to say, there are
521 * a bunch of places that store the directory struct. */
523 struct dir save, *tmp;
525 memcpy(&save, dir, sizeof(save));
526 memcpy(dir, node, sizeof(struct dir));
528 /* restore the red-black bits */
529 dir->d_left = save.d_left;
530 dir->d_right = save.d_right;
531 dir->d_back = save.d_back;
532 dir->d_color = save.d_color;
534 if (node == vol->v_dir) {/* we may need to fix up this pointer */
536 rootpar.d_child = vol->v_dir;
538 /* if we aren't the root directory, we have parents and
539 * siblings to worry about */
540 if (dir->d_parent->d_child == node)
541 dir->d_parent->d_child = dir;
542 dir->d_next->d_prev = dir;
543 dir->d_prev->d_next = dir;
546 /* fix up children. */
550 tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
553 if (node == curdir) /* another pointer to fixup */
556 /* we also need to fix up oforks. bleah */
557 if ((of = dir->d_ofork)) {
558 last = of->of_d_prev;
561 of = (last == of) ? NULL : of->of_d_next;
565 /* set the node's d_name */
566 node->d_m_name = save.d_m_name;
567 node->d_u_name = save.d_u_name;
568 node->d_m_name_ucs2 = save.d_m_name_ucs2;
571 if (node->d_color == DIRTREE_COLOR_BLACK)
572 dir_rmrecolor(vol, leaf);
574 if (node->d_m_name_ucs2)
575 free(node->d_u_name_ucs2);
576 if (node->d_u_name != node->d_m_name) {
577 free(node->d_u_name);
579 free(node->d_m_name);
581 #endif /* ! REMOVE_NODES */
584 /* ---------------------------------------
585 * remove the node and its childs from the tree
587 * FIXME what about opened forks with refs to it?
588 * it's an afp specs violation because you can't delete
589 * an opened forks. Now afpd doesn't care about forks opened by other
590 * process. It's fixable within afpd if fnctl_lock, doable with smb and
591 * next to impossible for nfs and local filesystem access.
593 static void dir_invalidate( struct vol *vol, struct dir *dir)
596 /* v_root can't be deleted */
597 if (movecwd(vol, vol->v_root) < 0) {
598 LOG(log_error, logtype_afpd, "cname can't chdir to : %s", vol->v_root);
602 dirchildremove(dir->d_parent, dir);
603 dir_remove( vol, dir );
606 /* ------------------------------------ */
607 static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
611 pdir = vol_tree_root(vol, dir->d_did);
612 while (pdir->d_did != dir->d_did ) {
613 if ( pdir->d_did > dir->d_did ) {
614 if ( pdir->d_left == SENTINEL ) {
621 if ( pdir->d_right == SENTINEL ) {
626 pdir = pdir->d_right;
632 #define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/"
635 caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
640 static u_int32_t did = 0;
641 static char cname[MAXPATHLEN];
642 static char lname[MAXPATHLEN];
643 ucs2_t u2_path[MAXPATHLEN];
644 ucs2_t u2_dename[MAXPATHLEN];
645 char *tmp, *savepath;
647 if (!(vol->v_flags & AFPVOL_CASEINSEN))
650 if (veto_file(ENUMVETO, path->u_name))
653 savepath = path->u_name;
655 /* very simple cache */
656 if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
657 path->u_name = cname;
659 if (of_stat( path ) == 0 ) {
662 /* something changed, we cannot stat ... */
666 if (NULL == ( dp = opendir( "." )) ) {
667 LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name);
672 /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
673 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) )
674 LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
676 /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
678 for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
679 if (NULL == check_dirent(vol, de->d_name))
682 if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) )
685 if (strcasecmp_w( u2_path, u2_dename) == 0) {
687 strlcpy(cname, de->d_name, sizeof(cname));
688 path->u_name = cname;
690 if (of_stat( path ) == 0 ) {
691 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
692 strlcpy(lname, tmp, sizeof(lname));
705 /* invalidate cache */
708 path->u_name = savepath;
710 /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */
716 * attempt to extend the current dir. tree to include path
717 * as a side-effect, movecwd to that point and return the new dir
720 extenddir(struct vol *vol, struct dir *dir, struct path *path)
724 if ( path->u_name == NULL) {
725 afp_errno = AFPERR_PARAM;
729 if (check_name(vol, path->u_name)) {
730 /* the name is illegal */
731 LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name);
733 afp_errno = AFPERR_PARAM;
737 if (of_stat( path ) != 0 ) {
738 if (!(vol->v_flags & AFPVOL_CASEINSEN))
740 else if(caseenumerate(vol, path, dir) != 0)
744 if (!S_ISDIR(path->st.st_mode)) {
748 /* mac name is always with the right encoding (from cname()) */
749 if (( dir = adddir( vol, dir, path)) == NULL ) {
754 if ( movecwd( vol, dir ) < 0 ) {
761 /* -------------------------
762 appledouble mkdir afp error code.
764 static int netatalk_mkdir(const struct vol *vol, const char *name)
769 if (vol->v_flags & AFPVOL_UNIX_PRIV) {
770 if (lstat(".", &st) < 0)
772 int mode = (DIRBITS & (~S_ISGID & st.st_mode)) | (0777 & ~vol->v_umask);
773 LOG(log_maxdebug, logtype_afpd, "netatalk_mkdir(\"%s\") {parent mode: %04o, vol umask: %04o}",
774 name, st.st_mode, vol->v_umask);
776 ret = mkdir(name, mode);
778 ret = ad_mkdir(name, DIRBITS | 0777);
784 return( AFPERR_NOOBJ );
786 return( AFPERR_VLOCK );
789 return( AFPERR_ACCESS );
791 return( AFPERR_EXIST );
794 return( AFPERR_DFULL );
796 return( AFPERR_PARAM );
802 /* ------------------- */
803 static int deletedir(int dirfd, char *dir)
805 char path[MAXPATHLEN + 1];
813 if ((len = strlen(dir)) +2 > sizeof(path))
817 if ((dp = opendirat(dirfd, dir)) == NULL)
823 remain = sizeof(path) -len -1;
824 while ((de = readdir(dp)) && err == AFP_OK) {
825 /* skip this and previous directory */
826 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
829 if (strlen(de->d_name) > remain) {
833 strcpy(path + len, de->d_name);
834 if (lstatat(dirfd, path, &st)) {
837 if (S_ISDIR(st.st_mode)) {
838 err = deletedir(dirfd, path);
840 err = netatalk_unlinkat(dirfd, path);
845 /* okay. the directory is empty. delete it. note: we already got rid
848 err = netatalk_rmdir(dirfd, dir);
853 /* do a recursive copy. */
854 static int copydir(const struct vol *vol, int dirfd, char *src, char *dst)
856 char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
865 /* doesn't exist or the path is too long. */
866 if (((slen = strlen(src)) > sizeof(spath) - 2) ||
867 ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
868 ((dp = opendirat(dirfd, src)) == NULL))
871 /* try to create the destination directory */
872 if (AFP_OK != (err = netatalk_mkdir(vol, dst)) ) {
877 /* set things up to copy */
881 srem = sizeof(spath) - slen -1;
886 drem = sizeof(dpath) - dlen -1;
889 while ((de = readdir(dp))) {
890 /* skip this and previous directory */
891 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
894 if (strlen(de->d_name) > srem) {
898 strcpy(spath + slen, de->d_name);
900 if (lstatat(dirfd, spath, &st) == 0) {
901 if (strlen(de->d_name) > drem) {
905 strcpy(dpath + dlen, de->d_name);
907 if (S_ISDIR(st.st_mode)) {
908 if (AFP_OK != (err = copydir(vol, dirfd, spath, dpath)))
910 } else if (AFP_OK != (err = copyfile(vol, vol, dirfd, spath, dpath, NULL, NULL))) {
914 /* keep the same time stamp. */
915 ut.actime = ut.modtime = st.st_mtime;
921 /* keep the same time stamp. */
922 if (lstatat(dirfd, src, &st) == 0) {
923 ut.actime = ut.modtime = st.st_mtime;
933 /* --- public functions follow --- */
935 /* NOTE: we start off with at least one node (the root directory). */
936 static struct dir *dirinsert(struct vol *vol, struct dir *dir)
940 if ((node = dir_insert(vol, dir)))
943 /* recolor the tree. the current node is red. */
944 dir->d_color = DIRTREE_COLOR_RED;
946 /* parent of this node has to be black. if the parent node
947 * is red, then we have a grandparent. */
948 while ((dir != vol->v_root) &&
949 (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
950 /* are we on the left tree? */
951 if (dir->d_back == dir->d_back->d_back->d_left) {
952 node = dir->d_back->d_back->d_right; /* get the right node */
953 if (node->d_color == DIRTREE_COLOR_RED) {
954 /* we're red. we need to change to black. */
955 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
956 node->d_color = DIRTREE_COLOR_BLACK;
957 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
958 dir = dir->d_back->d_back; /* finished. go up. */
960 if (dir == dir->d_back->d_right) {
962 dir_leftrotate(vol, dir);
964 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
965 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
966 dir_rightrotate(vol, dir->d_back->d_back);
969 node = dir->d_back->d_back->d_left;
970 if (node->d_color == DIRTREE_COLOR_RED) {
971 /* we're red. we need to change to black. */
972 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
973 node->d_color = DIRTREE_COLOR_BLACK;
974 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
975 dir = dir->d_back->d_back; /* finished. ascend */
977 if (dir == dir->d_back->d_left) {
979 dir_rightrotate(vol, dir);
981 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
982 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
983 dir_leftrotate(vol, dir->d_back->d_back);
988 vol->v_root->d_color = DIRTREE_COLOR_BLACK;
992 /* ---------------------------- */
994 adddir(struct vol *vol, struct dir *dir, struct path *path)
996 struct dir *cdir, *edir;
1003 struct adouble *adp = NULL;
1006 upath = path->u_name;
1008 upathlen = strlen(upath);
1010 /* get_id needs adp for reading CNID from adouble file */
1011 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1012 if ((ad_open_metadata(upath, ADFLAGS_DIR, 0, &ad)) == 0)
1015 id = get_id(vol, adp, st, dir->d_did, upath, upathlen);
1018 ad_close_metadata(adp);
1023 if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
1026 name = path->m_name;
1027 if ((cdir = dirnew(name, upath)) == NULL) {
1028 LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
1031 if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, path->m_name, -1, (char **)&cdir->d_m_name_ucs2)) {
1032 LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
1033 cdir->d_m_name_ucs2 = NULL;
1038 if ((edir = dirinsert( vol, cdir ))) {
1039 /* it's not possible with LASTDID
1041 - someone else have moved the directory.
1042 - it's a symlink inside the share.
1043 - it's an ID reused, the old directory was deleted but not
1044 the cnid record and the server've reused the inode for
1046 for HASH (we should get ride of HASH)
1047 - someone else have moved the directory.
1048 - it's an ID reused as above
1049 - it's a hash duplicate and we are in big trouble
1051 deleted = (edir->d_m_name == NULL);
1053 dir_hash_del(vol, edir);
1055 edir->d_m_name = cdir->d_m_name;
1056 edir->d_u_name = cdir->d_u_name;
1057 edir->d_m_name_ucs2 = cdir->d_m_name_ucs2;
1060 LOG(log_error, logtype_afpd, "adddir: insert %s", edir->d_m_name);
1061 if (!cdir->d_parent || (cdir->d_parent == dir && !deleted)) {
1062 hash_alloc_insert(vol->v_hash, cdir, cdir);
1065 /* the old was not in the same folder */
1067 dirchildremove(cdir->d_parent, cdir);
1070 /* parent/child directories */
1071 cdir->d_parent = dir;
1072 dirchildadd(vol, dir, cdir);
1076 /* --- public functions follow --- */
1077 /* free everything down. we don't bother to recolor as this is only
1078 * called to free the entire tree */
1079 void dirfreename(struct dir *dir)
1081 if (dir->d_u_name != dir->d_m_name) {
1082 free(dir->d_u_name);
1084 if (dir->d_m_name_ucs2)
1085 free(dir->d_m_name_ucs2);
1086 free(dir->d_m_name);
1089 void dirfree(struct dir *dir)
1091 if (!dir || (dir == SENTINEL))
1094 if ( dir->d_left != SENTINEL ) {
1095 dirfree( dir->d_left );
1097 if ( dir->d_right != SENTINEL ) {
1098 dirfree( dir->d_right );
1101 if (dir != SENTINEL) {
1107 /* --------------------------------------------
1108 * most of the time mac name and unix name are the same
1110 struct dir *dirnew(const char *m_name, const char *u_name)
1114 dir = (struct dir *) calloc(1, sizeof( struct dir ));
1118 if ((dir->d_m_name = strdup(m_name)) == NULL) {
1123 if (m_name == u_name || !strcmp(m_name, u_name)) {
1124 dir->d_u_name = dir->d_m_name;
1126 else if ((dir->d_u_name = strdup(u_name)) == NULL) {
1127 free(dir->d_m_name);
1132 dir->d_m_name_ucs2 = NULL;
1133 dir->d_left = dir->d_right = SENTINEL;
1134 dir->d_next = dir->d_prev = dir;
1139 /* ------------------ */
1140 static hash_val_t hash_fun_dir(const void *key)
1142 const struct dir *k = key;
1144 static unsigned long randbox[] = {
1145 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
1146 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
1147 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
1148 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
1151 const unsigned char *str = (unsigned char *)(k->d_u_name);
1152 hash_val_t acc = k->d_parent->d_did;
1155 acc ^= randbox[(*str + acc) & 0xf];
1156 acc = (acc << 1) | (acc >> 31);
1158 acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
1159 acc = (acc << 2) | (acc >> 30);
1167 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
1168 || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
1169 #define get16bits(d) (*((const uint16_t *) (d)))
1172 #if !defined (get16bits)
1173 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
1174 +(uint32_t)(((const uint8_t *)(d))[0]) )
1177 static hash_val_t hash_fun2_dir(const void *key)
1179 const struct dir *k = key;
1180 const char *data = k->d_u_name;
1181 int len = strlen(k->d_u_name);
1182 hash_val_t hash = k->d_parent->d_did, tmp;
1188 for (;len > 0; len--) {
1189 hash += get16bits (data);
1190 tmp = (get16bits (data+2) << 11) ^ hash;
1191 hash = (hash << 16) ^ tmp;
1192 data += 2*sizeof (uint16_t);
1196 /* Handle end cases */
1198 case 3: hash += get16bits (data);
1200 hash ^= data[sizeof (uint16_t)] << 18;
1203 case 2: hash += get16bits (data);
1207 case 1: hash += *data;
1212 /* Force "avalanching" of final 127 bits */
1223 /* ---------------- */
1224 static int hash_comp_dir(const void *key1, const void *key2)
1226 const struct dir *k1 = key1;
1227 const struct dir *k2 = key2;
1229 return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
1232 /* ---------------- */
1236 return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
1239 /* ------------------ */
1240 static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
1243 movecwd failed some of dir path are not there anymore.
1244 FIXME Is it true with other errors?
1245 so we remove dir from the cache
1247 if (dir->d_did == DIRDID_ROOT_PARENT)
1249 if (afp_errno == AFPERR_ACCESS) {
1250 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1253 /* FIXME should we set these?, don't need to call stat() after:
1255 ret->st_errno = EACCES;
1257 ret->m_name = dir->d_m_name;
1258 ret->u_name = dir->d_u_name;
1261 } else if (afp_errno == AFPERR_NOOBJ) {
1262 if ( movecwd( vol, dir->d_parent ) < 0 ) {
1265 strcpy(ret->m_name, dir->d_m_name);
1266 if (dir->d_m_name == dir->d_u_name) {
1267 ret->u_name = ret->m_name;
1270 size_t tp = strlen(ret->m_name)+1;
1272 ret->u_name = ret->m_name +tp;
1273 strcpy(ret->u_name, dir->d_u_name);
1275 /* FIXME should we set :
1277 ret->st_errno = ENOENT;
1279 dir_invalidate(vol, dir);
1282 dir_invalidate(vol, dir);
1286 /* -------------------------------------------------- */
1292 stat the file or errno
1295 curdir: filename parent directory
1301 stat the dir or errno
1305 curdir: dir parent directory
1313 curdir: dir parent directory
1320 cname(struct vol *vol, struct dir *dir, char **cpath)
1322 struct dir *cdir, *scdir=NULL;
1323 static char path[ MAXPATHLEN + 1];
1324 static struct path ret;
1336 afp_errno = AFPERR_NOOBJ;
1337 memset(&ret, 0, sizeof(ret));
1338 switch (ret.m_type = *data) { /* path type */
1341 len = (unsigned char) *data++;
1344 if (afp_version >= 30) {
1350 if (afp_version >= 30) {
1352 memcpy(&hint, data, sizeof(hint));
1354 data += sizeof(hint);
1356 memcpy(&len16, data, sizeof(len16));
1363 /* else it's an error */
1365 afp_errno = AFPERR_PARAM;
1368 *cpath += len + size;
1373 if (movecwd( vol, dir ) < 0 ) {
1374 return invalidate(vol, dir, &ret );
1376 if (*path == '\0') {
1383 if (*data == sep ) {
1387 while (*data == sep && len > 0 ) {
1388 if ( dir->d_parent == NULL ) {
1391 dir = dir->d_parent;
1396 /* would this be faster with strlen + strncpy? */
1398 while ( *data != sep && len > 0 ) {
1400 if (p > &path[ MAXPATHLEN]) {
1401 afp_errno = AFPERR_PARAM;
1407 /* short cut bits by chopping off a trailing \0. this also
1408 makes the traversal happy w/ filenames at the end of the
1415 if ( p == path ) { /* end of the name parameter */
1419 if (afp_version >= 30) {
1424 static char temp[ MAXPATHLEN + 1];
1426 if (dir->d_did == DIRDID_ROOT_PARENT) {
1428 With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
1429 So we compare it with the longname from the current volume and if they match
1430 we overwrite the requested path with the utf8 volume name so that the following
1433 ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
1434 if (strcasecmp( path, temp) == 0)
1435 ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
1438 if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
1439 afp_errno = AFPERR_PARAM;
1445 /* check for OS X mangled filename :( */
1447 t = demangle_osx(vol, path, dir->d_did, &fileid);
1450 /* duplicate work but we can't reuse all convert_char we did in demangle_osx
1451 * flags weren't the same
1453 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
1454 /* at last got our view of mac name */
1459 if (ret.u_name == NULL) {
1460 if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
1461 afp_errno = AFPERR_PARAM;
1467 cdir = dir->d_child;
1469 if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
1470 (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
1471 CH_UCS2, path, -1, (char **)&tmpname) )
1474 if (!cdir->d_m_name_ucs2) {
1475 LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
1476 /* this shouldn't happen !!!! */
1480 if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1483 if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1486 cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
1492 if (dir->d_did == DIRDID_ROOT_PARENT) {
1494 root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
1495 must check against the volume name.
1497 if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
1503 cdir = dirsearch_byname(vol, dir, ret.u_name);
1507 if (cdir == NULL && scdir != NULL) {
1509 /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
1512 if ( cdir == NULL ) {
1514 /* if dir == curdir it always succeed,
1515 even if curdir is deleted.
1516 it's not a pb because it will fail in extenddir
1518 if ( movecwd( vol, dir ) < 0 ) {
1519 /* dir is not valid anymore
1520 we delete dir from the cache and abort.
1522 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1523 afp_errno = AFPERR_NOOBJ;
1526 if (afp_errno == AFPERR_ACCESS)
1528 dir_invalidate(vol, dir);
1531 cdir = extenddir( vol, dir, &ret );
1535 cdir = extenddir( vol, dir, &ret );
1536 } /* if (!extend) */
1538 if ( cdir == NULL ) {
1540 if ( len > 0 || !ret.u_name ) {
1552 * Move curdir to dir, with a possible chdir()
1554 int movecwd(struct vol *vol, struct dir *dir)
1556 char path[MAXPATHLEN + 1];
1562 if ( dir == curdir ) {
1565 if ( dir->d_did == DIRDID_ROOT_PARENT) {
1566 afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
1570 p = path + sizeof(path) - 1;
1572 for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
1575 /* parent directory is deleted */
1576 afp_errno = AFPERR_NOOBJ;
1580 if (p -n -1 < path) {
1581 afp_errno = AFPERR_PARAM;
1588 if ( d != curdir ) {
1589 n = strlen( vol->v_path );
1590 if (p -n -1 < path) {
1591 afp_errno = AFPERR_PARAM;
1596 memcpy( p, vol->v_path, n );
1598 if ( (ret = lchdir(p )) != 0 ) {
1599 LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno));
1602 /* p is a symlink or getcwd failed */
1603 afp_errno = AFPERR_BADTYPE;
1604 vol->v_curdir = curdir = vol->v_dir;
1605 if (chdir(vol->v_path ) < 0) {
1606 LOG(log_debug, logtype_afpd, "can't chdir back'%s': %s", vol->v_path, strerror(errno));
1607 /* XXX what do we do here? */
1614 afp_errno = AFPERR_ACCESS;
1617 afp_errno = AFPERR_NOOBJ;
1622 vol->v_curdir = curdir = dir;
1627 * We can't use unix file's perm to support Apple's inherited protection modes.
1628 * If we aren't the file's owner we can't change its perms when moving it and smb
1629 * nfs,... don't even try.
1631 #define AFP_CHECK_ACCESS
1633 int check_access(char *path, int mode)
1635 #ifdef AFP_CHECK_ACCESS
1643 accessmode(p, &ma, curdir, NULL);
1644 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1646 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1652 /* --------------------- */
1653 int file_access(struct path *path, int mode)
1657 accessmode(path->u_name, &ma, curdir, &path->st);
1658 if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1660 if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1666 /* --------------------- */
1667 void setdiroffcnt(struct dir *dir, struct stat *st, u_int32_t count)
1669 dir->offcnt = count;
1670 dir->ctime = st->st_ctime;
1671 dir->d_flags &= ~DIRF_CNID;
1674 /* ---------------------
1675 * is our cached offspring count valid?
1678 static int diroffcnt(struct dir *dir, struct stat *st)
1680 return st->st_ctime == dir->ctime;
1683 /* ---------------------
1684 * is our cached also for reenumerate id?
1687 int dirreenumerate(struct dir *dir, struct stat *st)
1689 return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
1692 /* --------------------- */
1693 static int invisible_dots(const struct vol *vol, const char *name)
1695 return vol_inv_dots(vol) && *name == '.' && strcmp(name, ".") && strcmp(name, "..");
1698 /* ------------------------------
1700 (name, dir) with curdir:name == dir, from afp_enumerate
1703 int getdirparams(const struct vol *vol,
1704 u_int16_t bitmap, struct path *s_path,
1706 char *buf, size_t *buflen )
1710 char *data, *l_nameoff = NULL, *utf_nameoff = NULL;
1711 int bit = 0, isad = 0;
1717 struct stat *st = &s_path->st;
1718 char *upath = s_path->u_name;
1720 if ((bitmap & ((1 << DIRPBIT_ATTR) |
1721 (1 << DIRPBIT_CDATE) |
1722 (1 << DIRPBIT_MDATE) |
1723 (1 << DIRPBIT_BDATE) |
1724 (1 << DIRPBIT_FINFO)))) {
1726 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1727 if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
1729 if (ad.ad_md->adf_flags & O_CREAT) {
1730 /* We just created it */
1731 ad_setname(&ad, s_path->m_name);
1736 dir->d_parent->d_did,
1743 if ( dir->d_did == DIRDID_ROOT) {
1744 pdid = DIRDID_ROOT_PARENT;
1745 } else if (dir->d_did == DIRDID_ROOT_PARENT) {
1748 pdid = dir->d_parent->d_did;
1752 while ( bitmap != 0 ) {
1753 while (( bitmap & 1 ) == 0 ) {
1761 ad_getattr(&ad, &ashort);
1762 } else if (invisible_dots(vol, dir->d_u_name)) {
1763 ashort = htons(ATTRBIT_INVISIBLE);
1766 ashort |= htons(ATTRBIT_SHARED);
1767 memcpy( data, &ashort, sizeof( ashort ));
1768 data += sizeof( ashort );
1772 memcpy( data, &pdid, sizeof( pdid ));
1773 data += sizeof( pdid );
1776 case DIRPBIT_CDATE :
1777 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1778 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1779 memcpy( data, &aint, sizeof( aint ));
1780 data += sizeof( aint );
1783 case DIRPBIT_MDATE :
1784 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1785 memcpy( data, &aint, sizeof( aint ));
1786 data += sizeof( aint );
1789 case DIRPBIT_BDATE :
1790 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
1791 aint = AD_DATE_START;
1792 memcpy( data, &aint, sizeof( aint ));
1793 data += sizeof( aint );
1796 case DIRPBIT_FINFO :
1798 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
1799 } else { /* no appledouble */
1800 memset( data, 0, 32 );
1801 /* set default view -- this also gets done in ad_open() */
1802 ashort = htons(FINDERINFO_CLOSEDVIEW);
1803 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
1805 /* dot files are by default visible */
1806 if (invisible_dots(vol, dir->d_u_name)) {
1807 ashort = htons(FINDERINFO_INVISIBLE);
1808 memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
1814 case DIRPBIT_LNAME :
1815 if (dir->d_m_name) /* root of parent can have a null name */
1818 memset(data, 0, sizeof(u_int16_t));
1819 data += sizeof( u_int16_t );
1822 case DIRPBIT_SNAME :
1823 memset(data, 0, sizeof(u_int16_t));
1824 data += sizeof( u_int16_t );
1828 memcpy( data, &dir->d_did, sizeof( aint ));
1829 data += sizeof( aint );
1832 case DIRPBIT_OFFCNT :
1834 /* this needs to handle current directory access rights */
1835 if (diroffcnt(dir, st)) {
1836 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1838 else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
1839 setdiroffcnt(dir, st, ret);
1840 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1842 ashort = htons( ashort );
1843 memcpy( data, &ashort, sizeof( ashort ));
1844 data += sizeof( ashort );
1848 aint = htonl(st->st_uid);
1849 memcpy( data, &aint, sizeof( aint ));
1850 data += sizeof( aint );
1854 aint = htonl(st->st_gid);
1855 memcpy( data, &aint, sizeof( aint ));
1856 data += sizeof( aint );
1859 case DIRPBIT_ACCESS :
1860 accessmode( upath, &ma, dir , st);
1862 *data++ = ma.ma_user;
1863 *data++ = ma.ma_world;
1864 *data++ = ma.ma_group;
1865 *data++ = ma.ma_owner;
1868 /* Client has requested the ProDOS information block.
1869 Just pass back the same basic block for all
1870 directories. <shirsch@ibm.net> */
1871 case DIRPBIT_PDINFO :
1872 if (afp_version >= 30) { /* UTF8 name */
1873 utf8 = kTextEncodingUTF8;
1874 if (dir->d_m_name) /* root of parent can have a null name */
1877 memset(data, 0, sizeof(u_int16_t));
1878 data += sizeof( u_int16_t );
1880 memcpy(data, &aint, sizeof( aint ));
1881 data += sizeof( aint );
1883 else { /* ProDOS Info Block */
1886 ashort = htons( 0x0200 );
1887 memcpy( data, &ashort, sizeof( ashort ));
1888 data += sizeof( ashort );
1889 memset( data, 0, sizeof( ashort ));
1890 data += sizeof( ashort );
1894 case DIRPBIT_UNIXPR :
1895 aint = htonl(st->st_uid);
1896 memcpy( data, &aint, sizeof( aint ));
1897 data += sizeof( aint );
1898 aint = htonl(st->st_gid);
1899 memcpy( data, &aint, sizeof( aint ));
1900 data += sizeof( aint );
1903 aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */
1904 memcpy( data, &aint, sizeof( aint ));
1905 data += sizeof( aint );
1907 accessmode( upath, &ma, dir , st);
1909 *data++ = ma.ma_user;
1910 *data++ = ma.ma_world;
1911 *data++ = ma.ma_group;
1912 *data++ = ma.ma_owner;
1917 ad_close_metadata( &ad );
1919 return( AFPERR_BITMAP );
1925 ashort = htons( data - buf );
1926 memcpy( l_nameoff, &ashort, sizeof( ashort ));
1927 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, 0);
1929 if ( utf_nameoff ) {
1930 ashort = htons( data - buf );
1931 memcpy( utf_nameoff, &ashort, sizeof( ashort ));
1932 data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, utf8);
1935 ad_close_metadata( &ad );
1937 *buflen = data - buf;
1941 /* ----------------------------- */
1942 int path_error(struct path *path, int error)
1944 /* - a dir with access error
1945 * - no error it's a file
1948 if (path_isadir(path))
1950 if (path->st_valid && path->st_errno)
1952 return AFPERR_BADTYPE ;
1955 /* ----------------------------- */
1956 int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1961 u_int16_t vid, bitmap;
1967 memcpy( &vid, ibuf, sizeof( vid ));
1968 ibuf += sizeof( vid );
1970 if (NULL == ( vol = getvolbyvid( vid )) ) {
1971 return( AFPERR_PARAM );
1974 if (vol->v_flags & AFPVOL_RO)
1975 return AFPERR_VLOCK;
1977 memcpy( &did, ibuf, sizeof( did ));
1978 ibuf += sizeof( int );
1980 if (NULL == ( dir = dirlookup( vol, did )) ) {
1984 memcpy( &bitmap, ibuf, sizeof( bitmap ));
1985 bitmap = ntohs( bitmap );
1986 ibuf += sizeof( bitmap );
1988 if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1989 return get_afp_errno(AFPERR_NOOBJ);
1992 if ( *path->m_name != '\0' ) {
1993 rc = path_error(path, AFPERR_NOOBJ);
1994 /* maybe we are trying to set perms back */
1995 if (rc != AFPERR_ACCESS)
2000 * If ibuf is odd, make it even.
2002 if ((u_long)ibuf & 1 ) {
2006 if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
2007 setvoltime(obj, vol );
2013 * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
2015 * assume path == '\0' eg. it's a directory in canonical form
2018 struct path Cur_Path = {
2021 ".", /* unix name */
2023 NULL,/* struct dir */
2024 0, /* stat is not set */
2027 /* ------------------ */
2028 static int set_dir_errors(struct path *path, const char *where, int err)
2033 return AFPERR_ACCESS;
2035 return AFPERR_VLOCK;
2037 LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
2038 return AFPERR_PARAM;
2041 /* ------------------ */
2042 int setdirparams(struct vol *vol,
2043 struct path *path, u_int16_t d_bitmap, char *buf )
2055 u_int16_t ashort, bshort, oshort;
2057 int change_mdate = 0;
2058 int change_parent_mdate = 0;
2060 u_int16_t bitmap = d_bitmap;
2061 u_char finder_buf[32];
2064 u_int16_t upriv_bit = 0;
2067 upath = path->u_name;
2069 while ( bitmap != 0 ) {
2070 while (( bitmap & 1 ) == 0 ) {
2078 memcpy( &ashort, buf, sizeof( ashort ));
2079 buf += sizeof( ashort );
2081 case DIRPBIT_CDATE :
2083 memcpy(&cdate, buf, sizeof(cdate));
2084 buf += sizeof( cdate );
2086 case DIRPBIT_MDATE :
2087 memcpy(&newdate, buf, sizeof(newdate));
2088 buf += sizeof( newdate );
2090 case DIRPBIT_BDATE :
2092 memcpy(&bdate, buf, sizeof(bdate));
2093 buf += sizeof( bdate );
2095 case DIRPBIT_FINFO :
2097 memcpy( finder_buf, buf, 32 );
2100 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2101 change_parent_mdate = 1;
2102 memcpy( &owner, buf, sizeof(owner));
2103 buf += sizeof( owner );
2106 change_parent_mdate = 1;
2107 memcpy( &group, buf, sizeof( group ));
2108 buf += sizeof( group );
2110 case DIRPBIT_ACCESS :
2112 change_parent_mdate = 1;
2113 ma.ma_user = *buf++;
2114 ma.ma_world = *buf++;
2115 ma.ma_group = *buf++;
2116 ma.ma_owner = *buf++;
2117 mpriv = mtoumode( &ma ) | vol->v_dperm;
2118 if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2119 err = set_dir_errors(path, "setdirmode", errno);
2123 /* Ignore what the client thinks we should do to the
2124 ProDOS information block. Skip over the data and
2125 report nothing amiss. <shirsch@ibm.net> */
2126 case DIRPBIT_PDINFO :
2127 if (afp_version < 30) {
2131 err = AFPERR_BITMAP;
2135 case DIRPBIT_UNIXPR :
2136 if (vol_unix_priv(vol)) {
2137 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
2138 buf += sizeof( owner );
2139 memcpy( &group, buf, sizeof( group ));
2140 buf += sizeof( group );
2143 change_parent_mdate = 1;
2144 memcpy( &upriv, buf, sizeof( upriv ));
2145 buf += sizeof( upriv );
2146 upriv = ntohl (upriv) | vol->v_dperm;
2147 if (dir_rx_set(upriv)) {
2148 /* maybe we are trying to set perms back */
2149 if ( setdirunixmode(vol, upath, upriv) < 0 ) {
2151 err = set_dir_errors(path, "setdirunixmode", errno);
2162 err = AFPERR_BITMAP;
2170 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2172 if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
2174 * Check to see what we're trying to set. If it's anything
2175 * but ACCESS, UID, or GID, give an error. If it's any of those
2176 * three, we don't need the ad to be open, so just continue.
2178 * note: we also don't need to worry about mdate. also, be quiet
2179 * if we're using the noadouble option.
2181 if (!vol_noadouble(vol) && (d_bitmap &
2182 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
2183 (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
2184 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
2185 return AFPERR_ACCESS;
2191 * Check to see if a create was necessary. If it was, we'll want
2192 * to set our name, etc.
2194 if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
2195 ad_setname(&ad, curdir->d_m_name);
2201 while ( bitmap != 0 ) {
2202 while (( bitmap & 1 ) == 0 ) {
2210 ad_getattr(&ad, &bshort);
2212 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
2213 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
2217 if ((bshort & htons(ATTRBIT_INVISIBLE)) != (oshort & htons(ATTRBIT_INVISIBLE)))
2218 change_parent_mdate = 1;
2219 ad_setattr(&ad, bshort);
2222 case DIRPBIT_CDATE :
2224 ad_setdate(&ad, AD_DATE_CREATE, cdate);
2227 case DIRPBIT_MDATE :
2229 case DIRPBIT_BDATE :
2231 ad_setdate(&ad, AD_DATE_BACKUP, bdate);
2234 case DIRPBIT_FINFO :
2236 /* Fixes #2802236 */
2237 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
2238 *fflags &= htons(~FINDERINFO_ISHARED);
2240 if ( dir->d_did == DIRDID_ROOT ) {
2242 * Alright, we admit it, this is *really* sick!
2243 * The 4 bytes that we don't copy, when we're dealing
2244 * with the root of a volume, are the directory's
2245 * location information. This eliminates that annoying
2246 * behavior one sees when mounting above another mount
2249 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
2250 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
2252 memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
2256 case DIRPBIT_UID : /* What kind of loser mounts as root? */
2257 if ( (dir->d_did == DIRDID_ROOT) &&
2258 (setdeskowner( ntohl(owner), -1 ) < 0)) {
2259 err = set_dir_errors(path, "setdeskowner", errno);
2260 if (isad && err == AFPERR_PARAM) {
2261 err = AFP_OK; /* ???*/
2264 goto setdirparam_done;
2267 if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
2268 err = set_dir_errors(path, "setdirowner", errno);
2269 goto setdirparam_done;
2273 if (dir->d_did == DIRDID_ROOT)
2274 setdeskowner( -1, ntohl(group) );
2275 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2276 err = set_dir_errors(path, "setdirowner", errno);
2277 goto setdirparam_done;
2280 case DIRPBIT_ACCESS :
2281 if (dir->d_did == DIRDID_ROOT) {
2283 if (!dir_rx_set(mpriv)) {
2284 /* we can't remove read and search for owner on volume root */
2285 err = AFPERR_ACCESS;
2286 goto setdirparam_done;
2290 if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2291 err = set_dir_errors(path, "setdirmode", errno);
2292 goto setdirparam_done;
2295 case DIRPBIT_PDINFO :
2296 if (afp_version >= 30) {
2297 err = AFPERR_BITMAP;
2298 goto setdirparam_done;
2301 case DIRPBIT_UNIXPR :
2302 if (vol_unix_priv(vol)) {
2303 if (dir->d_did == DIRDID_ROOT) {
2304 if (!dir_rx_set(upriv)) {
2305 /* we can't remove read and search for owner on volume root */
2306 err = AFPERR_ACCESS;
2307 goto setdirparam_done;
2309 setdeskowner( -1, ntohl(group) );
2310 setdeskmode( upriv );
2312 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2313 err = set_dir_errors(path, "setdirowner", errno);
2314 goto setdirparam_done;
2317 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
2318 err = set_dir_errors(path, "setdirunixmode", errno);
2319 goto setdirparam_done;
2323 err = AFPERR_BITMAP;
2324 goto setdirparam_done;
2328 err = AFPERR_BITMAP;
2329 goto setdirparam_done;
2338 if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
2339 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2343 ad_setdate(&ad, AD_DATE_MODIFY, newdate);
2344 ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
2349 if (path->st_valid && !path->st_errno) {
2350 struct stat *st = &path->st;
2352 if (dir && dir->d_parent) {
2353 ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_parent->d_did, vol->v_stamp);
2357 ad_close_metadata( &ad);
2360 if (change_parent_mdate && dir->d_did != DIRDID_ROOT
2361 && gettimeofday(&tv, NULL) == 0) {
2362 if (!movecwd(vol, dir->d_parent)) {
2363 newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2364 /* be careful with bitmap because now dir is null */
2365 bitmap = 1<<DIRPBIT_MDATE;
2366 setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
2367 /* should we reset curdir ?*/
2374 int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2388 memcpy( &vid, ibuf, sizeof( vid ));
2389 ibuf += sizeof( vid );
2390 if (NULL == (vol = getvolbyvid( vid )) ) {
2391 return( AFPERR_PARAM );
2394 memcpy( &did, ibuf, sizeof( did ));
2395 ibuf += sizeof( did );
2399 * if it's CNID 2 our only choice to meet the specs is call sync.
2400 * For any other CNID just sync that dir. To my knowledge the
2401 * intended use of FPSyncDir is to sync the volume so all we're
2402 * ever going to see here is probably CNID 2. Anyway, we' prepared.
2405 if ( ntohl(did) == 2 ) {
2408 if (NULL == ( dir = dirlookup( vol, did )) ) {
2409 return afp_errno; /* was AFPERR_NOOBJ */
2412 if (movecwd( vol, dir ) < 0 )
2413 return ( AFPERR_NOOBJ );
2416 * Assuming only OSens that have dirfd also may require fsyncing directories
2417 * in order to flush metadata e.g. Linux.
2421 if (NULL == ( dp = opendir( "." )) ) {
2424 return( AFPERR_NOOBJ );
2426 return( AFPERR_ACCESS );
2428 return( AFPERR_PARAM );
2432 LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
2435 if ( fsync ( dfd ) < 0 )
2436 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2437 dir->d_u_name, strerror(errno) );
2438 closedir(dp); /* closes dfd too */
2441 if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
2444 return( AFPERR_NOOBJ );
2446 return( AFPERR_ACCESS );
2448 return( AFPERR_PARAM );
2452 LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
2453 vol->ad_path(".", ADFLAGS_DIR) );
2455 if ( fsync(dfd) < 0 )
2456 LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2457 vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
2464 int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2470 struct path *s_path;
2478 memcpy( &vid, ibuf, sizeof( vid ));
2479 ibuf += sizeof( vid );
2480 if (NULL == ( vol = getvolbyvid( vid )) ) {
2481 return( AFPERR_PARAM );
2484 if (vol->v_flags & AFPVOL_RO)
2485 return AFPERR_VLOCK;
2487 memcpy( &did, ibuf, sizeof( did ));
2488 ibuf += sizeof( did );
2489 if (NULL == ( dir = dirlookup( vol, did )) ) {
2490 return afp_errno; /* was AFPERR_NOOBJ */
2492 /* for concurrent access we need to be sure we are not in the
2493 * folder we want to create...
2497 if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
2498 return get_afp_errno(AFPERR_PARAM);
2500 /* cname was able to move curdir to it! */
2501 if (*s_path->m_name == '\0')
2502 return AFPERR_EXIST;
2504 upath = s_path->u_name;
2506 if (AFP_OK != (err = netatalk_mkdir(vol, upath))) {
2510 if (of_stat(s_path) < 0) {
2514 if ((dir = adddir( vol, curdir, s_path)) == NULL) {
2518 if ( movecwd( vol, dir ) < 0 ) {
2519 return( AFPERR_PARAM );
2522 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2523 if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
2524 if (vol_noadouble(vol))
2525 goto createdir_done;
2526 return( AFPERR_ACCESS );
2528 ad_setname(&ad, s_path->m_name);
2529 ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
2532 ad_close_metadata( &ad);
2535 #ifdef HAVE_NFSv4_ACLS
2536 /* FIXME: are we really inside the created dir? */
2537 addir_inherit_acl(vol);
2540 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
2541 *rbuflen = sizeof( u_int32_t );
2542 setvoltime(obj, vol );
2547 * dst new unix filename (not a pathname)
2548 * newname new mac name
2550 * dirfd -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd
2552 int renamedir(const struct vol *vol,
2557 struct dir *newparent,
2565 /* existence check moved to afp_moveandrename */
2566 if ( unix_rename(dirfd, src, -1, dst ) < 0 ) {
2569 return( AFPERR_NOOBJ );
2571 return( AFPERR_ACCESS );
2573 return AFPERR_VLOCK;
2575 /* tried to move directory into a subdirectory of itself */
2576 return AFPERR_CANTMOVE;
2578 /* this needs to copy and delete. bleah. that means we have
2579 * to deal with entire directory hierarchies. */
2580 if ((err = copydir(vol, dirfd, src, dst)) < 0) {
2584 if ((err = deletedir(dirfd, src)) < 0)
2588 return( AFPERR_PARAM );
2592 vol->vfs->vfs_renamedir(vol, dirfd, src, dst);
2594 len = strlen( newname );
2595 /* rename() succeeded so we need to update our tree even if we can't open
2599 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2601 if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
2602 ad_setname(&ad, newname);
2604 ad_close_metadata( &ad);
2607 dir_hash_del(vol, dir);
2608 if (dir->d_m_name == dir->d_u_name)
2609 dir->d_u_name = NULL;
2611 if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
2612 LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
2613 /* FIXME : fatal ? */
2616 dir->d_m_name = buf;
2617 strcpy( dir->d_m_name, newname );
2619 if (newname == dst) {
2620 free(dir->d_u_name);
2621 dir->d_u_name = dir->d_m_name;
2624 if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
2625 LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
2628 dir->d_u_name = buf;
2629 strcpy( dir->d_u_name, dst );
2632 if (dir->d_m_name_ucs2)
2633 free(dir->d_m_name_ucs2);
2635 dir->d_m_name_ucs2 = NULL;
2636 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))
2637 dir->d_m_name_ucs2 = NULL;
2639 if (( parent = dir->d_parent ) == NULL ) {
2642 if ( parent == newparent ) {
2643 hash_alloc_insert(vol->v_hash, dir, dir);
2647 /* detach from old parent and add to new one. */
2648 dirchildremove(parent, dir);
2649 dir->d_parent = newparent;
2650 dirchildadd(vol, newparent, dir);
2654 /* delete an empty directory */
2655 int deletecurdir(struct vol *vol)
2665 if ( curdir->d_parent == NULL ) {
2666 return( AFPERR_ACCESS );
2671 ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2672 /* we never want to create a resource fork here, we are going to delete it */
2673 if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
2675 ad_getattr(&ad, &ashort);
2676 ad_close_metadata(&ad);
2677 if ((ashort & htons(ATTRBIT_NODELETE))) {
2678 return AFPERR_OLOCK;
2681 err = vol->vfs->vfs_deletecurdir(vol);
2686 /* now get rid of dangling symlinks */
2687 if ((dp = opendir("."))) {
2688 while ((de = readdir(dp))) {
2689 /* skip this and previous directory */
2690 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2693 /* bail if it's not a symlink */
2694 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
2696 return AFPERR_DIRNEMPT;
2699 if ((err = netatalk_unlink(de->d_name))) {
2706 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
2711 err = netatalk_rmdir_all_errors(-1, fdir->d_u_name);
2712 if ( err == AFP_OK || err == AFPERR_NOOBJ) {
2713 dirchildremove(curdir, fdir);
2714 cnid_delete(vol->v_cdb, fdir->d_did);
2715 dir_remove( vol, fdir );
2719 /* inode is used as key for cnid.
2720 * Close the descriptor only after cnid_delete
2728 int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2738 sfunc = (unsigned char) *ibuf++;
2742 if (sfunc >= 3 && sfunc <= 6) {
2743 if (afp_version < 30) {
2744 return( AFPERR_PARAM );
2751 case 3 :/* unicode */
2752 memcpy( &id, ibuf, sizeof( id ));
2755 if (( pw = getpwuid( id )) == NULL ) {
2756 return( AFPERR_NOITEM );
2758 len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
2759 pw->pw_name, -1, &name);
2766 case 4 : /* unicode */
2767 memcpy( &id, ibuf, sizeof( id ));
2770 if (NULL == ( gr = (struct group *)getgrgid( id ))) {
2771 return( AFPERR_NOITEM );
2773 len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
2774 gr->gr_name, -1, &name);
2780 #ifdef HAVE_NFSv4_ACLS
2781 case 5 : /* UUID -> username */
2782 case 6 : /* UUID -> groupname */
2783 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2784 return AFPERR_PARAM;
2785 LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
2787 len = getnamefromuuid( ibuf, &name, &type);
2788 if (len != 0) /* its a error code, not len */
2789 return AFPERR_NOITEM;
2790 if (type == UUID_USER) {
2791 if (( pw = getpwnam( name )) == NULL )
2792 return( AFPERR_NOITEM );
2793 LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
2794 id = htonl(UUID_USER);
2795 memcpy( rbuf, &id, sizeof( id ));
2796 id = htonl( pw->pw_uid);
2797 rbuf += sizeof( id );
2798 memcpy( rbuf, &id, sizeof( id ));
2799 rbuf += sizeof( id );
2800 *rbuflen = 2 * sizeof( id );
2801 } else { /* type == UUID_GROUP */
2802 if (( gr = getgrnam( name )) == NULL )
2803 return( AFPERR_NOITEM );
2804 LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
2805 id = htonl(UUID_GROUP);
2806 memcpy( rbuf, &id, sizeof( id ));
2807 rbuf += sizeof( id );
2808 id = htonl( gr->gr_gid);
2809 memcpy( rbuf, &id, sizeof( id ));
2810 rbuf += sizeof( id );
2811 *rbuflen = 2 * sizeof( id );
2816 return( AFPERR_PARAM );
2820 len = strlen( name );
2823 u_int16_t tp = htons(len);
2824 memcpy(rbuf, &tp, sizeof(tp));
2833 memcpy( rbuf, name, len );
2841 int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2850 sfunc = (unsigned char) *ibuf++;
2852 LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
2855 case 2 : /* unicode */
2856 if (afp_version < 30) {
2857 return( AFPERR_PARAM );
2859 memcpy(&ulen, ibuf, sizeof(ulen));
2862 LOG(log_debug, logtype_afpd, "afp_mapname: alive");
2866 len = (unsigned char) *ibuf++;
2868 #ifdef HAVE_NFSv4_ACLS
2869 case 5 : /* username -> UUID */
2870 case 6 : /* groupname -> UUID */
2871 if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2872 return AFPERR_PARAM;
2873 memcpy(&ulen, ibuf, sizeof(ulen));
2879 return( AFPERR_PARAM );
2885 return AFPERR_PARAM;
2888 case 1 : /* unicode */
2890 if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) {
2891 return( AFPERR_NOITEM );
2895 memcpy( rbuf, &id, sizeof( id ));
2896 *rbuflen = sizeof( id );
2899 case 2 : /* unicode */
2901 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
2902 if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
2903 return( AFPERR_NOITEM );
2906 LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
2908 memcpy( rbuf, &id, sizeof( id ));
2909 *rbuflen = sizeof( id );
2911 #ifdef HAVE_NFSv4_ACLS
2912 case 5 : /* username -> UUID */
2913 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2914 if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
2915 return AFPERR_NOITEM;
2916 *rbuflen = UUID_BINSIZE;
2918 case 6 : /* groupname -> UUID */
2919 LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2920 if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
2921 return AFPERR_NOITEM;
2922 *rbuflen = UUID_BINSIZE;
2930 /* ------------------------------------
2931 variable DID support
2933 int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2944 /* do nothing as dids are static for the life of the process. */
2948 memcpy(&vid, ibuf, sizeof( vid ));
2949 ibuf += sizeof( vid );
2950 if (( vol = getvolbyvid( vid )) == NULL ) {
2951 return( AFPERR_PARAM );
2954 memcpy( &did, ibuf, sizeof( did ));
2955 ibuf += sizeof( did );
2956 if (( dir = dirlookup( vol, did )) == NULL ) {
2957 return( AFPERR_PARAM );
2960 /* dir_remove -- deletedid */
2966 /* did creation gets done automatically
2967 * there's a pb again with case but move it to cname
2969 int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2972 struct dir *parentdir;
2980 memcpy(&vid, ibuf, sizeof(vid));
2981 ibuf += sizeof( vid );
2983 if (NULL == ( vol = getvolbyvid( vid )) ) {
2984 return( AFPERR_PARAM );
2987 memcpy(&did, ibuf, sizeof(did));
2988 ibuf += sizeof(did);
2990 if (NULL == ( parentdir = dirlookup( vol, did )) ) {
2994 if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
2995 return get_afp_errno(AFPERR_PARAM);
2998 if ( *path->m_name != '\0' ) {
2999 return path_error(path, AFPERR_NOOBJ);
3002 if ( !path->st_valid && of_stat(path ) < 0 ) {
3003 return( AFPERR_NOOBJ );
3005 if ( path->st_errno ) {
3006 return( AFPERR_NOOBJ );
3009 memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did));
3010 *rbuflen = sizeof(curdir->d_did);