]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/directory.c
BIG commit to improve code style using astyle as well as fix up CNID DB
[netatalk.git] / etc / afpd / directory.c
1 /*
2  * $Id: directory.c,v 1.20 2001-12-03 05:03:38 jmarcus Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  *
7  * 19 jan 2000 implemented red-black trees for directory lookups
8  * (asun@cobalt.com).
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif /* HAVE_CONFIG_H */
14
15 #include <sys/syslog.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <errno.h>
19 #include <sys/time.h>
20 #include <sys/param.h>
21 #include <netatalk/endian.h>
22 #include <atalk/adouble.h>
23 #include <atalk/afp.h>
24 #include <atalk/util.h>
25 #ifdef CNID_DB
26 #include <atalk/cnid.h>
27 #endif /* CNID_DB */
28 #include <utime.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <dirent.h>
32 #ifdef HAVE_FCNTL_H
33 #include <fcntl.h>
34 #endif /* HAVE_FCNTL_H */
35 #include <grp.h>
36 #include <pwd.h>
37
38 /* STDC check */
39 #if STDC_HEADERS
40 #include <string.h>
41 #else /* STDC_HEADERS */
42 #ifndef HAVE_STRCHR
43 #define strchr index
44 #define strrchr index
45 #endif /* HAVE_STRCHR */
46 char *strchr (), *strrchr ();
47 #ifndef HAVE_MEMCPY
48 #define memcpy(d,s,n) bcopy ((s), (d), (n))
49 #define memmove(d,s,n) bcopy ((s), (d), (n))
50 #endif /* ! HAVE_MEMCPY */
51 #endif /* STDC_HEADERS */
52
53 #include "directory.h"
54 #include "desktop.h"
55 #include "volume.h"
56 #include "fork.h"
57 #include "file.h"
58 #include "globals.h"
59 #include "unix.h"
60
61 #ifdef FORCE_UIDGID
62 #include "uid.h"
63 #endif /* FORCE_UIDGID */
64
65 struct dir      *curdir;
66
67 #define SENTINEL (&sentinel)
68 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, DIRTREE_COLOR_BLACK,
69                                  NULL, NULL, NULL, NULL, NULL, 0, 0, NULL };
70 static struct dir       rootpar = { SENTINEL, SENTINEL, NULL, 0,
71                                 NULL, NULL, NULL, NULL, NULL, 0, 0, NULL };
72
73 /* (from IM: Toolbox Essentials)
74  * dirFinderInfo (DInfo) fields:
75  * field        bytes
76  * frRect       8    folder's window rectangle
77  * frFlags      2    flags
78  * frLocation   4    folder's location in window
79  * frView       2    folder's view (default == closedView (256))
80  *
81  * extended dirFinderInfo (DXInfo) fields:
82  * frScroll     4    scroll position
83  * frOpenChain: 4    directory ID chain of open folders
84  * frScript:    1    script flag and code
85  * frXFlags:    1    reserved
86  * frComment:   2    comment ID
87  * frPutAway:   4    home directory ID
88  */
89
90 /*
91  * redid did assignment for directories. now we use red-black trees.
92  * how exciting.
93  */
94 struct dir *
95             dirsearch( vol, did )
96             const struct vol    *vol;
97 u_int32_t       did;
98 {
99     struct dir  *dir;
100
101
102     /* check for 0 did */
103     if (!did)
104         return NULL;
105
106     if ( did == DIRDID_ROOT_PARENT ) {
107         if (!rootpar.d_did)
108             rootpar.d_did = DIRDID_ROOT_PARENT;
109         rootpar.d_child = vol->v_dir;
110         return( &rootpar );
111     }
112
113     dir = vol->v_root;
114     while ( dir != SENTINEL ) {
115         if (dir->d_did == did)
116             return dir->d_name ? dir : NULL;
117         dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
118     }
119     return NULL;
120 }
121
122
123 /* rotate the tree to the left */
124 static void dir_leftrotate(vol, dir)
125 struct vol *vol;
126 struct dir *dir;
127 {
128     struct dir *right = dir->d_right;
129
130     /* whee. move the right's left tree into dir's right tree */
131     dir->d_right = right->d_left;
132     if (right->d_left != SENTINEL)
133         right->d_left->d_back = dir;
134
135     if (right != SENTINEL) {
136         right->d_back = dir->d_back;
137         right->d_left = dir;
138     }
139
140     if (!dir->d_back) /* no parent. move the right tree to the top. */
141         vol->v_root = right;
142     else if (dir == dir->d_back->d_left) /* we were on the left */
143         dir->d_back->d_left = right;
144     else
145         dir->d_back->d_right = right; /* we were on the right */
146
147     /* re-insert dir on the left tree */
148     if (dir != SENTINEL)
149         dir->d_back = right;
150 }
151
152
153
154 /* rotate the tree to the right */
155 static void dir_rightrotate(vol, dir)
156 struct vol *vol;
157 struct dir *dir;
158 {
159     struct dir *left = dir->d_left;
160
161     /* whee. move the left's right tree into dir's left tree */
162     dir->d_left = left->d_right;
163     if (left->d_right != SENTINEL)
164         left->d_right->d_back = dir;
165
166     if (left != SENTINEL) {
167         left->d_back = dir->d_back;
168         left->d_right = dir;
169     }
170
171     if (!dir->d_back) /* no parent. move the left tree to the top. */
172         vol->v_root = left;
173     else if (dir == dir->d_back->d_right) /* we were on the right */
174         dir->d_back->d_right = left;
175     else
176         dir->d_back->d_left = left; /* we were on the left */
177
178     /* re-insert dir on the right tree */
179     if (dir != SENTINEL)
180         dir->d_back = left;
181 }
182
183 #if 0
184 /* recolor after a removal */
185 static struct dir *dir_rmrecolor(vol, dir)
186             struct vol *vol;
187 struct dir *dir;
188 {
189     struct dir *leaf;
190
191     while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
192         /* are we on the left tree? */
193         if (dir == dir->d_back->d_left) {
194             leaf = dir->d_back->d_right; /* get right side */
195             if (leaf->d_color == DIRTREE_COLOR_RED) {
196                 /* we're red. we need to change to black. */
197                 leaf->d_color = DIRTREE_COLOR_BLACK;
198                 dir->d_back->d_color = DIRTREE_COLOR_RED;
199                 dir_leftrotate(vol, dir->d_back);
200                 leaf = dir->d_back->d_right;
201             }
202
203             /* right leaf has black end nodes */
204             if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
205                     (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
206                 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
207                 dir = dir->d_back; /* ascend */
208             } else {
209                 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
210                     leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
211                     leaf->d_color = DIRTREE_COLOR_RED;
212                     dir_rightrotate(vol, leaf);
213                     leaf = dir->d_back->d_right;
214                 }
215                 leaf->d_color = dir->d_back->d_color;
216                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
217                 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
218                 dir_leftrotate(vol, dir->d_back);
219                 dir = vol->v_root;
220             }
221         } else { /* right tree */
222             leaf = dir->d_back->d_left; /* left tree */
223             if (leaf->d_color == DIRTREE_COLOR_RED) {
224                 leaf->d_color = DIRTREE_COLOR_BLACK;
225                 dir->d_back->d_color = DIRTREE_COLOR_RED;
226                 dir_rightrotate(vol, dir->d_back);
227                 leaf = dir->d_back->d_left;
228             }
229
230             /* left leaf has black end nodes */
231             if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
232                     (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
233                 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
234                 dir = dir->d_back; /* ascend */
235             } else {
236                 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
237                     leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
238                     leaf->d_color = DIRTREE_COLOR_RED;
239                     dir_leftrotate(vol, leaf);
240                     leaf = dir->d_back->d_left;
241                 }
242                 leaf->d_color = dir->d_back->d_color;
243                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
244                 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
245                 dir_rightrotate(vol, dir->d_back);
246                 dir = vol->v_root;
247             }
248         }
249     }
250     dir->d_color = DIRTREE_COLOR_BLACK;
251
252     return dir;
253 }
254 #endif /* 0 */
255
256
257 /* remove the node from the tree. this is just like insertion, but
258  * different. actually, it has to worry about a bunch of things that
259  * insertion doesn't care about. */
260 static void dir_remove( vol, dir )
261 struct vol      *vol;
262 struct dir      *dir;
263 {
264 #ifdef REMOVE_NODES
265     struct ofork *of, *last;
266     struct dir *node, *leaf;
267 #endif /* REMOVE_NODES */
268
269     if (!dir || (dir == SENTINEL))
270         return;
271
272     /* i'm not sure if it really helps to delete stuff. */
273 #ifndef REMOVE_NODES 
274     free(dir->d_name);
275     dir->d_name = NULL;
276 #else /* ! REMOVE_NODES */
277
278     /* go searching for a node with at most one child */
279     if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
280         node = dir;
281     } else {
282         node = dir->d_right;
283         while (node->d_left != SENTINEL)
284             node = node->d_left;
285     }
286
287     /* get that child */
288     leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
289
290     /* detach node */
291     leaf->d_back = node->d_back;
292     if (!node->d_back) {
293         vol->v_root = leaf;
294     } else if (node == node->d_back->d_left) { /* left tree */
295         node->d_back->d_left = leaf;
296     } else {
297         node->d_back->d_right = leaf;
298     }
299
300     /* we want to free node, but we also want to free the data in dir.
301     * currently, that's d_name and the directory traversal bits.
302     * we just copy the necessary bits and then fix up all the
303     * various pointers to the directory. needless to say, there are
304     * a bunch of places that store the directory struct. */
305     if (node != dir) {
306         struct dir save, *tmp;
307
308         memcpy(&save, dir, sizeof(save));
309         memcpy(dir, node, sizeof(struct dir));
310
311         /* restore the red-black bits */
312         dir->d_left = save.d_left;
313         dir->d_right = save.d_right;
314         dir->d_back = save.d_back;
315         dir->d_color = save.d_color;
316
317         if (node == vol->v_dir) {/* we may need to fix up this pointer */
318             vol->v_dir = dir;
319             rootpar.d_child = vol->v_dir;
320         } else {
321             /* if we aren't the root directory, we have parents and
322             * siblings to worry about */
323             if (dir->d_parent->d_child == node)
324                 dir->d_parent->d_child = dir;
325             dir->d_next->d_prev = dir;
326             dir->d_prev->d_next = dir;
327         }
328
329         /* fix up children. */
330         tmp = dir->d_child;
331         while (tmp) {
332             tmp->d_parent = dir;
333             tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
334         }
335
336         if (node == curdir) /* another pointer to fixup */
337             curdir = dir;
338
339         /* we also need to fix up oforks. bleah */
340         if ((of = dir->d_ofork)) {
341             last = of->of_d_prev;
342             while (of) {
343                 of->of_dir = dir;
344                 of = (last == of) ? NULL : of->of_d_next;
345             }
346         }
347
348         /* set the node's d_name */
349         node->d_name = save.d_name;
350     }
351
352     if (node->d_color == DIRTREE_COLOR_BLACK)
353         dir_rmrecolor(vol, leaf);
354     free(node->d_name);
355     free(node);
356 #endif /* ! REMOVE_NODES */
357 }
358
359
360 static struct dir *dir_insert(vol, dir)
361             const struct vol *vol;
362 struct dir *dir;
363 {
364     struct dir  *pdir;
365
366     pdir = vol->v_root;
367     while (pdir->d_did != dir->d_did ) {
368         if ( pdir->d_did > dir->d_did ) {
369             if ( pdir->d_left == SENTINEL ) {
370                 pdir->d_left = dir;
371                 dir->d_back = pdir;
372                 return NULL;
373             }
374             pdir = pdir->d_left;
375         } else {
376             if ( pdir->d_right == SENTINEL ) {
377                 pdir->d_right = dir;
378                 dir->d_back = pdir;
379                 return NULL;
380             }
381             pdir = pdir->d_right;
382         }
383     }
384     return pdir;
385 }
386
387
388 /*
389  * attempt to extend the current dir. tree to include path
390  * as a side-effect, movecwd to that point and return the new dir
391  */
392
393 static struct dir *
394             extenddir( vol, dir, path )
395             struct vol  *vol;
396 struct dir      *dir;
397 char    *path;
398 {
399     char        *p;
400     struct stat st;
401
402     p = mtoupath(vol, path );
403     if ( stat( p, &st ) != 0 ) {
404         return( NULL );
405     }
406     if (!S_ISDIR(st.st_mode)) {
407         return( NULL );
408     }
409
410     if (( dir = adddir( vol, dir, path, strlen( path ), p, strlen(p),
411                         &st)) == NULL ) {
412         return( NULL );
413     }
414
415     if ( movecwd( vol, dir ) < 0 ) {
416         return( NULL );
417     }
418
419     return( dir );
420 }
421
422 static int deletedir(char *dir)
423 {
424     char path[MAXPATHLEN + 1];
425     DIR *dp;
426     struct dirent       *de;
427     struct stat st;
428     int len, err;
429
430     if ((len = strlen(dir)) > sizeof(path))
431         return AFPERR_PARAM;
432
433     /* already gone */
434     if ((dp = opendir(dir)) == NULL)
435         return AFP_OK;
436
437     strcpy(path, dir);
438     strcat(path, "/");
439     len++;
440     while ((de = readdir(dp))) {
441         /* skip this and previous directory */
442         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
443             continue;
444
445         strncpy(path + len, de->d_name, sizeof(path) - len);
446         if (stat(path, &st) == 0) {
447             if (S_ISDIR(st.st_mode)) {
448                 if ((err = deletedir(path)) < 0) {
449                     closedir(dp);
450                     return err;
451                 }
452             } else if (unlink(path) < 0) {
453                 switch (errno) {
454                 case ENOENT :
455                     continue; /* somebody went and deleted it behind our backs. */
456                 case EROFS:
457                     err = AFPERR_VLOCK;
458                 case EPERM:
459                 case EACCES :
460                     err = AFPERR_ACCESS;
461                 default :
462                     err = AFPERR_PARAM;
463                 }
464                 closedir(dp);
465                 return err;
466             }
467         }
468     }
469     closedir(dp);
470
471     /* okay. the directory is empty. delete it. note: we already got rid
472        of .AppleDouble.  */
473     if (rmdir(dir) < 0) {
474         switch ( errno ) {
475         case ENOENT :
476             break;
477         case ENOTEMPTY : /* should never happen */
478             return( AFPERR_DIRNEMPT );
479         case EPERM:
480         case EACCES :
481             return( AFPERR_ACCESS );
482         case EROFS:
483             return AFPERR_VLOCK;
484         default :
485             return( AFPERR_PARAM );
486         }
487     }
488     return AFP_OK;
489 }
490
491 /* do a recursive copy. */
492 static int copydir(char *src, char *dst, int noadouble)
493 {
494     char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
495     DIR *dp;
496     struct dirent       *de;
497     struct stat st;
498     struct utimbuf      ut;
499     int slen, dlen, err;
500
501     /* doesn't exist or the path is too long. */
502     if (((slen = strlen(src)) > sizeof(spath) - 2) ||
503             ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
504             ((dp = opendir(src)) == NULL))
505         return AFPERR_PARAM;
506
507     /* try to create the destination directory */
508     if (ad_mkdir(dst, DIRBITS | 0777) < 0) {
509         closedir(dp);
510         switch ( errno ) {
511         case ENOENT :
512             return( AFPERR_NOOBJ );
513         case EROFS :
514             return( AFPERR_VLOCK );
515         case EPERM:
516         case EACCES :
517             return( AFPERR_ACCESS );
518         case EEXIST :
519             return( AFPERR_EXIST );
520         case ENOSPC :
521         case EDQUOT :
522             return( AFPERR_DFULL );
523         default :
524             return( AFPERR_PARAM );
525         }
526     }
527
528     /* set things up to copy */
529     strcpy(spath, src);
530     strcat(spath, "/");
531     slen++;
532     strcpy(dpath, dst);
533     strcat(dpath, "/");
534     dlen++;
535     err = AFP_OK;
536     while ((de = readdir(dp))) {
537         /* skip this and previous directory */
538         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
539             continue;
540
541         strncpy(spath + slen, de->d_name, sizeof(spath) - slen);
542         if (stat(spath, &st) == 0) {
543             strncpy(dpath + dlen, de->d_name, sizeof(dpath) - dlen);
544
545             if (S_ISDIR(st.st_mode)) {
546                 if ((err = copydir(spath, dpath, noadouble)) < 0)
547                     goto copydir_done;
548             } else if ((err = copyfile(spath, dpath, NULL, noadouble)) < 0) {
549                 goto copydir_done;
550
551             } else {
552                 /* keep the same time stamp. */
553                 ut.actime = ut.modtime = st.st_mtime;
554                 utime(dpath, &ut);
555             }
556         }
557     }
558
559     /* keep the same time stamp. */
560     if (stat(src, &st) == 0) {
561         ut.actime = ut.modtime = st.st_mtime;
562         utime(dst, &ut);
563     }
564
565 copydir_done:
566     closedir(dp);
567     return err;
568 }
569
570
571 /* --- public functions follow --- */
572
573 /* NOTE: we start off with at least one node (the root directory). */
574 struct dir *dirinsert( vol, dir )
575             struct vol  *vol;
576 struct dir      *dir;
577 {
578     struct dir *node;
579
580     if ((node = dir_insert(vol, dir)))
581         return node;
582
583     /* recolor the tree. the current node is red. */
584     dir->d_color = DIRTREE_COLOR_RED;
585
586     /* parent of this node has to be black. if the parent node
587     * is red, then we have a grandparent. */
588     while ((dir != vol->v_root) &&
589             (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
590         /* are we on the left tree? */
591         if (dir->d_back == dir->d_back->d_back->d_left) {
592             node = dir->d_back->d_back->d_right;  /* get the right node */
593             if (node->d_color == DIRTREE_COLOR_RED) {
594                 /* we're red. we need to change to black. */
595                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
596                 node->d_color = DIRTREE_COLOR_BLACK;
597                 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
598                 dir = dir->d_back->d_back; /* finished. go up. */
599             } else {
600                 if (dir == dir->d_back->d_right) {
601                     dir = dir->d_back;
602                     dir_leftrotate(vol, dir);
603                 }
604                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
605                 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
606                 dir_rightrotate(vol, dir->d_back->d_back);
607             }
608         } else {
609             node = dir->d_back->d_back->d_left;
610             if (node->d_color == DIRTREE_COLOR_RED) {
611                 /* we're red. we need to change to black. */
612                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
613                 node->d_color = DIRTREE_COLOR_BLACK;
614                 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
615                 dir = dir->d_back->d_back; /* finished. ascend */
616             } else {
617                 if (dir == dir->d_back->d_left) {
618                     dir = dir->d_back;
619                     dir_rightrotate(vol, dir);
620                 }
621                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
622                 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
623                 dir_leftrotate(vol, dir->d_back->d_back);
624             }
625         }
626     }
627
628     vol->v_root->d_color = DIRTREE_COLOR_BLACK;
629     return NULL;
630 }
631
632 /* free everything down. we don't bother to recolor as this is only
633  * called to free the entire tree */
634 void dirfree( dir )
635 struct dir      *dir;
636 {
637     if (!dir || (dir == SENTINEL))
638         return;
639
640     if ( dir->d_left != SENTINEL ) {
641         dirfree( dir->d_left );
642     }
643     if ( dir->d_right != SENTINEL ) {
644         dirfree( dir->d_right );
645     }
646
647     if (dir != SENTINEL) {
648         free( dir->d_name );
649         free( dir );
650     }
651 }
652
653
654 struct dir *dirnew(const int len)
655 {
656     struct dir *dir;
657
658     dir = (struct dir *) calloc(1, sizeof( struct dir ));
659     if (!dir)
660         return NULL;
661
662     if ((dir->d_name = (char *) malloc(sizeof(char)*len)) == NULL) {
663         free(dir);
664         return NULL;
665     }
666
667     dir->d_left = dir->d_right = SENTINEL;
668     dir->d_next = dir->d_prev = dir;
669     return dir;
670 }
671
672
673 /* XXX: this needs to be changed to handle path types */
674 char *
675 cname( vol, dir, cpath )
676 const struct vol        *vol;
677 struct dir      *dir;
678 char    **cpath;
679 {
680     struct dir          *cdir;
681     static char         path[ MAXPATHLEN + 1];
682     char                *data, *p;
683     int                 extend = 0;
684     int                 len;
685
686     data = *cpath;
687     if ( *data++ != 2 ) {                       /* path type */
688         return( NULL );
689     }
690     len = (unsigned char) *data++;
691     *cpath += len + 2;
692     *path = '\0';
693
694     for ( ;; ) {
695         if ( len == 0 ) {
696             if ( !extend && movecwd( vol, dir ) < 0 ) {
697                 return( NULL );
698             }
699             return( path );
700         }
701
702         if ( *data == '\0' ) {
703             data++;
704             len--;
705         }
706
707         while ( *data == '\0' && len > 0 ) {
708             if ( dir->d_parent == NULL ) {
709                 return( NULL );
710             }
711             dir = dir->d_parent;
712             data++;
713             len--;
714         }
715
716         /* would this be faster with strlen + strncpy? */
717         p = path;
718         while ( *data != '\0' && len > 0 ) {
719             *p++ = *data++;
720             len--;
721         }
722
723         /* short cut bits by chopping off a trailing \0. this also
724                   makes the traversal happy w/ filenames at the end of the
725                   cname. */
726         if (len == 1)
727             len--;
728
729 #ifdef notdef
730         /*
731          * Dung Nguyen <ntd@adb.fr>
732          *
733          * AFPD cannot handle paths with "::" if the "::" notation is
734          * not at the beginning of the path. The following path will not
735          * be interpreted correctly:
736          *
737          * :a:b:::c: (directory c at the same level as directory a) */
738         if ( len > 0 ) {
739             data++;
740             len--;
741         }
742 #endif /* notdef */
743         *p = '\0';
744
745         if ( p != path ) { /* we got something */
746             if ( !extend ) {
747                 cdir = dir->d_child;
748                 while (cdir) {
749                     if ( strcasecmp( cdir->d_name, path ) == 0 ) {
750                         break;
751                     }
752                     cdir = (cdir == dir->d_child->d_prev) ? NULL :
753                            cdir->d_next;
754                 }
755                 if ( cdir == NULL ) {
756                     ++extend;
757                     if ( movecwd( vol, dir ) < 0 ) {
758                         return( NULL );
759                     }
760                     cdir = extenddir( vol, dir, path );
761                 }
762
763             } else {
764                 cdir = extenddir( vol, dir, path );
765             }
766
767             if ( cdir == NULL ) {
768                 if ( len > 0 ) {
769                     return( NULL );
770                 }
771
772             } else {
773                 dir = cdir;
774                 *path = '\0';
775             }
776         }
777     }
778 }
779
780 /*
781  * Move curdir to dir, with a possible chdir()
782  */
783 int movecwd( vol, dir)
784 const struct vol        *vol;
785 struct dir      *dir;
786 {
787     char path[MAXPATHLEN + 1];
788     struct dir  *d;
789     char        *p, *u;
790     int         n;
791
792     if ( dir == curdir ) {
793         return( 0 );
794     }
795     if ( dir->d_did == DIRDID_ROOT_PARENT) {
796         return( -1 );
797     }
798
799     p = path + sizeof(path) - 1;
800     *p-- = '\0';
801     *p = '.';
802     for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
803         *--p = '/';
804         u = mtoupath(vol, d->d_name );
805         n = strlen( u );
806         p -= n;
807         strncpy( p, u, n );
808     }
809     if ( d != curdir ) {
810         *--p = '/';
811         n = strlen( vol->v_path );
812         p -= n;
813         strncpy( p, vol->v_path, n );
814     }
815     if ( chdir( p ) < 0 ) {
816         return( -1 );
817     }
818     curdir = dir;
819     return( 0 );
820 }
821
822 int getdirparams(const struct vol *vol,
823                  u_int16_t bitmap,
824                  char *upath, struct dir *dir, struct stat *st,
825                  char *buf, int *buflen )
826 {
827     struct maccess      ma;
828     struct adouble      ad;
829     char                *data, *nameoff = NULL;
830     DIR                 *dp;
831     struct dirent       *de;
832     int                 bit = 0, isad = 1;
833     u_int32_t           aint;
834     u_int16_t           ashort;
835 #ifdef FORCE_UIDGID
836     uidgidset           *uidgid;
837     memset(&uidgid, 0, sizeof(uidgid));
838 #endif /* FORCE_UIDGID */
839
840     memset(&ad, 0, sizeof(ad));
841
842 #ifdef FORCE_UIDGID
843     save_uidgid ( &uidgid );
844     set_uidgid ( vol );
845 #endif /* FORCE_UIDGID */
846
847     if ( ad_open( upath, ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY,
848                   DIRBITS | 0777, &ad) < 0 ) {
849         isad = 0;
850     }
851
852     data = buf;
853     while ( bitmap != 0 ) {
854         while (( bitmap & 1 ) == 0 ) {
855             bitmap = bitmap>>1;
856             bit++;
857         }
858
859         switch ( bit ) {
860         case DIRPBIT_ATTR :
861             if ( isad ) {
862                 ad_getattr(&ad, &ashort);
863             } else if (*upath == '.' && strcmp(upath, ".") &&
864                        strcmp(upath, "..")) {
865                 ashort = htons(ATTRBIT_INVISIBLE);
866             } else
867                 ashort = 0;
868             memcpy( data, &ashort, sizeof( ashort ));
869             data += sizeof( ashort );
870             break;
871
872         case DIRPBIT_PDID :
873             if ( dir->d_did == DIRDID_ROOT) {
874                 aint = DIRDID_ROOT_PARENT;
875             } else if (dir->d_did == DIRDID_ROOT_PARENT) {
876                 aint = 0;
877             } else {
878                 aint = dir->d_parent->d_did;
879             }
880             memcpy( data, &aint, sizeof( aint ));
881             data += sizeof( aint );
882             break;
883
884         case DIRPBIT_CDATE :
885             if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
886                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
887             memcpy( data, &aint, sizeof( aint ));
888             data += sizeof( aint );
889             break;
890
891         case DIRPBIT_MDATE :
892             aint = AD_DATE_FROM_UNIX(st->st_mtime);
893             memcpy( data, &aint, sizeof( aint ));
894             data += sizeof( aint );
895             break;
896
897         case DIRPBIT_BDATE :
898             if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
899                 aint = AD_DATE_START;
900             memcpy( data, &aint, sizeof( aint ));
901             data += sizeof( aint );
902             break;
903
904         case DIRPBIT_FINFO :
905             if ( isad ) {
906                 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
907             } else { /* no appledouble */
908                 memset( data, 0, 32 );
909                 /* set default view -- this also gets done in ad_open() */
910                 ashort = htons(FINDERINFO_CLOSEDVIEW);
911                 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
912
913                 /* dot files are by default invisible */
914                 if (*upath == '.' && strcmp(upath, ".") &&
915                         strcmp(upath, "..")) {
916                     ashort = htons(FINDERINFO_INVISIBLE);
917                     memcpy(data + FINDERINFO_FRFLAGOFF,
918                            &ashort, sizeof(ashort));
919                 }
920             }
921             data += 32;
922             break;
923
924         case DIRPBIT_LNAME :
925             if (dir->d_name) /* root of parent can have a null name */
926                 nameoff = data;
927             else
928                 memset(data, 0, sizeof(u_int16_t));
929             data += sizeof( u_int16_t );
930             break;
931
932         case DIRPBIT_SNAME :
933             memset(data, 0, sizeof(u_int16_t));
934             data += sizeof( u_int16_t );
935             break;
936
937         case DIRPBIT_DID :
938             memcpy( data, &dir->d_did, sizeof( aint ));
939             data += sizeof( aint );
940             break;
941
942         case DIRPBIT_OFFCNT :
943             ashort = 0;
944             /* this needs to handle current directory access rights */
945             if ((dp = opendir( upath ))) {
946                 while (( de = readdir( dp )) != NULL ) {
947                     if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
948                         continue;
949
950                     if (!validupath(vol, de->d_name))
951                         continue;
952
953                     /* check for vetoed filenames */
954                     if (veto_file(vol->v_veto, de->d_name))
955                         continue;
956
957                     /* now check against too long a filename */
958                     if (strlen(utompath(vol, de->d_name)) > MACFILELEN)
959                         continue;
960
961                     ashort++;
962                 }
963                 closedir( dp );
964             }
965             ashort = htons( ashort );
966             memcpy( data, &ashort, sizeof( ashort ));
967             data += sizeof( ashort );
968             break;
969
970         case DIRPBIT_UID :
971             aint = htonl(st->st_uid);
972             memcpy( data, &aint, sizeof( aint ));
973             data += sizeof( aint );
974             break;
975
976         case DIRPBIT_GID :
977             aint = htonl(st->st_gid);
978             memcpy( data, &aint, sizeof( aint ));
979             data += sizeof( aint );
980             break;
981
982         case DIRPBIT_ACCESS :
983             utommode( st, &ma );
984 #ifndef SENDFILE_FLAVOR_LINUX /* ignore this section if it's linux */
985 #ifdef HAVE_ACCESS
986             accessmode( upath, &ma, dir );
987 #endif /* HAVE_ACCESS */
988 #endif /* SENDFILE_FLAVOR_LINUX */
989 #ifdef AFS      /* If only AFS defined, access() works only for AFS filesystems */ 
990             afsmode( upath, &ma, dir );
991 #endif /* AFS */
992             *data++ = ma.ma_user;
993             *data++ = ma.ma_world;
994             *data++ = ma.ma_group;
995             *data++ = ma.ma_owner;
996             break;
997
998             /* Client has requested the ProDOS information block.
999                Just pass back the same basic block for all
1000                directories. <shirsch@ibm.net> */
1001         case DIRPBIT_PDINFO :                     /* ProDOS Info Block */
1002             *data++ = 0x0f;
1003             *data++ = 0;
1004             ashort = htons( 0x0200 );
1005             memcpy( data, &ashort, sizeof( ashort ));
1006             data += sizeof( ashort );
1007             memset( data, 0, sizeof( ashort ));
1008             data += sizeof( ashort );
1009             break;
1010
1011         default :
1012             if ( isad ) {
1013                 ad_close( &ad, ADFLAGS_HF );
1014             }
1015 #ifdef FORCE_UIDGID
1016             restore_uidgid ( &uidgid );
1017 #endif /* FORCE_UIDGID */
1018             return( AFPERR_BITMAP );
1019         }
1020         bitmap = bitmap>>1;
1021         bit++;
1022     }
1023     if ( nameoff ) {
1024         ashort = htons( data - buf );
1025         memcpy( nameoff, &ashort, sizeof( ashort ));
1026
1027         if ((aint = strlen( dir->d_name )) > MACFILELEN)
1028             aint = MACFILELEN;
1029
1030         *data++ = aint;
1031         memcpy( data, dir->d_name, aint );
1032         data += aint;
1033     }
1034     if ( isad ) {
1035         ad_close( &ad, ADFLAGS_HF );
1036     }
1037     *buflen = data - buf;
1038     return( AFP_OK );
1039 }
1040
1041 int afp_setdirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1042 AFPObj      *obj;
1043 char    *ibuf, *rbuf;
1044 int             ibuflen, *rbuflen;
1045 {
1046     struct vol  *vol;
1047     struct dir  *dir;
1048     char        *path;
1049     u_int16_t   vid, bitmap;
1050     u_int32_t   did;
1051     int         rc;
1052
1053     *rbuflen = 0;
1054     ibuf += 2;
1055     memcpy( &vid, ibuf, sizeof( vid ));
1056     ibuf += sizeof( vid );
1057
1058     if (( vol = getvolbyvid( vid )) == NULL ) {
1059         return( AFPERR_PARAM );
1060     }
1061
1062     if (vol->v_flags & AFPVOL_RO)
1063         return AFPERR_VLOCK;
1064
1065     memcpy( &did, ibuf, sizeof( did ));
1066     ibuf += sizeof( int );
1067
1068     if (( dir = dirsearch( vol, did )) == NULL ) {
1069         return( AFPERR_NOOBJ );
1070     }
1071
1072     memcpy( &bitmap, ibuf, sizeof( bitmap ));
1073     bitmap = ntohs( bitmap );
1074     ibuf += sizeof( bitmap );
1075
1076     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1077         return( AFPERR_NOOBJ );
1078     }
1079
1080     /*
1081      * If ibuf is odd, make it even.
1082      */
1083     if ((u_long)ibuf & 1 ) {
1084         ibuf++;
1085     }
1086
1087     if (( rc = setdirparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
1088         setvoltime(obj, vol );
1089     }
1090     return( rc );
1091 }
1092
1093 int setdirparams(const struct vol *vol,
1094                  char *path, u_int16_t bitmap, char *buf )
1095 {
1096     struct maccess      ma;
1097     struct adouble      ad;
1098     struct utimbuf      ut;
1099     char                *upath;
1100     int                 bit = 0, aint, isad = 1;
1101     u_int16_t           ashort, bshort;
1102     int                 err = AFP_OK;
1103 #ifdef FORCE_UIDGID
1104     uidgidset           *uidgid;
1105
1106     memset(&uidgid, 0, sizeof(uidgid));
1107 #endif /* FORCE_UIDGID */
1108
1109     upath = mtoupath(vol, path);
1110     memset(&ad, 0, sizeof(ad));
1111 #ifdef FORCE_UIDGID
1112     save_uidgid ( &uidgid );
1113 #endif /* FORCE_UIDGID */
1114     if (ad_open( upath, vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
1115                  O_RDWR|O_CREAT, 0666, &ad) < 0) {
1116         /*
1117          * Check to see what we're trying to set.  If it's anything
1118          * but ACCESS, UID, or GID, give an error.  If it's any of those
1119          * three, we don't need the ad to be open, so just continue.
1120          *
1121          * note: we also don't need to worry about mdate. also, be quiet
1122          *       if we're using the noadouble option.
1123          */
1124         if (!vol_noadouble(vol) && (bitmap &
1125                                     ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
1126                                       (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
1127 #ifdef FORCE_UIDGID
1128             restore_uidgid ( &uidgid );
1129 #endif /* FORCE_UIDGID */
1130             return AFPERR_ACCESS;
1131         }
1132
1133         isad = 0;
1134     } else {
1135         /*
1136          * Check to see if a create was necessary. If it was, we'll want
1137          * to set our name, etc.
1138          */
1139         if ( ad_getoflags( &ad, ADFLAGS_HF ) & O_CREAT ) {
1140             ad_setentrylen( &ad, ADEID_NAME, strlen( curdir->d_name ));
1141             memcpy( ad_entry( &ad, ADEID_NAME ), curdir->d_name,
1142                     ad_getentrylen( &ad, ADEID_NAME ));
1143         }
1144     }
1145
1146     while ( bitmap != 0 ) {
1147         while (( bitmap & 1 ) == 0 ) {
1148             bitmap = bitmap>>1;
1149             bit++;
1150         }
1151
1152         switch( bit ) {
1153         case DIRPBIT_ATTR :
1154             if (isad) {
1155                 memcpy( &ashort, buf, sizeof( ashort ));
1156                 ad_getattr(&ad, &bshort);
1157                 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
1158                     bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
1159                 } else {
1160                     bshort &= ~ashort;
1161                 }
1162                 ad_setattr(&ad, bshort);
1163             }
1164             buf += sizeof( ashort );
1165             break;
1166
1167         case DIRPBIT_CDATE :
1168             if (isad) {
1169                 memcpy(&aint, buf, sizeof(aint));
1170                 ad_setdate(&ad, AD_DATE_CREATE, aint);
1171             }
1172             buf += sizeof( aint );
1173             break;
1174
1175         case DIRPBIT_MDATE :
1176             memcpy(&aint, buf, sizeof(aint));
1177             if (isad)
1178                 ad_setdate(&ad, AD_DATE_MODIFY, aint);
1179             ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
1180             utime(upath, &ut);
1181             buf += sizeof( aint );
1182             break;
1183
1184         case DIRPBIT_BDATE :
1185             if (isad) {
1186                 memcpy(&aint, buf, sizeof(aint));
1187                 ad_setdate(&ad, AD_DATE_BACKUP, aint);
1188             }
1189             buf += sizeof( aint );
1190             break;
1191
1192         case DIRPBIT_FINFO :
1193             /*
1194              * Alright, we admit it, this is *really* sick!
1195              * The 4 bytes that we don't copy, when we're dealing
1196              * with the root of a volume, are the directory's
1197              * location information. This eliminates that annoying
1198              * behavior one sees when mounting above another mount
1199              * point.
1200              */
1201             if (isad) {
1202                 if (  curdir->d_did == DIRDID_ROOT ) {
1203                     memcpy( ad_entry( &ad, ADEID_FINDERI ), buf, 10 );
1204                     memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, buf + 14, 18 );
1205                 } else {
1206                     memcpy( ad_entry( &ad, ADEID_FINDERI ), buf, 32 );
1207                 }
1208             }
1209             buf += 32;
1210             break;
1211
1212         case DIRPBIT_UID :      /* What kind of loser mounts as root? */
1213             memcpy( &aint, buf, sizeof(aint));
1214             buf += sizeof( aint );
1215             if ( (curdir->d_did == DIRDID_ROOT) &&
1216                     (setdeskowner( ntohl(aint), -1 ) < 0)) {
1217                 switch ( errno ) {
1218                 case EPERM :
1219                 case EACCES :
1220                     err = AFPERR_ACCESS;
1221                     goto setdirparam_done;
1222                     break;
1223                 case EROFS :
1224                     err = AFPERR_VLOCK;
1225                     goto setdirparam_done;
1226                     break;
1227                 default :
1228                     syslog( LOG_ERR, "setdirparam: setdeskowner: %s",
1229                             strerror(errno) );
1230                     if (!isad) {
1231                         err = AFPERR_PARAM;
1232                         goto setdirparam_done;
1233                     }
1234                     break;
1235                 }
1236             }
1237             if ( setdirowner( ntohl(aint), -1, vol_noadouble(vol) ) < 0 ) {
1238                 switch ( errno ) {
1239                 case EPERM :
1240                 case EACCES :
1241                     err = AFPERR_ACCESS;
1242                     goto setdirparam_done;
1243                     break;
1244                 case EROFS :
1245                     err = AFPERR_VLOCK;
1246                     goto setdirparam_done;
1247                     break;
1248                 default :
1249                     syslog( LOG_ERR, "setdirparam: setdirowner: %s",
1250                             strerror(errno) );
1251                     break;
1252                 }
1253             }
1254             break;
1255         case DIRPBIT_GID :
1256             memcpy( &aint, buf, sizeof( aint ));
1257             buf += sizeof( aint );
1258             if (curdir->d_did == DIRDID_ROOT)
1259                 setdeskowner( -1, ntohl(aint) );
1260
1261 #if 0       /* don't error if we can't set the desktop owner. */
1262             switch ( errno ) {
1263             case EPERM :
1264             case EACCES :
1265                 err = AFPERR_ACCESS;
1266                 goto setdirparam_done;
1267                 break;
1268             case EROFS :
1269                 err = AFPERR_VLOCK;
1270                 goto setdirparam_done;
1271                 break;
1272             default :
1273                 syslog( LOG_ERR, "setdirparam: setdeskowner: %m" );
1274                 if (!isad) {
1275                     err = AFPERR_PARAM;
1276                     goto setdirparam_done;
1277                 }
1278                 break;
1279             }
1280 #endif /* 0 */
1281
1282             if ( setdirowner( -1, ntohl(aint), vol_noadouble(vol) ) < 0 ) {
1283                 switch ( errno ) {
1284                 case EPERM :
1285                 case EACCES :
1286                     err = AFPERR_ACCESS;
1287                     goto setdirparam_done;
1288                     break;
1289                 case EROFS :
1290                     err = AFPERR_VLOCK;
1291                     goto setdirparam_done;
1292                     break;
1293                 default :
1294                     syslog( LOG_ERR, "setdirparam: setdirowner: %s",
1295                             strerror(errno) );
1296                     break;
1297                 }
1298             }
1299             break;
1300
1301         case DIRPBIT_ACCESS :
1302             ma.ma_user = *buf++;
1303             ma.ma_world = *buf++;
1304             ma.ma_group = *buf++;
1305             ma.ma_owner = *buf++;
1306
1307             if (curdir->d_did == DIRDID_ROOT)
1308                 setdeskmode(mtoumode( &ma ));
1309 #if 0 /* don't error if we can't set the desktop mode */
1310             switch ( errno ) {
1311             case EPERM :
1312             case EACCES :
1313                 err = AFPERR_ACCESS;
1314                 goto setdirparam_done;
1315             case EROFS :
1316                 err = AFPERR_VLOCK;
1317                 goto setdirparam_done;
1318             default :
1319                 syslog( LOG_ERR, "setdirparam: setdeskmode: %s",
1320                         strerror(errno) );
1321                 break;
1322                 err = AFPERR_PARAM;
1323                 goto setdirparam_done;
1324             }
1325         }
1326 #endif /* 0 */
1327
1328         if ( setdirmode( mtoumode( &ma ), vol_noadouble(vol),
1329                          (vol->v_flags & AFPVOL_DROPBOX)) < 0 ) {
1330             switch ( errno ) {
1331             case EPERM :
1332             case EACCES :
1333                 err = AFPERR_ACCESS;
1334                 goto setdirparam_done;
1335             case EROFS :
1336                 err = AFPERR_VLOCK;
1337                 goto setdirparam_done;
1338             default :
1339                 syslog( LOG_ERR, "setdirparam: setdirmode: %s",
1340                         strerror(errno) );
1341                 err = AFPERR_PARAM;
1342                 goto setdirparam_done;
1343             }
1344         }
1345         break;
1346
1347         /* Ignore what the client thinks we should do to the
1348            ProDOS information block.  Skip over the data and
1349            report nothing amiss. <shirsch@ibm.net> */
1350     case DIRPBIT_PDINFO :
1351         buf += 6;
1352         break;
1353
1354     default :
1355         err = AFPERR_BITMAP;
1356         goto setdirparam_done;
1357         break;
1358     }
1359
1360     bitmap = bitmap>>1;
1361     bit++;
1362 }
1363
1364
1365 setdirparam_done:
1366 if ( isad ) {
1367     ad_flush( &ad, ADFLAGS_HF );
1368     ad_close( &ad, ADFLAGS_HF );
1369 }
1370
1371 #ifdef FORCE_UIDGID
1372 restore_uidgid ( &uidgid );
1373 #endif /* FORCE_UIDGID */
1374 return err;
1375 }
1376
1377 int afp_createdir(obj, ibuf, ibuflen, rbuf, rbuflen )
1378 AFPObj      *obj;
1379 char    *ibuf, *rbuf;
1380 int             ibuflen, *rbuflen;
1381 {
1382     struct adouble      ad;
1383     struct stat         st;
1384     struct vol          *vol;
1385     struct dir          *dir;
1386     char                *path, *upath;
1387     u_int32_t           did;
1388     u_int16_t           vid;
1389 #ifdef FORCE_UIDGID
1390     uidgidset           *uidgid;
1391
1392     memset(&uidgid, 0, sizeof(uidgid));
1393 #endif /* FORCE_UIDGID */
1394
1395     *rbuflen = 0;
1396     ibuf += 2;
1397
1398     memcpy( &vid, ibuf, sizeof( vid ));
1399     ibuf += sizeof( vid );
1400     if (( vol = getvolbyvid( vid )) == NULL ) {
1401         return( AFPERR_PARAM );
1402     }
1403
1404     if (vol->v_flags & AFPVOL_RO)
1405         return AFPERR_VLOCK;
1406
1407     memcpy( &did, ibuf, sizeof( did ));
1408     ibuf += sizeof( did );
1409     if (( dir = dirsearch( vol, did )) == NULL ) {
1410         return( AFPERR_NOOBJ );
1411     }
1412
1413     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1414         switch( errno ) {
1415         case EACCES:
1416             return( AFPERR_ACCESS );
1417         case EEXIST:
1418             return( AFPERR_EXIST );
1419         default:
1420             return( AFPERR_NOOBJ );
1421         }
1422     }
1423
1424     /* check for illegal bits */
1425     if ((vol->v_flags & AFPVOL_MSWINDOWS) &&
1426             strpbrk(path, MSWINDOWS_BADCHARS))
1427         return AFPERR_PARAM;
1428
1429     upath = mtoupath(vol, path);
1430
1431     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
1432         return AFPERR_PARAM;
1433
1434     if (!validupath(vol, upath))
1435         return AFPERR_EXIST;
1436
1437     /* check for vetoed filenames */
1438     if (veto_file(vol->v_veto, upath))
1439         return AFPERR_EXIST;
1440
1441 #ifdef FORCE_UIDGID
1442     save_uidgid ( &uidgid );
1443     set_uidgid  ( vol );
1444 #endif /* FORCE_UIDGID */
1445
1446     if ( ad_mkdir( upath, DIRBITS | 0777 ) < 0 ) {
1447 #ifdef FORCE_UIDGID
1448         restore_uidgid ( &uidgid );
1449 #endif /* FORCE_UIDGID */
1450         switch ( errno ) {
1451         case ENOENT :
1452             return( AFPERR_NOOBJ );
1453         case EROFS :
1454             return( AFPERR_VLOCK );
1455         case EACCES :
1456             return( AFPERR_ACCESS );
1457         case EEXIST :
1458             return( AFPERR_EXIST );
1459         case ENOSPC :
1460         case EDQUOT :
1461             return( AFPERR_DFULL );
1462         default :
1463             return( AFPERR_PARAM );
1464         }
1465     }
1466
1467     if (stat(upath, &st) < 0) {
1468 #ifdef FORCE_UIDGID
1469         restore_uidgid ( &uidgid );
1470 #endif /* FORCE_UIDGID */
1471         return AFPERR_MISC;
1472     }
1473
1474     if ((dir = adddir( vol, curdir, path, strlen( path ), upath,
1475                        strlen(upath), &st)) == NULL) {
1476 #ifdef FORCE_UIDGID
1477         restore_uidgid ( &uidgid );
1478 #endif /* FORCE_UIDGID */
1479         return AFPERR_MISC;
1480     }
1481
1482     if ( movecwd( vol, dir ) < 0 ) {
1483 #ifdef FORCE_UIDGID
1484         restore_uidgid ( &uidgid );
1485 #endif /* FORCE_UIDGID */
1486         return( AFPERR_PARAM );
1487     }
1488
1489     memset(&ad, 0, sizeof(ad));
1490     if (ad_open( "", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
1491                  O_RDWR|O_CREAT, 0666, &ad ) < 0)  {
1492         if (vol_noadouble(vol))
1493             goto createdir_done;
1494 #ifdef FORCE_UIDGID
1495         restore_uidgid ( &uidgid );
1496 #endif /* FORCE_UIDGID */
1497         return( AFPERR_ACCESS );
1498     }
1499
1500     ad_setentrylen( &ad, ADEID_NAME, strlen( path ));
1501     memcpy( ad_entry( &ad, ADEID_NAME ), path,
1502             ad_getentrylen( &ad, ADEID_NAME ));
1503     ad_flush( &ad, ADFLAGS_HF );
1504     ad_close( &ad, ADFLAGS_HF );
1505
1506 createdir_done:
1507     memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
1508     *rbuflen = sizeof( u_int32_t );
1509     setvoltime(obj, vol );
1510 #ifdef FORCE_UIDGID
1511     restore_uidgid ( &uidgid );
1512 #endif /* FORCE_UIDGID */
1513     return( AFP_OK );
1514 }
1515
1516
1517 int renamedir(src, dst, dir, newparent, newname, noadouble)
1518 char    *src, *dst, *newname;
1519 struct dir      *dir, *newparent;
1520 const int noadouble;
1521 {
1522     struct adouble      ad;
1523     struct dir          *parent;
1524     char                *buf;
1525     int                 len, err;
1526
1527     /* existence check moved to afp_moveandrename */
1528     if ( rename( src, dst ) < 0 ) {
1529         switch ( errno ) {
1530         case ENOENT :
1531             return( AFPERR_NOOBJ );
1532         case EACCES :
1533             return( AFPERR_ACCESS );
1534         case EROFS:
1535             return AFPERR_VLOCK;
1536         case EINVAL:
1537             /* tried to move directory into a subdirectory of itself */
1538             return AFPERR_CANTMOVE;
1539         case EXDEV:
1540             /* this needs to copy and delete. bleah. that means we have
1541              * to deal with entire directory hierarchies. */
1542             if ((err = copydir(src, dst, noadouble)) < 0) {
1543                 deletedir(dst);
1544                 return err;
1545             }
1546             if ((err = deletedir(src)) < 0)
1547                 return err;
1548             break;
1549         default :
1550             return( AFPERR_PARAM );
1551         }
1552     }
1553
1554     memset(&ad, 0, sizeof(ad));
1555     if ( ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad) < 0 ) {
1556         switch ( errno ) {
1557         case ENOENT :
1558             if (noadouble) {
1559                 len = strlen(newname);
1560                 goto renamedir_done;
1561             }
1562             return( AFPERR_NOOBJ );
1563         case EACCES :
1564             return( AFPERR_ACCESS );
1565         default :
1566             return( AFPERR_PARAM );
1567         }
1568     }
1569     len = strlen( newname );
1570     ad_setentrylen( &ad, ADEID_NAME, len );
1571     memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
1572     ad_flush( &ad, ADFLAGS_HF );
1573     ad_close( &ad, ADFLAGS_HF );
1574
1575 renamedir_done:
1576     if ((buf = (char *) realloc( dir->d_name, len + 1 )) == NULL ) {
1577         syslog( LOG_ERR, "renamedir: realloc: %s", strerror(errno) );
1578         return AFPERR_MISC;
1579     }
1580     dir->d_name = buf;
1581     strcpy( dir->d_name, newname );
1582
1583     if (( parent = dir->d_parent ) == NULL ) {
1584         return( AFP_OK );
1585     }
1586     if ( parent == newparent ) {
1587         return( AFP_OK );
1588     }
1589
1590     /* detach from old parent and add to new one. */
1591     dirchildremove(parent, dir);
1592     dir->d_parent = newparent;
1593     dirchildadd(newparent, dir);
1594     return( AFP_OK );
1595 }
1596
1597 #define DOT_APPLEDOUBLE_LEN 13
1598 /* delete an empty directory */
1599 int deletecurdir( vol, path, pathlen )
1600 const struct vol        *vol;
1601 char *path;
1602 int pathlen;
1603 {
1604     struct dirent *de;
1605     struct stat st;
1606     struct dir  *fdir;
1607     DIR *dp;
1608 #ifdef FORCE_UIDGID
1609     uidgidset           *uidgid;
1610
1611     memset(&uidgid, 0, sizeof(uidgid));
1612 #endif /* FORCE_UIDGID */
1613
1614     if ( curdir->d_parent == NULL ) {
1615         return( AFPERR_ACCESS );
1616     }
1617
1618     if ( curdir->d_child != NULL ) {
1619         return( AFPERR_DIRNEMPT );
1620     }
1621
1622     fdir = curdir;
1623
1624 #ifdef FORCE_UIDGID
1625     save_uidgid ( &uidgid );
1626     set_uidgid  ( vol );
1627 #endif /* FORCE_UIDGID */
1628
1629     /* delete stray .AppleDouble files. this happens to get .Parent files
1630        as well. */
1631     if ((dp = opendir(".AppleDouble"))) {
1632         strcpy(path, ".AppleDouble/");
1633         while ((de = readdir(dp))) {
1634             /* skip this and previous directory */
1635             if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1636                 continue;
1637
1638             /* bail if the file exists in the current directory.
1639              * note: this will not fail with dangling symlinks */
1640             if (stat(de->d_name, &st) == 0) {
1641                 closedir(dp);
1642 #ifdef FORCE_UIDGID
1643                 restore_uidgid ( &uidgid );
1644 #endif /* FORCE_UIDGID */
1645                 return AFPERR_DIRNEMPT;
1646             }
1647
1648             strcpy(path + DOT_APPLEDOUBLE_LEN, de->d_name);
1649             if (unlink(path) < 0) {
1650                 closedir(dp);
1651                 switch (errno) {
1652                 case EPERM:
1653                 case EACCES :
1654 #ifdef FORCE_UIDGID
1655                     restore_uidgid ( &uidgid );
1656 #endif /* FORCE_UIDGID */
1657                     return( AFPERR_ACCESS );
1658                 case EROFS:
1659 #ifdef FORCE_UIDGID
1660                     restore_uidgid ( &uidgid );
1661 #endif /* FORCE_UIDGID */
1662                     return AFPERR_VLOCK;
1663                 case ENOENT :
1664                     continue;
1665                 default :
1666 #ifdef FORCE_UIDGID
1667                     restore_uidgid ( &uidgid );
1668 #endif /* FORCE_UIDGID */
1669                     return( AFPERR_PARAM );
1670                 }
1671             }
1672         }
1673         closedir(dp);
1674     }
1675
1676     if ( rmdir( ".AppleDouble" ) < 0 ) {
1677         switch ( errno ) {
1678         case ENOENT :
1679             break;
1680         case ENOTEMPTY :
1681 #ifdef FORCE_UIDGID
1682             restore_uidgid ( &uidgid );
1683 #endif /* FORCE_UIDGID */
1684             return( AFPERR_DIRNEMPT );
1685         case EROFS:
1686 #ifdef FORCE_UIDGID
1687             restore_uidgid ( &uidgid );
1688 #endif /* FORCE_UIDGID */
1689             return AFPERR_VLOCK;
1690         case EPERM:
1691         case EACCES :
1692 #ifdef FORCE_UIDGID
1693             restore_uidgid ( &uidgid );
1694 #endif /* FORCE_UIDGID */
1695             return( AFPERR_ACCESS );
1696         default :
1697 #ifdef FORCE_UIDGID
1698             restore_uidgid ( &uidgid );
1699 #endif /* FORCE_UIDGID */
1700             return( AFPERR_PARAM );
1701         }
1702     }
1703
1704     /* now get rid of dangling symlinks */
1705     if ((dp = opendir("."))) {
1706         while ((de = readdir(dp))) {
1707             /* skip this and previous directory */
1708             if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1709                 continue;
1710
1711             /* bail if it's not a symlink */
1712             if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
1713 #ifdef FORCE_UIDGID
1714                 restore_uidgid ( &uidgid );
1715 #endif /* FORCE_UIDGID */
1716                 return AFPERR_DIRNEMPT;
1717             }
1718
1719             if (unlink(de->d_name) < 0) {
1720                 switch (errno) {
1721                 case EPERM:
1722                 case EACCES :
1723 #ifdef FORCE_UIDGID
1724                     restore_uidgid ( &uidgid );
1725 #endif /* FORCE_UIDGID */
1726                     return( AFPERR_ACCESS );
1727                 case EROFS:
1728 #ifdef FORCE_UIDGID
1729                     restore_uidgid ( &uidgid );
1730 #endif /* FORCE_UIDGID */
1731                     return AFPERR_VLOCK;
1732                 case ENOENT :
1733                     continue;
1734                 default :
1735 #ifdef FORCE_UIDGID
1736                     restore_uidgid ( &uidgid );
1737 #endif /* FORCE_UIDGID */
1738                     return( AFPERR_PARAM );
1739                 }
1740             }
1741         }
1742         closedir(dp);
1743     }
1744
1745     if ( movecwd( vol, curdir->d_parent ) < 0 ) {
1746 #ifdef FORCE_UIDGID
1747         restore_uidgid ( &uidgid );
1748 #endif /* FORCE_UIDGID */
1749         return( AFPERR_NOOBJ );
1750     }
1751
1752     if ( rmdir(mtoupath(vol, fdir->d_name)) < 0 ) {
1753         switch ( errno ) {
1754         case ENOENT :
1755 #ifdef FORCE_UIDGID
1756             restore_uidgid ( &uidgid );
1757 #endif /* FORCE_UIDGID */
1758             return( AFPERR_NOOBJ );
1759         case ENOTEMPTY :
1760 #ifdef FORCE_UIDGID
1761             restore_uidgid ( &uidgid );
1762 #endif /* FORCE_UIDGID */
1763             return( AFPERR_DIRNEMPT );
1764         case EPERM:
1765         case EACCES :
1766 #ifdef FORCE_UIDGID
1767             restore_uidgid ( &uidgid );
1768 #endif /* FORCE_UIDGID */
1769             return( AFPERR_ACCESS );
1770         case EROFS:
1771 #ifdef FORCE_UIDGID
1772             restore_uidgid ( &uidgid );
1773 #endif /* FORCE_UIDGID */
1774             return AFPERR_VLOCK;
1775         default :
1776 #ifdef FORCE_UIDGID
1777             restore_uidgid ( &uidgid );
1778 #endif /* FORCE_UIDGID */
1779             return( AFPERR_PARAM );
1780         }
1781     }
1782
1783     dirchildremove(curdir, fdir);
1784 #ifdef CNID_DB
1785     cnid_delete(vol->v_db, fdir->d_did);
1786 #endif /* CNID_DB */
1787     dir_remove( vol, fdir );
1788
1789 #ifdef FORCE_UIDGID
1790     restore_uidgid ( &uidgid );
1791 #endif /* FORCE_UIDGID */
1792     return( AFP_OK );
1793 }
1794
1795 int afp_mapid(obj, ibuf, ibuflen, rbuf, rbuflen )
1796 AFPObj      *obj;
1797 char    *ibuf, *rbuf;
1798 int             ibuflen, *rbuflen;
1799 {
1800     struct passwd       *pw;
1801     struct group        *gr;
1802     char                *name;
1803     u_int32_t           id;
1804     int                 len, sfunc;
1805
1806     ibuf++;
1807     sfunc = (unsigned char) *ibuf++;
1808     memcpy( &id, ibuf, sizeof( id ));
1809
1810     id = ntohl(id);
1811
1812     if ( id != 0 ) {
1813         switch ( sfunc ) {
1814         case 1 :
1815             if (( pw = getpwuid( id )) == NULL ) {
1816                 *rbuflen = 0;
1817                 return( AFPERR_NOITEM );
1818             }
1819             name = pw->pw_name;
1820             break;
1821
1822         case 2 :
1823             if (( gr = (struct group *)getgrgid( id )) == NULL ) {
1824                 *rbuflen = 0;
1825                 return( AFPERR_NOITEM );
1826             }
1827             name = gr->gr_name;
1828             break;
1829
1830         default :
1831             *rbuflen = 0;
1832             return( AFPERR_PARAM );
1833         }
1834
1835         len = strlen( name );
1836
1837     } else {
1838         len = 0;
1839         name = NULL;
1840     }
1841
1842     *rbuf++ = len;
1843     if ( len > 0 ) {
1844         memcpy( rbuf, name, len );
1845     }
1846     *rbuflen = len + 1;
1847     return( AFP_OK );
1848 }
1849
1850 int afp_mapname(obj, ibuf, ibuflen, rbuf, rbuflen )
1851 AFPObj      *obj;
1852 char    *ibuf, *rbuf;
1853 int             ibuflen, *rbuflen;
1854 {
1855     struct passwd       *pw;
1856     struct group        *gr;
1857     int                 len, sfunc;
1858     u_int32_t           id;
1859
1860     ibuf++;
1861     sfunc = (unsigned char) *ibuf++;
1862     len = (unsigned char) *ibuf++;
1863     ibuf[ len ] = '\0';
1864
1865     if ( len != 0 ) {
1866         switch ( sfunc ) {
1867         case 3 :
1868             if (( pw = (struct passwd *)getpwnam( ibuf )) == NULL ) {
1869                 *rbuflen = 0;
1870                 return( AFPERR_NOITEM );
1871             }
1872             id = pw->pw_uid;
1873             break;
1874
1875         case 4 :
1876             if (( gr = (struct group *)getgrnam( ibuf )) == NULL ) {
1877                 *rbuflen = 0;
1878                 return( AFPERR_NOITEM );
1879             }
1880             id = gr->gr_gid;
1881             break;
1882         default :
1883             *rbuflen = 0;
1884             return( AFPERR_PARAM );
1885         }
1886     } else {
1887         id = 0;
1888     }
1889     id = htonl(id);
1890     memcpy( rbuf, &id, sizeof( id ));
1891     *rbuflen = sizeof( id );
1892     return( AFP_OK );
1893 }
1894
1895 /* variable DID support */
1896 int afp_closedir(obj, ibuf, ibuflen, rbuf, rbuflen )
1897 AFPObj      *obj;
1898 char    *ibuf, *rbuf;
1899 int             ibuflen, *rbuflen;
1900 {
1901 #if 0
1902     struct vol   *vol;
1903     struct dir   *dir;
1904     u_int16_t    vid;
1905     u_int32_t    did;
1906 #endif /* 0 */
1907
1908     *rbuflen = 0;
1909
1910     /* do nothing as dids are static for the life of the process. */
1911 #if 0
1912     ibuf += 2;
1913
1914     memcpy(&vid,  ibuf, sizeof( vid ));
1915     ibuf += sizeof( vid );
1916     if (( vol = getvolbyvid( vid )) == NULL ) {
1917         return( AFPERR_PARAM );
1918     }
1919
1920     memcpy( &did, ibuf, sizeof( did ));
1921     ibuf += sizeof( did );
1922     if (( dir = dirsearch( vol, did )) == NULL ) {
1923         return( AFPERR_PARAM );
1924     }
1925
1926     /* dir_remove -- deletedid */
1927 #endif /* 0 */
1928
1929     return AFP_OK;
1930 }
1931
1932 /* did creation gets done automatically */
1933 int afp_opendir(obj, ibuf, ibuflen, rbuf, rbuflen )
1934 AFPObj      *obj;
1935 char    *ibuf, *rbuf;
1936 int             ibuflen, *rbuflen;
1937 {
1938     struct vol          *vol;
1939     struct dir          *dir, *parentdir;
1940     struct stat         st;
1941     char                *path, *upath;
1942     u_int32_t           did;
1943     u_int16_t           vid;
1944 #ifdef FORCE_UIDGID
1945     uidgidset           *uidgid;
1946
1947     memset(&uidgid, 0, sizeof(uidgid));
1948 #endif /* FORCE_UIDGID */
1949
1950     *rbuflen = 0;
1951     ibuf += 2;
1952
1953     memcpy(&vid, ibuf, sizeof(vid));
1954     ibuf += sizeof( vid );
1955
1956     if (( vol = getvolbyvid( vid )) == NULL ) {
1957         return( AFPERR_PARAM );
1958     }
1959
1960     memcpy(&did, ibuf, sizeof(did));
1961     ibuf += sizeof(did);
1962
1963     if (( parentdir = dirsearch( vol, did )) == NULL ) {
1964         return( AFPERR_NOOBJ );
1965     }
1966
1967     if (( path = cname( vol, parentdir, &ibuf )) == NULL ) {
1968         switch( errno ) {
1969         case EACCES:
1970             return( AFPERR_ACCESS );
1971         default:
1972             return( AFPERR_NOOBJ );
1973         }
1974     }
1975
1976     /* see if we already have the directory. */
1977     upath = mtoupath(vol, path);
1978     if ( stat( upath, &st ) < 0 ) {
1979         return( AFPERR_NOOBJ );
1980     }
1981
1982     dir = parentdir->d_child;
1983     while (dir) {
1984         if (strdiacasecmp(dir->d_name, path) == 0) {
1985             memcpy(rbuf, &dir->d_did, sizeof(dir->d_did));
1986             *rbuflen = sizeof(dir->d_did);
1987             return AFP_OK;
1988         }
1989         dir = (dir == parentdir->d_child->d_prev) ? NULL : dir->d_next;
1990     }
1991
1992 #ifdef FORCE_UIDGID
1993     save_uidgid ( &uidgid );
1994     set_uidgid  ( vol );
1995 #endif /* FORCE_UIDGID */
1996
1997     /* we don't already have a did. add one in. */
1998     if ((dir = adddir(vol, parentdir, path, strlen(path),
1999                       upath, strlen(upath), &st)) == NULL) {
2000 #ifdef FORCE_UIDGID
2001         restore_uidgid ( &uidgid );
2002 #endif /* FORCE_UIDGID */
2003         return AFPERR_MISC;
2004     }
2005
2006     memcpy(rbuf, &dir->d_did, sizeof(dir->d_did));
2007     *rbuflen = sizeof(dir->d_did);
2008 #ifdef FORCE_UIDGID
2009     restore_uidgid ( &uidgid );
2010 #endif /* FORCE_UIDGID */
2011     return AFP_OK;
2012 }