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