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
13 #include <sys/syslog.h>
14 #include <sys/types.h>
18 #include <sys/param.h>
19 #include <netatalk/endian.h>
20 #include <atalk/adouble.h>
21 #include <atalk/afp.h>
22 #include <atalk/util.h>
23 #include <atalk/cnid.h>
33 #include "directory.h"
47 #define SENTINEL (&sentinel)
48 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, DIRTREE_COLOR_BLACK,
49 NULL, NULL, NULL, NULL, NULL, 0, 0, NULL };
50 static struct dir rootpar = { SENTINEL, SENTINEL, NULL, 0,
51 NULL, NULL, NULL, NULL, NULL, 0, 0, NULL };
53 /* (from IM: Toolbox Essentials)
54 * dirFinderInfo (DInfo) fields:
56 * frRect 8 folder's window rectangle
58 * frLocation 4 folder's location in window
59 * frView 2 folder's view (default == closedView (256))
61 * extended dirFinderInfo (DXInfo) fields:
62 * frScroll 4 scroll position
63 * frOpenChain: 4 directory ID chain of open folders
64 * frScript: 1 script flag and code
65 * frXFlags: 1 reserved
66 * frComment: 2 comment ID
67 * frPutAway: 4 home directory ID
71 * redid did assignment for directories. now we use red-black trees.
76 const struct vol *vol;
86 if ( did == DIRDID_ROOT_PARENT ) {
88 rootpar.d_did = DIRDID_ROOT_PARENT;
89 rootpar.d_child = vol->v_dir;
94 while ( dir != SENTINEL ) {
95 if (dir->d_did == did)
96 return dir->d_name ? dir : NULL;
97 dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
103 /* rotate the tree to the left */
104 static void dir_leftrotate(vol, dir)
108 struct dir *right = dir->d_right;
110 /* whee. move the right's left tree into dir's right tree */
111 dir->d_right = right->d_left;
112 if (right->d_left != SENTINEL)
113 right->d_left->d_back = dir;
115 if (right != SENTINEL) {
116 right->d_back = dir->d_back;
120 if (!dir->d_back) /* no parent. move the right tree to the top. */
122 else if (dir == dir->d_back->d_left) /* we were on the left */
123 dir->d_back->d_left = right;
125 dir->d_back->d_right = right; /* we were on the right */
127 /* re-insert dir on the left tree */
134 /* rotate the tree to the right */
135 static void dir_rightrotate(vol, dir)
139 struct dir *left = dir->d_left;
141 /* whee. move the left's right tree into dir's left tree */
142 dir->d_left = left->d_right;
143 if (left->d_right != SENTINEL)
144 left->d_right->d_back = dir;
146 if (left != SENTINEL) {
147 left->d_back = dir->d_back;
151 if (!dir->d_back) /* no parent. move the left tree to the top. */
153 else if (dir == dir->d_back->d_right) /* we were on the right */
154 dir->d_back->d_right = left;
156 dir->d_back->d_left = left; /* we were on the left */
158 /* re-insert dir on the right tree */
163 /* recolor after a removal */
164 static struct dir *dir_rmrecolor(vol, dir)
170 while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
171 /* are we on the left tree? */
172 if (dir == dir->d_back->d_left) {
173 leaf = dir->d_back->d_right; /* get right side */
174 if (leaf->d_color == DIRTREE_COLOR_RED) {
175 /* we're red. we need to change to black. */
176 leaf->d_color = DIRTREE_COLOR_BLACK;
177 dir->d_back->d_color = DIRTREE_COLOR_RED;
178 dir_leftrotate(vol, dir->d_back);
179 leaf = dir->d_back->d_right;
182 /* right leaf has black end nodes */
183 if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
184 (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
185 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
186 dir = dir->d_back; /* ascend */
188 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
189 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
190 leaf->d_color = DIRTREE_COLOR_RED;
191 dir_rightrotate(vol, leaf);
192 leaf = dir->d_back->d_right;
194 leaf->d_color = dir->d_back->d_color;
195 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
196 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
197 dir_leftrotate(vol, dir->d_back);
200 } else { /* right tree */
201 leaf = dir->d_back->d_left; /* left tree */
202 if (leaf->d_color == DIRTREE_COLOR_RED) {
203 leaf->d_color = DIRTREE_COLOR_BLACK;
204 dir->d_back->d_color = DIRTREE_COLOR_RED;
205 dir_rightrotate(vol, dir->d_back);
206 leaf = dir->d_back->d_left;
209 /* left leaf has black end nodes */
210 if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
211 (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
212 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
213 dir = dir->d_back; /* ascend */
215 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
216 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
217 leaf->d_color = DIRTREE_COLOR_RED;
218 dir_leftrotate(vol, leaf);
219 leaf = dir->d_back->d_left;
221 leaf->d_color = dir->d_back->d_color;
222 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
223 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
224 dir_rightrotate(vol, dir->d_back);
229 dir->d_color = DIRTREE_COLOR_BLACK;
233 /* remove the node from the tree. this is just like insertion, but
234 * different. actually, it has to worry about a bunch of things that
235 * insertion doesn't care about. */
236 static void dir_remove( vol, dir )
241 struct ofork *of, *last;
242 struct dir *node, *leaf;
245 if (!dir || (dir == SENTINEL))
248 /* i'm not sure if it really helps to delete stuff. */
254 /* go searching for a node with at most one child */
255 if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
259 while (node->d_left != SENTINEL)
264 leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
267 leaf->d_back = node->d_back;
270 } else if (node == node->d_back->d_left) { /* left tree */
271 node->d_back->d_left = leaf;
273 node->d_back->d_right = leaf;
276 /* we want to free node, but we also want to free the data in dir.
277 * currently, that's d_name and the directory traversal bits.
278 * we just copy the necessary bits and then fix up all the
279 * various pointers to the directory. needless to say, there are
280 * a bunch of places that store the directory struct. */
282 struct dir save, *tmp;
284 memcpy(&save, dir, sizeof(save));
285 memcpy(dir, node, sizeof(struct dir));
287 /* restore the red-black bits */
288 dir->d_left = save.d_left;
289 dir->d_right = save.d_right;
290 dir->d_back = save.d_back;
291 dir->d_color = save.d_color;
293 if (node == vol->v_dir) {/* we may need to fix up this pointer */
295 rootpar.d_child = vol->v_dir;
297 /* if we aren't the root directory, we have parents and
298 * siblings to worry about */
299 if (dir->d_parent->d_child == node)
300 dir->d_parent->d_child = dir;
301 dir->d_next->d_prev = dir;
302 dir->d_prev->d_next = dir;
305 /* fix up children. */
309 tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
312 if (node == curdir) /* another pointer to fixup */
315 /* we also need to fix up oforks. bleah */
316 if ((of = dir->d_ofork)) {
317 last = of->of_d_prev;
320 of = (last == of) ? NULL : of->of_d_next;
324 /* set the node's d_name */
325 node->d_name = save.d_name;
328 if (node->d_color == DIRTREE_COLOR_BLACK)
329 dir_rmrecolor(vol, leaf);
336 static struct dir *dir_insert(vol, dir)
337 const struct vol *vol;
343 while (pdir->d_did != dir->d_did ) {
344 if ( pdir->d_did > dir->d_did ) {
345 if ( pdir->d_left == SENTINEL ) {
352 if ( pdir->d_right == SENTINEL ) {
357 pdir = pdir->d_right;
365 * attempt to extend the current dir. tree to include path
366 * as a side-effect, movecwd to that point and return the new dir
370 extenddir( vol, dir, path )
378 p = mtoupath(vol, path );
379 if ( stat( p, &st ) != 0 ) {
382 if (!S_ISDIR(st.st_mode)) {
386 if (( dir = adddir( vol, dir, path, strlen( path ), p, strlen(p),
391 if ( movecwd( vol, dir ) < 0 ) {
398 static int deletedir(char *dir)
400 char path[MAXPATHLEN + 1];
406 if ((len = strlen(dir)) > sizeof(path))
410 if ((dp = opendir(dir)) == NULL)
416 while ((de = readdir(dp))) {
417 /* skip this and previous directory */
418 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
421 strncpy(path + len, de->d_name, sizeof(path) - len);
422 if (stat(path, &st) == 0) {
423 if (S_ISDIR(st.st_mode)) {
424 if ((err = deletedir(path)) < 0) {
428 } else if (unlink(path) < 0) {
431 continue; /* somebody went and deleted it behind our backs. */
447 /* okay. the directory is empty. delete it. note: we already got rid
449 if (rmdir(dir) < 0) {
453 case ENOTEMPTY : /* should never happen */
454 return( AFPERR_DIRNEMPT );
457 return( AFPERR_ACCESS );
461 return( AFPERR_PARAM );
467 /* do a recursive copy. */
468 static int copydir(char *src, char *dst, int noadouble)
470 char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
477 /* doesn't exist or the path is too long. */
478 if (((slen = strlen(src)) > sizeof(spath) - 2) ||
479 ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
480 ((dp = opendir(src)) == NULL))
483 /* try to create the destination directory */
484 if (ad_mkdir(dst, DIRBITS | 0777) < 0) {
488 return( AFPERR_NOOBJ );
490 return( AFPERR_VLOCK );
493 return( AFPERR_ACCESS );
495 return( AFPERR_EXIST );
498 return( AFPERR_DFULL );
500 return( AFPERR_PARAM );
504 /* set things up to copy */
512 while ((de = readdir(dp))) {
513 /* skip this and previous directory */
514 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
517 strncpy(spath + slen, de->d_name, sizeof(spath) - slen);
518 if (stat(spath, &st) == 0) {
519 strncpy(dpath + dlen, de->d_name, sizeof(dpath) - dlen);
521 if (S_ISDIR(st.st_mode)) {
522 if ((err = copydir(spath, dpath, noadouble)) < 0)
524 } else if ((err = copyfile(spath, dpath, NULL, noadouble)) < 0) {
528 /* keep the same time stamp. */
529 ut.actime = ut.modtime = st.st_mtime;
535 /* keep the same time stamp. */
536 if (stat(src, &st) == 0) {
537 ut.actime = ut.modtime = st.st_mtime;
547 /* --- public functions follow --- */
549 /* NOTE: we start off with at least one node (the root directory). */
550 struct dir *dirinsert( vol, dir )
556 if ((node = dir_insert(vol, dir)))
559 /* recolor the tree. the current node is red. */
560 dir->d_color = DIRTREE_COLOR_RED;
562 /* parent of this node has to be black. if the parent node
563 * is red, then we have a grandparent. */
564 while ((dir != vol->v_root) &&
565 (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
566 /* are we on the left tree? */
567 if (dir->d_back == dir->d_back->d_back->d_left) {
568 node = dir->d_back->d_back->d_right; /* get the right node */
569 if (node->d_color == DIRTREE_COLOR_RED) {
570 /* we're red. we need to change to black. */
571 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
572 node->d_color = DIRTREE_COLOR_BLACK;
573 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
574 dir = dir->d_back->d_back; /* finished. go up. */
576 if (dir == dir->d_back->d_right) {
578 dir_leftrotate(vol, dir);
580 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
581 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
582 dir_rightrotate(vol, dir->d_back->d_back);
585 node = dir->d_back->d_back->d_left;
586 if (node->d_color == DIRTREE_COLOR_RED) {
587 /* we're red. we need to change to black. */
588 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
589 node->d_color = DIRTREE_COLOR_BLACK;
590 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
591 dir = dir->d_back->d_back; /* finished. ascend */
593 if (dir == dir->d_back->d_left) {
595 dir_rightrotate(vol, dir);
597 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
598 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
599 dir_leftrotate(vol, dir->d_back->d_back);
604 vol->v_root->d_color = DIRTREE_COLOR_BLACK;
608 /* free everything down. we don't bother to recolor as this is only
609 * called to free the entire tree */
613 if (!dir || (dir == SENTINEL))
616 if ( dir->d_left != SENTINEL ) {
617 dirfree( dir->d_left );
619 if ( dir->d_right != SENTINEL ) {
620 dirfree( dir->d_right );
623 if (dir != SENTINEL) {
630 struct dir *dirnew(const int len)
634 dir = (struct dir *) calloc(1, sizeof( struct dir ));
638 if ((dir->d_name = (char *) malloc(sizeof(char)*len)) == NULL) {
643 dir->d_left = dir->d_right = SENTINEL;
644 dir->d_next = dir->d_prev = dir;
649 /* XXX: this needs to be changed to handle path types */
651 cname( vol, dir, cpath )
652 const struct vol *vol;
657 static char path[ MAXPATHLEN + 1];
663 if ( *data++ != 2 ) { /* path type */
666 len = (unsigned char) *data++;
672 if ( !extend && movecwd( vol, dir ) < 0 ) {
678 if ( *data == '\0' ) {
683 while ( *data == '\0' && len > 0 ) {
684 if ( dir->d_parent == NULL ) {
692 /* would this be faster with strlen + strncpy? */
694 while ( *data != '\0' && len > 0 ) {
699 /* short cut bits by chopping off a trailing \0. this also
700 makes the traversal happy w/ filenames at the end of the
707 * Dung Nguyen <ntd@adb.fr>
709 * AFPD cannot handle paths with "::" if the "::" notation is
710 * not at the beginning of the path. The following path will not
711 * be interpreted correctly:
713 * :a:b:::c: (directory c at the same level as directory a) */
721 if ( p != path ) { /* we got something */
725 if ( strcasecmp( cdir->d_name, path ) == 0 ) {
728 cdir = (cdir == dir->d_child->d_prev) ? NULL :
731 if ( cdir == NULL ) {
733 if ( movecwd( vol, dir ) < 0 ) {
736 cdir = extenddir( vol, dir, path );
740 cdir = extenddir( vol, dir, path );
743 if ( cdir == NULL ) {
757 * Move curdir to dir, with a possible chdir()
759 int movecwd( vol, dir)
760 const struct vol *vol;
763 char path[MAXPATHLEN + 1];
768 if ( dir == curdir ) {
771 if ( dir->d_did == DIRDID_ROOT_PARENT) {
775 p = path + sizeof(path) - 1;
778 for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
780 u = mtoupath(vol, d->d_name );
787 n = strlen( vol->v_path );
789 strncpy( p, vol->v_path, n );
791 if ( chdir( p ) < 0 ) {
798 int getdirparams(vol, bitmap, upath, dir, st, buf, buflen )
799 const struct vol *vol;
809 char *data, *nameoff = NULL;
812 int bit = 0, isad = 1;
819 memset(&ad, 0, sizeof(ad));
822 save_uidgid ( uidgid );
826 if ( ad_open( upath, ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY,
827 DIRBITS | 0777, &ad) < 0 ) {
832 while ( bitmap != 0 ) {
833 while (( bitmap & 1 ) == 0 ) {
841 ad_getattr(&ad, &ashort);
842 } else if (*upath == '.' && strcmp(upath, ".") &&
843 strcmp(upath, "..")) {
844 ashort = htons(ATTRBIT_INVISIBLE);
847 memcpy( data, &ashort, sizeof( ashort ));
848 data += sizeof( ashort );
852 if ( dir->d_did == DIRDID_ROOT) {
853 aint = DIRDID_ROOT_PARENT;
854 } else if (dir->d_did == DIRDID_ROOT_PARENT) {
857 aint = dir->d_parent->d_did;
859 memcpy( data, &aint, sizeof( aint ));
860 data += sizeof( aint );
864 if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
865 aint = AD_DATE_FROM_UNIX(st->st_mtime);
866 memcpy( data, &aint, sizeof( aint ));
867 data += sizeof( aint );
871 aint = AD_DATE_FROM_UNIX(st->st_mtime);
872 memcpy( data, &aint, sizeof( aint ));
873 data += sizeof( aint );
877 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
878 aint = AD_DATE_START;
879 memcpy( data, &aint, sizeof( aint ));
880 data += sizeof( aint );
885 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
886 } else { /* no appledouble */
887 memset( data, 0, 32 );
888 /* set default view -- this also gets done in ad_open() */
889 ashort = htons(FINDERINFO_CLOSEDVIEW);
890 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
892 /* dot files are by default invisible */
893 if (*upath == '.' && strcmp(upath, ".") &&
894 strcmp(upath, "..")) {
895 ashort = htons(FINDERINFO_INVISIBLE);
896 memcpy(data + FINDERINFO_FRFLAGOFF,
897 &ashort, sizeof(ashort));
904 if (dir->d_name) /* root of parent can have a null name */
907 memset(data, 0, sizeof(u_int16_t));
908 data += sizeof( u_int16_t );
912 memset(data, 0, sizeof(u_int16_t));
913 data += sizeof( u_int16_t );
917 memcpy( data, &dir->d_did, sizeof( aint ));
918 data += sizeof( aint );
921 case DIRPBIT_OFFCNT :
923 /* this needs to handle current directory access rights */
924 if ((dp = opendir( upath ))) {
925 while (( de = readdir( dp )) != NULL ) {
926 if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
929 if (!validupath(vol, de->d_name))
932 /* now check against too long a filename */
933 if (strlen(utompath(vol, de->d_name)) > MACFILELEN)
940 ashort = htons( ashort );
941 memcpy( data, &ashort, sizeof( ashort ));
942 data += sizeof( ashort );
947 memcpy( data, &aint, sizeof( aint ));
948 data += sizeof( aint );
953 memcpy( data, &aint, sizeof( aint ));
954 data += sizeof( aint );
957 case DIRPBIT_ACCESS :
959 #ifndef SENDFILE_FLAVOR_LINUX /* ignore this section if it's linux */
961 accessmode( upath, &ma, dir );
963 #endif SENDFILE_FLAVOR_LINUX
964 #ifdef AFS /* If only AFS defined, access() works only for AFS filesystems */
965 afsmode( upath, &ma, dir );
967 *data++ = ma.ma_user;
968 *data++ = ma.ma_world;
969 *data++ = ma.ma_group;
970 *data++ = ma.ma_owner;
973 /* Client has requested the ProDOS information block.
974 Just pass back the same basic block for all
975 directories. <shirsch@ibm.net> */
976 case DIRPBIT_PDINFO : /* ProDOS Info Block */
979 ashort = htons( 0x0200 );
980 memcpy( data, &ashort, sizeof( ashort ));
981 data += sizeof( ashort );
982 memset( data, 0, sizeof( ashort ));
983 data += sizeof( ashort );
988 ad_close( &ad, ADFLAGS_HF );
991 restore_uidgid ( uidgid );
993 return( AFPERR_BITMAP );
999 ashort = htons( data - buf );
1000 memcpy( nameoff, &ashort, sizeof( ashort ));
1002 if ((aint = strlen( dir->d_name )) > MACFILELEN)
1006 memcpy( data, dir->d_name, aint );
1010 ad_close( &ad, ADFLAGS_HF );
1012 *buflen = data - buf;
1016 int afp_setdirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1019 int ibuflen, *rbuflen;
1024 u_int16_t vid, bitmap;
1030 memcpy( &vid, ibuf, sizeof( vid ));
1031 ibuf += sizeof( vid );
1033 if (( vol = getvolbyvid( vid )) == NULL ) {
1034 return( AFPERR_PARAM );
1037 if (vol->v_flags & AFPVOL_RO)
1038 return AFPERR_VLOCK;
1040 memcpy( &did, ibuf, sizeof( did ));
1041 ibuf += sizeof( int );
1043 if (( dir = dirsearch( vol, did )) == NULL ) {
1044 return( AFPERR_NOOBJ );
1047 memcpy( &bitmap, ibuf, sizeof( bitmap ));
1048 bitmap = ntohs( bitmap );
1049 ibuf += sizeof( bitmap );
1051 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1052 return( AFPERR_NOOBJ );
1056 * If ibuf is odd, make it even.
1058 if ((u_long)ibuf & 1 ) {
1062 if (( rc = setdirparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
1063 setvoltime(obj, vol );
1068 int setdirparams(vol, path, bitmap, buf )
1069 const struct vol *vol;
1077 int bit = 0, aint, isad = 1;
1078 u_int16_t ashort, bshort;
1084 upath = mtoupath(vol, path);
1085 memset(&ad, 0, sizeof(ad));
1087 save_uidgid ( uidgid );
1089 if (ad_open( upath, vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
1090 O_RDWR|O_CREAT, 0666, &ad) < 0) {
1092 * Check to see what we're trying to set. If it's anything
1093 * but ACCESS, UID, or GID, give an error. If it's any of those
1094 * three, we don't need the ad to be open, so just continue.
1096 * note: we also don't need to worry about mdate. also, be quiet
1097 * if we're using the noadouble option.
1099 if (!vol_noadouble(vol) && (bitmap &
1100 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
1101 (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
1103 restore_uidgid ( uidgid );
1105 return AFPERR_ACCESS;
1111 * Check to see if a create was necessary. If it was, we'll want
1112 * to set our name, etc.
1114 if ( ad_getoflags( &ad, ADFLAGS_HF ) & O_CREAT ) {
1115 ad_setentrylen( &ad, ADEID_NAME, strlen( curdir->d_name ));
1116 memcpy( ad_entry( &ad, ADEID_NAME ), curdir->d_name,
1117 ad_getentrylen( &ad, ADEID_NAME ));
1121 while ( bitmap != 0 ) {
1122 while (( bitmap & 1 ) == 0 ) {
1130 memcpy( &ashort, buf, sizeof( ashort ));
1131 ad_getattr(&ad, &bshort);
1132 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
1133 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
1137 ad_setattr(&ad, bshort);
1139 buf += sizeof( ashort );
1142 case DIRPBIT_CDATE :
1144 memcpy(&aint, buf, sizeof(aint));
1145 ad_setdate(&ad, AD_DATE_CREATE, aint);
1147 buf += sizeof( aint );
1150 case DIRPBIT_MDATE :
1151 memcpy(&aint, buf, sizeof(aint));
1153 ad_setdate(&ad, AD_DATE_MODIFY, aint);
1154 ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
1156 buf += sizeof( aint );
1159 case DIRPBIT_BDATE :
1161 memcpy(&aint, buf, sizeof(aint));
1162 ad_setdate(&ad, AD_DATE_BACKUP, aint);
1164 buf += sizeof( aint );
1167 case DIRPBIT_FINFO :
1169 * Alright, we admit it, this is *really* sick!
1170 * The 4 bytes that we don't copy, when we're dealing
1171 * with the root of a volume, are the directory's
1172 * location information. This eliminates that annoying
1173 * behavior one sees when mounting above another mount
1177 if ( curdir->d_did == DIRDID_ROOT ) {
1178 memcpy( ad_entry( &ad, ADEID_FINDERI ), buf, 10 );
1179 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, buf + 14, 18 );
1181 memcpy( ad_entry( &ad, ADEID_FINDERI ), buf, 32 );
1187 case DIRPBIT_UID : /* What kind of loser mounts as root? */
1188 memcpy( &aint, buf, sizeof(aint));
1189 buf += sizeof( aint );
1190 if ( (curdir->d_did == DIRDID_ROOT) &&
1191 (setdeskowner( aint, -1 ) < 0)) {
1195 err = AFPERR_ACCESS;
1196 goto setdirparam_done;
1200 goto setdirparam_done;
1203 syslog( LOG_ERR, "setdirparam: setdeskowner: %m" );
1206 goto setdirparam_done;
1211 if ( setdirowner( aint, -1, vol_noadouble(vol) ) < 0 ) {
1215 err = AFPERR_ACCESS;
1216 goto setdirparam_done;
1220 goto setdirparam_done;
1223 syslog( LOG_ERR, "setdirparam: setdirowner: %m" );
1230 memcpy( &aint, buf, sizeof( aint ));
1231 buf += sizeof( aint );
1232 if (curdir->d_did == DIRDID_ROOT)
1233 setdeskowner( -1, aint );
1235 #if 0 /* don't error if we can't set the desktop owner. */
1239 err = AFPERR_ACCESS;
1240 goto setdirparam_done;
1244 goto setdirparam_done;
1247 syslog( LOG_ERR, "setdirparam: setdeskowner: %m" );
1250 goto setdirparam_done;
1256 if ( setdirowner( -1, aint, vol_noadouble(vol) ) < 0 ) {
1260 err = AFPERR_ACCESS;
1261 goto setdirparam_done;
1265 goto setdirparam_done;
1268 syslog( LOG_ERR, "setdirparam: setdirowner: %m" );
1274 case DIRPBIT_ACCESS :
1275 ma.ma_user = *buf++;
1276 ma.ma_world = *buf++;
1277 ma.ma_group = *buf++;
1278 ma.ma_owner = *buf++;
1280 if (curdir->d_did == DIRDID_ROOT)
1281 setdeskmode(mtoumode( &ma ));
1282 #if 0 /* don't error if we can't set the desktop mode */
1286 err = AFPERR_ACCESS;
1287 goto setdirparam_done;
1290 goto setdirparam_done;
1292 syslog( LOG_ERR, "setdirparam: setdeskmode: %m" );
1295 goto setdirparam_done;
1300 if ( setdirmode( mtoumode( &ma ), vol_noadouble(vol),
1301 (vol->v_flags & AFPVOL_DROPBOX)) < 0 ) {
1305 err = AFPERR_ACCESS;
1306 goto setdirparam_done;
1309 goto setdirparam_done;
1311 syslog( LOG_ERR, "setdirparam: setdirmode: %m" );
1313 goto setdirparam_done;
1318 /* Ignore what the client thinks we should do to the
1319 ProDOS information block. Skip over the data and
1320 report nothing amiss. <shirsch@ibm.net> */
1321 case DIRPBIT_PDINFO :
1326 err = AFPERR_BITMAP;
1327 goto setdirparam_done;
1338 ad_flush( &ad, ADFLAGS_HF );
1339 ad_close( &ad, ADFLAGS_HF );
1343 restore_uidgid ( uidgid );
1348 int afp_createdir(obj, ibuf, ibuflen, rbuf, rbuflen )
1351 int ibuflen, *rbuflen;
1367 memcpy( &vid, ibuf, sizeof( vid ));
1368 ibuf += sizeof( vid );
1369 if (( vol = getvolbyvid( vid )) == NULL ) {
1370 return( AFPERR_PARAM );
1373 if (vol->v_flags & AFPVOL_RO)
1374 return AFPERR_VLOCK;
1376 memcpy( &did, ibuf, sizeof( did ));
1377 ibuf += sizeof( did );
1378 if (( dir = dirsearch( vol, did )) == NULL ) {
1379 return( AFPERR_NOOBJ );
1382 if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1383 return( AFPERR_NOOBJ );
1386 /* check for illegal bits */
1387 if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
1388 strpbrk(path, MSWINDOWS_BADCHARS))
1389 return AFPERR_PARAM;
1391 upath = mtoupath(vol, path);
1393 if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
1394 return AFPERR_PARAM;
1396 if (!validupath(vol, upath))
1397 return AFPERR_EXIST;
1400 save_uidgid ( uidgid );
1404 if ( ad_mkdir( upath, DIRBITS | 0777 ) < 0 ) {
1406 restore_uidgid ( uidgid );
1410 return( AFPERR_NOOBJ );
1412 return( AFPERR_VLOCK );
1414 return( AFPERR_ACCESS );
1416 return( AFPERR_EXIST );
1419 return( AFPERR_DFULL );
1421 return( AFPERR_PARAM );
1425 if (stat(upath, &st) < 0) {
1427 restore_uidgid ( uidgid );
1432 if ((dir = adddir( vol, curdir, path, strlen( path ), upath,
1433 strlen(upath), &st)) == NULL) {
1435 restore_uidgid ( uidgid );
1440 if ( movecwd( vol, dir ) < 0 ) {
1442 restore_uidgid ( uidgid );
1444 return( AFPERR_PARAM );
1447 memset(&ad, 0, sizeof(ad));
1448 if (ad_open( "", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
1449 O_RDWR|O_CREAT, 0666, &ad ) < 0) {
1450 if (vol_noadouble(vol))
1451 goto createdir_done;
1453 restore_uidgid ( uidgid );
1455 return( AFPERR_ACCESS );
1458 ad_setentrylen( &ad, ADEID_NAME, strlen( path ));
1459 memcpy( ad_entry( &ad, ADEID_NAME ), path,
1460 ad_getentrylen( &ad, ADEID_NAME ));
1461 ad_flush( &ad, ADFLAGS_HF );
1462 ad_close( &ad, ADFLAGS_HF );
1465 memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
1466 *rbuflen = sizeof( u_int32_t );
1467 setvoltime(obj, vol );
1469 restore_uidgid ( uidgid );
1475 int renamedir(src, dst, dir, newparent, newname, noadouble)
1476 char *src, *dst, *newname;
1477 struct dir *dir, *newparent;
1478 const int noadouble;
1485 /* existence check moved to afp_moveandrename */
1486 if ( rename( src, dst ) < 0 ) {
1489 return( AFPERR_NOOBJ );
1491 return( AFPERR_ACCESS );
1493 return AFPERR_VLOCK;
1495 /* tried to move directory into a subdirectory of itself */
1496 return AFPERR_CANTMOVE;
1498 /* this needs to copy and delete. bleah. that means we have
1499 * to deal with entire directory hierarchies. */
1500 if ((err = copydir(src, dst, noadouble)) < 0) {
1504 if ((err = deletedir(src)) < 0)
1508 return( AFPERR_PARAM );
1512 memset(&ad, 0, sizeof(ad));
1513 if ( ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad) < 0 ) {
1517 len = strlen(newname);
1518 goto renamedir_done;
1520 return( AFPERR_NOOBJ );
1522 return( AFPERR_ACCESS );
1524 return( AFPERR_PARAM );
1527 len = strlen( newname );
1528 ad_setentrylen( &ad, ADEID_NAME, len );
1529 memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
1530 ad_flush( &ad, ADFLAGS_HF );
1531 ad_close( &ad, ADFLAGS_HF );
1534 if ((buf = (char *) realloc( dir->d_name, len + 1 )) == NULL ) {
1535 syslog( LOG_ERR, "renamedir: realloc: %m" );
1539 strcpy( dir->d_name, newname );
1541 if (( parent = dir->d_parent ) == NULL ) {
1544 if ( parent == newparent ) {
1548 /* detach from old parent and add to new one. */
1549 dirchildremove(parent, dir);
1550 dir->d_parent = newparent;
1551 dirchildadd(newparent, dir);
1555 #define DOT_APPLEDOUBLE_LEN 13
1556 /* delete an empty directory */
1557 int deletecurdir( vol, path, pathlen )
1558 const struct vol *vol;
1570 if ( curdir->d_parent == NULL ) {
1571 return( AFPERR_ACCESS );
1574 if ( curdir->d_child != NULL ) {
1575 return( AFPERR_DIRNEMPT );
1581 save_uidgid ( uidgid );
1585 /* delete stray .AppleDouble files. this happens to get .Parent files
1587 if ((dp = opendir(".AppleDouble"))) {
1588 strcpy(path, ".AppleDouble/");
1589 while ((de = readdir(dp))) {
1590 /* skip this and previous directory */
1591 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1594 /* bail if the file exists in the current directory.
1595 * note: this will not fail with dangling symlinks */
1596 if (stat(de->d_name, &st) == 0) {
1599 restore_uidgid ( uidgid );
1601 return AFPERR_DIRNEMPT;
1604 strcpy(path + DOT_APPLEDOUBLE_LEN, de->d_name);
1605 if (unlink(path) < 0) {
1611 restore_uidgid ( uidgid );
1613 return( AFPERR_ACCESS );
1616 restore_uidgid ( uidgid );
1618 return AFPERR_VLOCK;
1623 restore_uidgid ( uidgid );
1625 return( AFPERR_PARAM );
1632 if ( rmdir( ".AppleDouble" ) < 0 ) {
1638 restore_uidgid ( uidgid );
1640 return( AFPERR_DIRNEMPT );
1643 restore_uidgid ( uidgid );
1645 return AFPERR_VLOCK;
1649 restore_uidgid ( uidgid );
1651 return( AFPERR_ACCESS );
1654 restore_uidgid ( uidgid );
1656 return( AFPERR_PARAM );
1660 /* now get rid of dangling symlinks */
1661 if ((dp = opendir("."))) {
1662 while ((de = readdir(dp))) {
1663 /* skip this and previous directory */
1664 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1667 /* bail if it's not a symlink */
1668 if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
1670 restore_uidgid ( uidgid );
1672 return AFPERR_DIRNEMPT;
1675 if (unlink(de->d_name) < 0) {
1680 restore_uidgid ( uidgid );
1682 return( AFPERR_ACCESS );
1685 restore_uidgid ( uidgid );
1687 return AFPERR_VLOCK;
1692 restore_uidgid ( uidgid );
1694 return( AFPERR_PARAM );
1701 if ( movecwd( vol, curdir->d_parent ) < 0 ) {
1703 restore_uidgid ( uidgid );
1705 return( AFPERR_NOOBJ );
1708 if ( rmdir(mtoupath(vol, fdir->d_name)) < 0 ) {
1712 restore_uidgid ( uidgid );
1714 return( AFPERR_NOOBJ );
1717 restore_uidgid ( uidgid );
1719 return( AFPERR_DIRNEMPT );
1723 restore_uidgid ( uidgid );
1725 return( AFPERR_ACCESS );
1728 restore_uidgid ( uidgid );
1730 return AFPERR_VLOCK;
1733 restore_uidgid ( uidgid );
1735 return( AFPERR_PARAM );
1739 dirchildremove(curdir, fdir);
1740 #if AD_VERSION > AD_VERSION1
1741 cnid_delete(vol->v_db, fdir->d_did);
1743 dir_remove( vol, fdir );
1746 restore_uidgid ( uidgid );
1751 int afp_mapid(obj, ibuf, ibuflen, rbuf, rbuflen )
1754 int ibuflen, *rbuflen;
1763 sfunc = (unsigned char) *ibuf++;
1764 memcpy( &id, ibuf, sizeof( id ));
1769 if (( pw = getpwuid( id )) == NULL ) {
1771 return( AFPERR_NOITEM );
1777 if (( gr = (struct group *)getgrgid( id )) == NULL ) {
1779 return( AFPERR_NOITEM );
1786 return( AFPERR_PARAM );
1789 len = strlen( name );
1798 memcpy( rbuf, name, len );
1804 int afp_mapname(obj, ibuf, ibuflen, rbuf, rbuflen )
1807 int ibuflen, *rbuflen;
1815 sfunc = (unsigned char) *ibuf++;
1816 len = (unsigned char) *ibuf++;
1822 if (( pw = (struct passwd *)getpwnam( ibuf )) == NULL ) {
1824 return( AFPERR_NOITEM );
1830 if (( gr = (struct group *)getgrnam( ibuf )) == NULL ) {
1832 return( AFPERR_NOITEM );
1838 return( AFPERR_PARAM );
1844 memcpy( rbuf, &id, sizeof( id ));
1845 *rbuflen = sizeof( id );
1849 /* variable DID support */
1850 int afp_closedir(obj, ibuf, ibuflen, rbuf, rbuflen )
1853 int ibuflen, *rbuflen;
1864 /* do nothing as dids are static for the life of the process. */
1868 memcpy(&vid, ibuf, sizeof( vid ));
1869 ibuf += sizeof( vid );
1870 if (( vol = getvolbyvid( vid )) == NULL ) {
1871 return( AFPERR_PARAM );
1874 memcpy( &did, ibuf, sizeof( did ));
1875 ibuf += sizeof( did );
1876 if (( dir = dirsearch( vol, did )) == NULL ) {
1877 return( AFPERR_PARAM );
1880 /* dir_remove -- deletedid */
1886 /* did creation gets done automatically */
1887 int afp_opendir(obj, ibuf, ibuflen, rbuf, rbuflen )
1890 int ibuflen, *rbuflen;
1893 struct dir *dir, *parentdir;
1905 memcpy(&vid, ibuf, sizeof(vid));
1906 ibuf += sizeof( vid );
1908 if (( vol = getvolbyvid( vid )) == NULL ) {
1909 return( AFPERR_PARAM );
1912 memcpy(&did, ibuf, sizeof(did));
1913 ibuf += sizeof(did);
1915 if (( parentdir = dirsearch( vol, did )) == NULL ) {
1916 return( AFPERR_NOOBJ );
1919 if (( path = cname( vol, parentdir, &ibuf )) == NULL ) {
1920 return( AFPERR_NOOBJ );
1923 /* see if we already have the directory. */
1924 upath = mtoupath(vol, path);
1925 if ( stat( upath, &st ) < 0 ) {
1926 return( AFPERR_NOOBJ );
1929 dir = parentdir->d_child;
1931 if (strdiacasecmp(dir->d_name, path) == 0) {
1932 memcpy(rbuf, &dir->d_did, sizeof(dir->d_did));
1933 *rbuflen = sizeof(dir->d_did);
1936 dir = (dir == parentdir->d_child->d_prev) ? NULL : dir->d_next;
1940 save_uidgid ( uidgid );
1944 /* we don't already have a did. add one in. */
1945 if ((dir = adddir(vol, parentdir, path, strlen(path),
1946 upath, strlen(upath), &st)) == NULL) {
1948 restore_uidgid ( uidgid );
1953 memcpy(rbuf, &dir->d_did, sizeof(dir->d_did));
1954 *rbuflen = sizeof(dir->d_did);
1956 restore_uidgid ( uidgid );