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