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