]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/directory.c
AC_HEADER_STDC autoconf change
[netatalk.git] / etc / afpd / directory.c
1 /*
2  * $Id: directory.c,v 1.18 2001-09-06 20:00:59 rufustfirefly 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         return( AFPERR_NOOBJ );
1415     }
1416
1417     /* check for illegal bits */
1418     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
1419         strpbrk(path, MSWINDOWS_BADCHARS))
1420         return AFPERR_PARAM;
1421
1422     upath = mtoupath(vol, path);
1423
1424     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
1425       return AFPERR_PARAM;
1426
1427     if (!validupath(vol, upath))
1428       return AFPERR_EXIST;
1429
1430     /* check for vetoed filenames */
1431     if (veto_file(vol->v_veto, upath))
1432         return AFPERR_EXIST;
1433
1434 #ifdef FORCE_UIDGID
1435     save_uidgid ( &uidgid );
1436     set_uidgid  ( vol );
1437 #endif /* FORCE_UIDGID */
1438
1439     if ( ad_mkdir( upath, DIRBITS | 0777 ) < 0 ) {
1440 #ifdef FORCE_UIDGID
1441         restore_uidgid ( &uidgid );
1442 #endif /* FORCE_UIDGID */
1443         switch ( errno ) {
1444         case ENOENT :
1445             return( AFPERR_NOOBJ );
1446         case EROFS :
1447             return( AFPERR_VLOCK );
1448         case EACCES :
1449             return( AFPERR_ACCESS );
1450         case EEXIST :
1451             return( AFPERR_EXIST );
1452         case ENOSPC :
1453         case EDQUOT :
1454             return( AFPERR_DFULL );
1455         default :
1456             return( AFPERR_PARAM );
1457         }
1458     }
1459
1460     if (stat(upath, &st) < 0) {
1461 #ifdef FORCE_UIDGID
1462       restore_uidgid ( &uidgid );
1463 #endif /* FORCE_UIDGID */
1464       return AFPERR_MISC;
1465         }
1466
1467     if ((dir = adddir( vol, curdir, path, strlen( path ), upath,
1468                        strlen(upath), &st)) == NULL) {
1469 #ifdef FORCE_UIDGID
1470       restore_uidgid ( &uidgid );
1471 #endif /* FORCE_UIDGID */
1472       return AFPERR_MISC;
1473         }
1474
1475     if ( movecwd( vol, dir ) < 0 ) {
1476 #ifdef FORCE_UIDGID
1477       restore_uidgid ( &uidgid );
1478 #endif /* FORCE_UIDGID */
1479         return( AFPERR_PARAM );
1480     }
1481
1482     memset(&ad, 0, sizeof(ad));
1483     if (ad_open( "", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
1484                  O_RDWR|O_CREAT, 0666, &ad ) < 0)  {
1485       if (vol_noadouble(vol))
1486           goto createdir_done;
1487 #ifdef FORCE_UIDGID
1488       restore_uidgid ( &uidgid );
1489 #endif /* FORCE_UIDGID */
1490       return( AFPERR_ACCESS );
1491     }
1492     
1493     ad_setentrylen( &ad, ADEID_NAME, strlen( path ));
1494     memcpy( ad_entry( &ad, ADEID_NAME ), path, 
1495            ad_getentrylen( &ad, ADEID_NAME ));
1496     ad_flush( &ad, ADFLAGS_HF );
1497     ad_close( &ad, ADFLAGS_HF );
1498
1499 createdir_done:
1500     memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
1501     *rbuflen = sizeof( u_int32_t );
1502     setvoltime(obj, vol );
1503 #ifdef FORCE_UIDGID
1504     restore_uidgid ( &uidgid );
1505 #endif /* FORCE_UIDGID */
1506     return( AFP_OK );
1507 }
1508
1509
1510 int renamedir(src, dst, dir, newparent, newname, noadouble)
1511     char        *src, *dst, *newname;
1512     struct dir  *dir, *newparent;
1513     const int noadouble;
1514 {
1515     struct adouble      ad;
1516     struct dir          *parent;
1517     char                *buf;
1518     int                 len, err;
1519
1520     /* existence check moved to afp_moveandrename */
1521     if ( rename( src, dst ) < 0 ) {
1522         switch ( errno ) {
1523         case ENOENT :
1524             return( AFPERR_NOOBJ );
1525         case EACCES :
1526             return( AFPERR_ACCESS );
1527         case EROFS:
1528             return AFPERR_VLOCK;
1529         case EINVAL: 
1530             /* tried to move directory into a subdirectory of itself */
1531             return AFPERR_CANTMOVE;
1532         case EXDEV:
1533           /* this needs to copy and delete. bleah. that means we have
1534            * to deal with entire directory hierarchies. */
1535             if ((err = copydir(src, dst, noadouble)) < 0) {
1536                deletedir(dst);
1537                return err;
1538             }
1539             if ((err = deletedir(src)) < 0)
1540                return err;
1541             break;
1542         default : 
1543             return( AFPERR_PARAM );
1544         }
1545     }
1546
1547     memset(&ad, 0, sizeof(ad));
1548     if ( ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad) < 0 ) {
1549         switch ( errno ) {
1550         case ENOENT :
1551             if (noadouble) {
1552               len = strlen(newname);
1553               goto renamedir_done;
1554             }
1555             return( AFPERR_NOOBJ );
1556         case EACCES :
1557             return( AFPERR_ACCESS );
1558         default : 
1559             return( AFPERR_PARAM );
1560         }
1561     }
1562     len = strlen( newname );
1563     ad_setentrylen( &ad, ADEID_NAME, len );
1564     memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
1565     ad_flush( &ad, ADFLAGS_HF );
1566     ad_close( &ad, ADFLAGS_HF );
1567
1568 renamedir_done:
1569     if ((buf = (char *) realloc( dir->d_name, len + 1 )) == NULL ) {
1570         syslog( LOG_ERR, "renamedir: realloc: %s", strerror(errno) );
1571         return AFPERR_MISC;
1572     }
1573     dir->d_name = buf;
1574     strcpy( dir->d_name, newname );
1575
1576     if (( parent = dir->d_parent ) == NULL ) {
1577         return( AFP_OK );
1578     }
1579     if ( parent == newparent ) {
1580         return( AFP_OK );
1581     }
1582
1583     /* detach from old parent and add to new one. */
1584     dirchildremove(parent, dir);
1585     dir->d_parent = newparent;
1586     dirchildadd(newparent, dir);
1587     return( AFP_OK );
1588 }
1589
1590 #define DOT_APPLEDOUBLE_LEN 13
1591 /* delete an empty directory */
1592 int deletecurdir( vol, path, pathlen )
1593     const struct vol    *vol;
1594     char *path;
1595     int pathlen;
1596 {
1597     struct dirent *de;
1598     struct stat st;
1599     struct dir  *fdir;
1600     DIR *dp;
1601 #ifdef FORCE_UIDGID
1602     uidgidset           *uidgid;
1603
1604     memset(&uidgid, 0, sizeof(uidgid));
1605 #endif /* FORCE_UIDGID */
1606
1607     if ( curdir->d_parent == NULL ) {
1608         return( AFPERR_ACCESS );
1609     }
1610
1611     if ( curdir->d_child != NULL ) {
1612         return( AFPERR_DIRNEMPT );
1613     }
1614
1615     fdir = curdir;
1616
1617 #ifdef FORCE_UIDGID
1618     save_uidgid ( &uidgid );
1619     set_uidgid  ( vol );
1620 #endif /* FORCE_UIDGID */
1621
1622     /* delete stray .AppleDouble files. this happens to get .Parent files
1623        as well. */
1624     if ((dp = opendir(".AppleDouble"))) {
1625       strcpy(path, ".AppleDouble/");
1626       while ((de = readdir(dp))) {
1627         /* skip this and previous directory */
1628         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1629           continue;
1630
1631         /* bail if the file exists in the current directory.
1632          * note: this will not fail with dangling symlinks */
1633         if (stat(de->d_name, &st) == 0) {
1634           closedir(dp);
1635 #ifdef FORCE_UIDGID
1636         restore_uidgid ( &uidgid );
1637 #endif /* FORCE_UIDGID */
1638           return AFPERR_DIRNEMPT;
1639         }
1640
1641         strcpy(path + DOT_APPLEDOUBLE_LEN, de->d_name);
1642         if (unlink(path) < 0) {
1643           closedir(dp);
1644           switch (errno) {
1645           case EPERM:
1646           case EACCES :
1647 #ifdef FORCE_UIDGID
1648             restore_uidgid ( &uidgid );
1649 #endif /* FORCE_UIDGID */
1650             return( AFPERR_ACCESS );
1651           case EROFS:
1652 #ifdef FORCE_UIDGID
1653             restore_uidgid ( &uidgid );
1654 #endif /* FORCE_UIDGID */
1655             return AFPERR_VLOCK;
1656           case ENOENT :
1657             continue;
1658           default :
1659 #ifdef FORCE_UIDGID
1660             restore_uidgid ( &uidgid );
1661 #endif /* FORCE_UIDGID */
1662             return( AFPERR_PARAM );
1663           }
1664         }
1665       }
1666       closedir(dp);
1667     }
1668     
1669     if ( rmdir( ".AppleDouble" ) < 0 ) {
1670         switch ( errno ) {
1671         case ENOENT :
1672             break;
1673         case ENOTEMPTY :
1674 #ifdef FORCE_UIDGID
1675             restore_uidgid ( &uidgid );
1676 #endif /* FORCE_UIDGID */
1677             return( AFPERR_DIRNEMPT );
1678         case EROFS:
1679 #ifdef FORCE_UIDGID
1680             restore_uidgid ( &uidgid );
1681 #endif /* FORCE_UIDGID */
1682             return AFPERR_VLOCK;
1683         case EPERM:
1684         case EACCES :
1685 #ifdef FORCE_UIDGID
1686             restore_uidgid ( &uidgid );
1687 #endif /* FORCE_UIDGID */
1688             return( AFPERR_ACCESS );
1689         default :
1690 #ifdef FORCE_UIDGID
1691             restore_uidgid ( &uidgid );
1692 #endif /* FORCE_UIDGID */
1693             return( AFPERR_PARAM );
1694         }
1695     }
1696
1697     /* now get rid of dangling symlinks */
1698     if ((dp = opendir("."))) {
1699       while ((de = readdir(dp))) {
1700         /* skip this and previous directory */
1701         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1702           continue;
1703
1704         /* bail if it's not a symlink */
1705         if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
1706 #ifdef FORCE_UIDGID
1707           restore_uidgid ( &uidgid );
1708 #endif /* FORCE_UIDGID */
1709           return AFPERR_DIRNEMPT;
1710         }
1711
1712         if (unlink(de->d_name) < 0) {
1713           switch (errno) {
1714           case EPERM:
1715           case EACCES :
1716 #ifdef FORCE_UIDGID
1717             restore_uidgid ( &uidgid );
1718 #endif /* FORCE_UIDGID */
1719             return( AFPERR_ACCESS );
1720           case EROFS:
1721 #ifdef FORCE_UIDGID
1722             restore_uidgid ( &uidgid );
1723 #endif /* FORCE_UIDGID */
1724             return AFPERR_VLOCK;
1725           case ENOENT :
1726             continue;
1727           default :
1728 #ifdef FORCE_UIDGID
1729             restore_uidgid ( &uidgid );
1730 #endif /* FORCE_UIDGID */
1731             return( AFPERR_PARAM );
1732           }
1733         }
1734       }
1735       closedir(dp);
1736     }
1737
1738     if ( movecwd( vol, curdir->d_parent ) < 0 ) {
1739 #ifdef FORCE_UIDGID
1740         restore_uidgid ( &uidgid );
1741 #endif /* FORCE_UIDGID */
1742         return( AFPERR_NOOBJ );
1743     }
1744
1745     if ( rmdir(mtoupath(vol, fdir->d_name)) < 0 ) {
1746         switch ( errno ) {
1747         case ENOENT :
1748 #ifdef FORCE_UIDGID
1749             restore_uidgid ( &uidgid );
1750 #endif /* FORCE_UIDGID */
1751             return( AFPERR_NOOBJ );
1752         case ENOTEMPTY :
1753 #ifdef FORCE_UIDGID
1754             restore_uidgid ( &uidgid );
1755 #endif /* FORCE_UIDGID */
1756             return( AFPERR_DIRNEMPT );
1757         case EPERM:
1758         case EACCES :
1759 #ifdef FORCE_UIDGID
1760             restore_uidgid ( &uidgid );
1761 #endif /* FORCE_UIDGID */
1762             return( AFPERR_ACCESS );
1763         case EROFS:
1764 #ifdef FORCE_UIDGID
1765             restore_uidgid ( &uidgid );
1766 #endif /* FORCE_UIDGID */
1767             return AFPERR_VLOCK;
1768         default : 
1769 #ifdef FORCE_UIDGID
1770             restore_uidgid ( &uidgid );
1771 #endif /* FORCE_UIDGID */
1772             return( AFPERR_PARAM );
1773         }
1774     }
1775
1776     dirchildremove(curdir, fdir);
1777 #ifdef CNID_DB
1778     cnid_delete(vol->v_db, fdir->d_did);
1779 #endif /* CNID_DB */
1780     dir_remove( vol, fdir );
1781
1782 #ifdef FORCE_UIDGID
1783     restore_uidgid ( &uidgid );
1784 #endif /* FORCE_UIDGID */
1785     return( AFP_OK );
1786 }
1787
1788 int afp_mapid(obj, ibuf, ibuflen, rbuf, rbuflen )
1789     AFPObj      *obj;
1790     char        *ibuf, *rbuf;
1791     int         ibuflen, *rbuflen;
1792 {
1793     struct passwd       *pw;
1794     struct group        *gr;
1795     char                *name;
1796     u_int32_t           id;
1797     int                 len, sfunc;
1798
1799     ibuf++;
1800     sfunc = (unsigned char) *ibuf++;
1801     memcpy( &id, ibuf, sizeof( id ));
1802
1803     id = ntohl(id);
1804
1805     if ( id != 0 ) {
1806         switch ( sfunc ) {
1807         case 1 :
1808             if (( pw = getpwuid( id )) == NULL ) {
1809                 *rbuflen = 0;
1810                 return( AFPERR_NOITEM );
1811             }
1812             name = pw->pw_name;
1813             break;
1814
1815         case 2 :
1816             if (( gr = (struct group *)getgrgid( id )) == NULL ) {
1817                 *rbuflen = 0;
1818                 return( AFPERR_NOITEM );
1819             }
1820             name = gr->gr_name;
1821             break;
1822
1823         default :
1824             *rbuflen = 0;
1825             return( AFPERR_PARAM );
1826         }
1827
1828         len = strlen( name );
1829
1830     } else {
1831         len = 0;
1832         name = NULL;
1833     }
1834
1835     *rbuf++ = len;
1836     if ( len > 0 ) {
1837         memcpy( rbuf, name, len );
1838     }
1839     *rbuflen = len + 1;
1840     return( AFP_OK );
1841 }
1842
1843 int afp_mapname(obj, ibuf, ibuflen, rbuf, rbuflen )
1844     AFPObj      *obj;
1845     char        *ibuf, *rbuf;
1846     int         ibuflen, *rbuflen;
1847 {
1848     struct passwd       *pw;
1849     struct group        *gr;
1850     int                 len, sfunc;
1851     u_int32_t           id;
1852
1853     ibuf++;
1854     sfunc = (unsigned char) *ibuf++;
1855     len = (unsigned char) *ibuf++;
1856     ibuf[ len ] = '\0';
1857
1858     if ( len != 0 ) {
1859         switch ( sfunc ) {
1860         case 3 :
1861             if (( pw = (struct passwd *)getpwnam( ibuf )) == NULL ) {
1862                 *rbuflen = 0;
1863                 return( AFPERR_NOITEM );
1864             }
1865             id = pw->pw_uid;
1866             break;
1867
1868         case 4 :
1869             if (( gr = (struct group *)getgrnam( ibuf )) == NULL ) {
1870                 *rbuflen = 0;
1871                 return( AFPERR_NOITEM );
1872             }
1873             id = gr->gr_gid;
1874             break;
1875         default :
1876             *rbuflen = 0;
1877             return( AFPERR_PARAM );
1878         }
1879     } else {
1880         id = 0;
1881     }
1882     id = htonl(id);
1883     memcpy( rbuf, &id, sizeof( id ));
1884     *rbuflen = sizeof( id );
1885     return( AFP_OK );
1886 }
1887
1888 /* variable DID support */
1889 int afp_closedir(obj, ibuf, ibuflen, rbuf, rbuflen )
1890     AFPObj      *obj;
1891     char        *ibuf, *rbuf;
1892     int         ibuflen, *rbuflen;
1893 {
1894 #if 0
1895     struct vol   *vol;
1896     struct dir   *dir;
1897     u_int16_t    vid;
1898     u_int32_t    did;
1899 #endif /* 0 */
1900
1901    *rbuflen = 0;
1902
1903   /* do nothing as dids are static for the life of the process. */
1904 #if 0
1905     ibuf += 2;
1906
1907     memcpy(&vid,  ibuf, sizeof( vid ));
1908     ibuf += sizeof( vid );
1909     if (( vol = getvolbyvid( vid )) == NULL ) {
1910         return( AFPERR_PARAM );
1911     }
1912
1913     memcpy( &did, ibuf, sizeof( did ));
1914     ibuf += sizeof( did );
1915     if (( dir = dirsearch( vol, did )) == NULL ) {
1916         return( AFPERR_PARAM );
1917     }
1918
1919     /* dir_remove -- deletedid */
1920 #endif /* 0 */
1921
1922     return AFP_OK;
1923 }
1924
1925 /* did creation gets done automatically */
1926 int afp_opendir(obj, ibuf, ibuflen, rbuf, rbuflen )
1927     AFPObj      *obj;
1928     char        *ibuf, *rbuf;
1929     int         ibuflen, *rbuflen;
1930 {
1931     struct vol          *vol;
1932     struct dir          *dir, *parentdir;
1933     struct stat         st;
1934     char                *path, *upath;
1935     u_int32_t           did;
1936     u_int16_t           vid;
1937 #ifdef FORCE_UIDGID
1938     uidgidset           *uidgid;
1939
1940     memset(&uidgid, 0, sizeof(uidgid));
1941 #endif /* FORCE_UIDGID */
1942
1943     *rbuflen = 0;
1944     ibuf += 2;
1945
1946     memcpy(&vid, ibuf, sizeof(vid));
1947     ibuf += sizeof( vid );
1948
1949     if (( vol = getvolbyvid( vid )) == NULL ) {
1950         return( AFPERR_PARAM );
1951     }
1952
1953     memcpy(&did, ibuf, sizeof(did));
1954     ibuf += sizeof(did);
1955
1956     if (( parentdir = dirsearch( vol, did )) == NULL ) {
1957         return( AFPERR_NOOBJ );
1958     }
1959
1960     if (( path = cname( vol, parentdir, &ibuf )) == NULL ) {
1961         return( AFPERR_NOOBJ );
1962     }
1963
1964     /* see if we already have the directory. */
1965     upath = mtoupath(vol, path);
1966     if ( stat( upath, &st ) < 0 ) {
1967         return( AFPERR_NOOBJ );
1968     }
1969
1970     dir = parentdir->d_child;
1971     while (dir) {
1972       if (strdiacasecmp(dir->d_name, path) == 0) {
1973         memcpy(rbuf, &dir->d_did, sizeof(dir->d_did));
1974         *rbuflen = sizeof(dir->d_did);
1975         return AFP_OK;
1976       }    
1977       dir = (dir == parentdir->d_child->d_prev) ? NULL : dir->d_next;
1978     }
1979
1980 #ifdef FORCE_UIDGID
1981     save_uidgid ( &uidgid );
1982     set_uidgid  ( vol );
1983 #endif /* FORCE_UIDGID */
1984
1985     /* we don't already have a did. add one in. */
1986     if ((dir = adddir(vol, parentdir, path, strlen(path), 
1987                       upath, strlen(upath), &st)) == NULL) {
1988 #ifdef FORCE_UIDGID
1989       restore_uidgid ( &uidgid );
1990 #endif /* FORCE_UIDGID */
1991       return AFPERR_MISC;
1992         }
1993
1994     memcpy(rbuf, &dir->d_did, sizeof(dir->d_did));
1995     *rbuflen = sizeof(dir->d_did);
1996 #ifdef FORCE_UIDGID
1997     restore_uidgid ( &uidgid );
1998 #endif /* FORCE_UIDGID */
1999     return AFP_OK;
2000 }