]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/directory.c
Warning fixes.
[netatalk.git] / etc / afpd / directory.c
1 /*
2  * $Id: directory.c,v 1.16 2001-08-15 01:37:34 srittau 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                   /* now check against too long a filename */
940                   if (strlen(utompath(vol, de->d_name)) > MACFILELEN)
941                     continue;
942
943                   ashort++;
944                 }
945                 closedir( dp );
946             }
947             ashort = htons( ashort );
948             memcpy( data, &ashort, sizeof( ashort ));
949             data += sizeof( ashort );
950             break;
951
952         case DIRPBIT_UID :
953             aint = htonl(st->st_uid);
954             memcpy( data, &aint, sizeof( aint ));
955             data += sizeof( aint );
956             break;
957
958         case DIRPBIT_GID :
959             aint = htonl(st->st_gid);
960             memcpy( data, &aint, sizeof( aint ));
961             data += sizeof( aint );
962             break;
963
964         case DIRPBIT_ACCESS :
965             utommode( st, &ma );
966 #ifndef SENDFILE_FLAVOR_LINUX /* ignore this section if it's linux */
967 #ifdef HAVE_ACCESS
968             accessmode( upath, &ma, dir );
969 #endif /* HAVE_ACCESS */
970 #endif /* SENDFILE_FLAVOR_LINUX */
971 #ifdef AFS      /* If only AFS defined, access() works only for AFS filesystems */ 
972             afsmode( upath, &ma, dir );
973 #endif /* AFS */
974             *data++ = ma.ma_user;
975             *data++ = ma.ma_world;
976             *data++ = ma.ma_group;
977             *data++ = ma.ma_owner;
978             break;
979
980             /* Client has requested the ProDOS information block.
981                Just pass back the same basic block for all
982                directories. <shirsch@ibm.net> */
983         case DIRPBIT_PDINFO :                     /* ProDOS Info Block */
984             *data++ = 0x0f;
985             *data++ = 0;
986             ashort = htons( 0x0200 );
987             memcpy( data, &ashort, sizeof( ashort ));
988             data += sizeof( ashort );
989             memset( data, 0, sizeof( ashort ));
990             data += sizeof( ashort );
991             break;
992
993         default :
994             if ( isad ) {
995               ad_close( &ad, ADFLAGS_HF );
996             }
997 #ifdef FORCE_UIDGID
998             restore_uidgid ( &uidgid );
999 #endif /* FORCE_UIDGID */
1000             return( AFPERR_BITMAP );
1001         }
1002         bitmap = bitmap>>1;
1003         bit++;
1004     }
1005     if ( nameoff ) {
1006         ashort = htons( data - buf );
1007         memcpy( nameoff, &ashort, sizeof( ashort ));
1008
1009         if ((aint = strlen( dir->d_name )) > MACFILELEN)
1010           aint = MACFILELEN;
1011           
1012         *data++ = aint;
1013         memcpy( data, dir->d_name, aint );
1014         data += aint;
1015     }
1016     if ( isad ) {
1017         ad_close( &ad, ADFLAGS_HF );
1018     }
1019     *buflen = data - buf;
1020     return( AFP_OK );
1021 }
1022
1023 int afp_setdirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1024     AFPObj      *obj;
1025     char        *ibuf, *rbuf;
1026     int         ibuflen, *rbuflen;
1027 {
1028     struct vol  *vol;
1029     struct dir  *dir;
1030     char        *path;
1031     u_int16_t   vid, bitmap;
1032     u_int32_t   did;
1033     int         rc;
1034
1035     *rbuflen = 0;
1036     ibuf += 2;
1037     memcpy( &vid, ibuf, sizeof( vid ));
1038     ibuf += sizeof( vid );
1039
1040     if (( vol = getvolbyvid( vid )) == NULL ) {
1041         return( AFPERR_PARAM );
1042     }
1043
1044     if (vol->v_flags & AFPVOL_RO)
1045         return AFPERR_VLOCK;
1046
1047     memcpy( &did, ibuf, sizeof( did ));
1048     ibuf += sizeof( int );
1049
1050     if (( dir = dirsearch( vol, did )) == NULL ) {
1051         return( AFPERR_NOOBJ );
1052     }
1053
1054     memcpy( &bitmap, ibuf, sizeof( bitmap ));
1055     bitmap = ntohs( bitmap );
1056     ibuf += sizeof( bitmap );
1057
1058     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1059         return( AFPERR_NOOBJ );
1060     }
1061
1062     /*
1063      * If ibuf is odd, make it even.
1064      */
1065     if ((u_long)ibuf & 1 ) {
1066         ibuf++;
1067     }
1068
1069     if (( rc = setdirparams(vol, path, bitmap, ibuf )) == AFP_OK ) {
1070         setvoltime(obj, vol );
1071     }
1072     return( rc );
1073 }
1074
1075 int setdirparams(const struct vol *vol,
1076                  char *path, u_int16_t bitmap, char *buf )
1077 {
1078     struct maccess      ma;
1079     struct adouble      ad;
1080     struct utimbuf      ut;
1081     char                *upath;
1082     int                 bit = 0, aint, isad = 1;
1083     u_int16_t           ashort, bshort;
1084     int                 err = AFP_OK;
1085 #ifdef FORCE_UIDGID
1086     uidgidset           *uidgid;
1087
1088     memset(&uidgid, 0, sizeof(uidgid));
1089 #endif /* FORCE_UIDGID */
1090
1091     upath = mtoupath(vol, path);
1092     memset(&ad, 0, sizeof(ad));
1093 #ifdef FORCE_UIDGID
1094     save_uidgid ( &uidgid );
1095 #endif /* FORCE_UIDGID */
1096     if (ad_open( upath, vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR, 
1097                  O_RDWR|O_CREAT, 0666, &ad) < 0) {
1098         /*
1099          * Check to see what we're trying to set.  If it's anything
1100          * but ACCESS, UID, or GID, give an error.  If it's any of those
1101          * three, we don't need the ad to be open, so just continue.
1102          *
1103          * note: we also don't need to worry about mdate. also, be quiet
1104          *       if we're using the noadouble option.
1105          */
1106         if (!vol_noadouble(vol) && (bitmap &
1107                 ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
1108                   (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
1109 #ifdef FORCE_UIDGID
1110           restore_uidgid ( &uidgid );
1111 #endif /* FORCE_UIDGID */
1112           return AFPERR_ACCESS;
1113         }
1114
1115         isad = 0;
1116     } else {
1117         /*
1118          * Check to see if a create was necessary. If it was, we'll want
1119          * to set our name, etc.
1120          */
1121         if ( ad_getoflags( &ad, ADFLAGS_HF ) & O_CREAT ) {
1122             ad_setentrylen( &ad, ADEID_NAME, strlen( curdir->d_name ));
1123             memcpy( ad_entry( &ad, ADEID_NAME ), curdir->d_name, 
1124                     ad_getentrylen( &ad, ADEID_NAME ));
1125         }
1126     }
1127
1128     while ( bitmap != 0 ) {
1129         while (( bitmap & 1 ) == 0 ) {
1130             bitmap = bitmap>>1;
1131             bit++;
1132         }
1133
1134         switch( bit ) {
1135         case DIRPBIT_ATTR :
1136             if (isad) {
1137               memcpy( &ashort, buf, sizeof( ashort ));
1138               ad_getattr(&ad, &bshort);
1139               if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
1140                 bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
1141               } else {
1142                 bshort &= ~ashort;
1143               }
1144               ad_setattr(&ad, bshort);
1145             }
1146             buf += sizeof( ashort );
1147             break;
1148
1149         case DIRPBIT_CDATE :
1150             if (isad) {
1151               memcpy(&aint, buf, sizeof(aint));
1152               ad_setdate(&ad, AD_DATE_CREATE, aint);
1153             }
1154             buf += sizeof( aint );
1155             break;
1156
1157         case DIRPBIT_MDATE :
1158             memcpy(&aint, buf, sizeof(aint));
1159             if (isad)
1160               ad_setdate(&ad, AD_DATE_MODIFY, aint);
1161             ut.actime = ut.modtime = AD_DATE_TO_UNIX(aint);
1162             utime(upath, &ut);
1163             buf += sizeof( aint );
1164             break;
1165
1166         case DIRPBIT_BDATE :
1167             if (isad) {
1168               memcpy(&aint, buf, sizeof(aint));
1169               ad_setdate(&ad, AD_DATE_BACKUP, aint);
1170             }
1171             buf += sizeof( aint );
1172             break;
1173
1174         case DIRPBIT_FINFO :
1175             /*
1176              * Alright, we admit it, this is *really* sick!
1177              * The 4 bytes that we don't copy, when we're dealing
1178              * with the root of a volume, are the directory's
1179              * location information. This eliminates that annoying
1180              * behavior one sees when mounting above another mount
1181              * point.
1182              */
1183             if (isad) {
1184               if (  curdir->d_did == DIRDID_ROOT ) {
1185                 memcpy( ad_entry( &ad, ADEID_FINDERI ), buf, 10 );
1186                 memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, buf + 14, 18 );
1187               } else {
1188                 memcpy( ad_entry( &ad, ADEID_FINDERI ), buf, 32 );
1189               }
1190             } 
1191             buf += 32;
1192             break;
1193
1194         case DIRPBIT_UID :      /* What kind of loser mounts as root? */
1195             memcpy( &aint, buf, sizeof(aint));
1196             buf += sizeof( aint );
1197             if ( (curdir->d_did == DIRDID_ROOT) &&
1198                  (setdeskowner( ntohl(aint), -1 ) < 0)) {
1199                 switch ( errno ) {
1200                 case EPERM :
1201                 case EACCES :
1202                     err = AFPERR_ACCESS;
1203                     goto setdirparam_done;
1204                     break;
1205                 case EROFS :
1206                     err = AFPERR_VLOCK;
1207                     goto setdirparam_done;
1208                     break;
1209                 default :
1210                     syslog( LOG_ERR, "setdirparam: setdeskowner: %s",
1211                             strerror(errno) );
1212                     if (!isad) {
1213                     err = AFPERR_PARAM;
1214                     goto setdirparam_done;
1215                     }
1216                     break;
1217                 }
1218             }
1219             if ( setdirowner( ntohl(aint), -1, vol_noadouble(vol) ) < 0 ) {
1220                 switch ( errno ) {
1221                 case EPERM :
1222                 case EACCES :
1223                     err = AFPERR_ACCESS;
1224                     goto setdirparam_done;
1225                     break;
1226                 case EROFS :
1227                     err = AFPERR_VLOCK;
1228                     goto setdirparam_done;
1229                     break;
1230                 default :
1231                     syslog( LOG_ERR, "setdirparam: setdirowner: %s",
1232                             strerror(errno) );
1233                     break;
1234                 }
1235             }
1236             break;
1237         case DIRPBIT_GID :
1238             memcpy( &aint, buf, sizeof( aint ));
1239             buf += sizeof( aint );
1240             if (curdir->d_did == DIRDID_ROOT)
1241               setdeskowner( -1, ntohl(aint) );
1242
1243 #if 0       /* don't error if we can't set the desktop owner. */
1244                 switch ( errno ) {
1245                 case EPERM :
1246                 case EACCES :
1247                     err = AFPERR_ACCESS;
1248                     goto setdirparam_done;
1249                     break;
1250                 case EROFS :
1251                     err = AFPERR_VLOCK;
1252                     goto setdirparam_done;
1253                     break;
1254                 default :
1255                     syslog( LOG_ERR, "setdirparam: setdeskowner: %m" );
1256                     if (!isad) {
1257                       err = AFPERR_PARAM;
1258                       goto setdirparam_done;
1259                     }
1260                     break;
1261                 }
1262 #endif /* 0 */
1263
1264             if ( setdirowner( -1, ntohl(aint), vol_noadouble(vol) ) < 0 ) {
1265                 switch ( errno ) {
1266                 case EPERM :
1267                 case EACCES :
1268                     err = AFPERR_ACCESS;
1269                     goto setdirparam_done;
1270                     break;
1271                 case EROFS :
1272                     err = AFPERR_VLOCK;
1273                     goto setdirparam_done;
1274                     break;
1275                 default :
1276                     syslog( LOG_ERR, "setdirparam: setdirowner: %s",
1277                             strerror(errno) );
1278                     break;
1279                 }
1280             }
1281             break;
1282
1283         case DIRPBIT_ACCESS :
1284             ma.ma_user = *buf++;
1285             ma.ma_world = *buf++;
1286             ma.ma_group = *buf++;
1287             ma.ma_owner = *buf++;
1288
1289             if (curdir->d_did == DIRDID_ROOT) 
1290                  setdeskmode(mtoumode( &ma ));
1291 #if 0 /* don't error if we can't set the desktop mode */
1292                 switch ( errno ) {
1293                 case EPERM :
1294                 case EACCES :
1295                     err = AFPERR_ACCESS;
1296                     goto setdirparam_done;
1297                 case EROFS :
1298                     err = AFPERR_VLOCK;
1299                     goto setdirparam_done;
1300                 default :
1301                     syslog( LOG_ERR, "setdirparam: setdeskmode: %s",
1302                             strerror(errno) );
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: %s",
1322                             strerror(errno) );
1323                     err = AFPERR_PARAM;
1324                     goto setdirparam_done;
1325                 }
1326             }
1327             break;
1328             
1329             /* Ignore what the client thinks we should do to the
1330                ProDOS information block.  Skip over the data and
1331                report nothing amiss. <shirsch@ibm.net> */
1332         case DIRPBIT_PDINFO :
1333             buf += 6;
1334             break;
1335
1336         default :
1337             err = AFPERR_BITMAP;
1338             goto setdirparam_done;
1339             break;
1340         }
1341
1342         bitmap = bitmap>>1;
1343         bit++;
1344     }
1345
1346
1347 setdirparam_done:
1348     if ( isad ) {
1349         ad_flush( &ad, ADFLAGS_HF );
1350         ad_close( &ad, ADFLAGS_HF );
1351     }
1352
1353 #ifdef FORCE_UIDGID
1354     restore_uidgid ( &uidgid );
1355 #endif /* FORCE_UIDGID */
1356     return err;
1357 }
1358
1359 int afp_createdir(obj, ibuf, ibuflen, rbuf, rbuflen )
1360     AFPObj      *obj;
1361     char        *ibuf, *rbuf;
1362     int         ibuflen, *rbuflen;
1363 {
1364     struct adouble      ad;
1365     struct stat         st;
1366     struct vol          *vol;
1367     struct dir          *dir;
1368     char                *path, *upath;
1369     u_int32_t           did;
1370     u_int16_t           vid;
1371 #ifdef FORCE_UIDGID
1372     uidgidset           *uidgid;
1373
1374     memset(&uidgid, 0, sizeof(uidgid));
1375 #endif /* FORCE_UIDGID */
1376
1377     *rbuflen = 0;
1378     ibuf += 2;
1379
1380     memcpy( &vid, ibuf, sizeof( vid ));
1381     ibuf += sizeof( vid );
1382     if (( vol = getvolbyvid( vid )) == NULL ) {
1383         return( AFPERR_PARAM );
1384     }
1385
1386     if (vol->v_flags & AFPVOL_RO)
1387         return AFPERR_VLOCK;
1388
1389     memcpy( &did, ibuf, sizeof( did ));
1390     ibuf += sizeof( did );
1391     if (( dir = dirsearch( vol, did )) == NULL ) {
1392         return( AFPERR_NOOBJ );
1393     }
1394
1395     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
1396         return( AFPERR_NOOBJ );
1397     }
1398
1399     /* check for illegal bits */
1400     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
1401         strpbrk(path, MSWINDOWS_BADCHARS))
1402         return AFPERR_PARAM;
1403
1404     upath = mtoupath(vol, path);
1405
1406     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
1407       return AFPERR_PARAM;
1408
1409     if (!validupath(vol, upath))
1410       return AFPERR_EXIST;
1411
1412 #ifdef FORCE_UIDGID
1413     save_uidgid ( &uidgid );
1414     set_uidgid  ( vol );
1415 #endif /* FORCE_UIDGID */
1416
1417     if ( ad_mkdir( upath, DIRBITS | 0777 ) < 0 ) {
1418 #ifdef FORCE_UIDGID
1419         restore_uidgid ( &uidgid );
1420 #endif /* FORCE_UIDGID */
1421         switch ( errno ) {
1422         case ENOENT :
1423             return( AFPERR_NOOBJ );
1424         case EROFS :
1425             return( AFPERR_VLOCK );
1426         case EACCES :
1427             return( AFPERR_ACCESS );
1428         case EEXIST :
1429             return( AFPERR_EXIST );
1430         case ENOSPC :
1431         case EDQUOT :
1432             return( AFPERR_DFULL );
1433         default :
1434             return( AFPERR_PARAM );
1435         }
1436     }
1437
1438     if (stat(upath, &st) < 0) {
1439 #ifdef FORCE_UIDGID
1440       restore_uidgid ( &uidgid );
1441 #endif /* FORCE_UIDGID */
1442       return AFPERR_MISC;
1443         }
1444
1445     if ((dir = adddir( vol, curdir, path, strlen( path ), upath,
1446                        strlen(upath), &st)) == NULL) {
1447 #ifdef FORCE_UIDGID
1448       restore_uidgid ( &uidgid );
1449 #endif /* FORCE_UIDGID */
1450       return AFPERR_MISC;
1451         }
1452
1453     if ( movecwd( vol, dir ) < 0 ) {
1454 #ifdef FORCE_UIDGID
1455       restore_uidgid ( &uidgid );
1456 #endif /* FORCE_UIDGID */
1457         return( AFPERR_PARAM );
1458     }
1459
1460     memset(&ad, 0, sizeof(ad));
1461     if (ad_open( "", vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR,
1462                  O_RDWR|O_CREAT, 0666, &ad ) < 0)  {
1463       if (vol_noadouble(vol))
1464           goto createdir_done;
1465 #ifdef FORCE_UIDGID
1466       restore_uidgid ( &uidgid );
1467 #endif /* FORCE_UIDGID */
1468       return( AFPERR_ACCESS );
1469     }
1470     
1471     ad_setentrylen( &ad, ADEID_NAME, strlen( path ));
1472     memcpy( ad_entry( &ad, ADEID_NAME ), path, 
1473            ad_getentrylen( &ad, ADEID_NAME ));
1474     ad_flush( &ad, ADFLAGS_HF );
1475     ad_close( &ad, ADFLAGS_HF );
1476
1477 createdir_done:
1478     memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
1479     *rbuflen = sizeof( u_int32_t );
1480     setvoltime(obj, vol );
1481 #ifdef FORCE_UIDGID
1482     restore_uidgid ( &uidgid );
1483 #endif /* FORCE_UIDGID */
1484     return( AFP_OK );
1485 }
1486
1487
1488 int renamedir(src, dst, dir, newparent, newname, noadouble)
1489     char        *src, *dst, *newname;
1490     struct dir  *dir, *newparent;
1491     const int noadouble;
1492 {
1493     struct adouble      ad;
1494     struct dir          *parent;
1495     char                *buf;
1496     int                 len, err;
1497
1498     /* existence check moved to afp_moveandrename */
1499     if ( rename( src, dst ) < 0 ) {
1500         switch ( errno ) {
1501         case ENOENT :
1502             return( AFPERR_NOOBJ );
1503         case EACCES :
1504             return( AFPERR_ACCESS );
1505         case EROFS:
1506             return AFPERR_VLOCK;
1507         case EINVAL: 
1508             /* tried to move directory into a subdirectory of itself */
1509             return AFPERR_CANTMOVE;
1510         case EXDEV:
1511           /* this needs to copy and delete. bleah. that means we have
1512            * to deal with entire directory hierarchies. */
1513             if ((err = copydir(src, dst, noadouble)) < 0) {
1514                deletedir(dst);
1515                return err;
1516             }
1517             if ((err = deletedir(src)) < 0)
1518                return err;
1519             break;
1520         default : 
1521             return( AFPERR_PARAM );
1522         }
1523     }
1524
1525     memset(&ad, 0, sizeof(ad));
1526     if ( ad_open( dst, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0, &ad) < 0 ) {
1527         switch ( errno ) {
1528         case ENOENT :
1529             if (noadouble) {
1530               len = strlen(newname);
1531               goto renamedir_done;
1532             }
1533             return( AFPERR_NOOBJ );
1534         case EACCES :
1535             return( AFPERR_ACCESS );
1536         default : 
1537             return( AFPERR_PARAM );
1538         }
1539     }
1540     len = strlen( newname );
1541     ad_setentrylen( &ad, ADEID_NAME, len );
1542     memcpy( ad_entry( &ad, ADEID_NAME ), newname, len );
1543     ad_flush( &ad, ADFLAGS_HF );
1544     ad_close( &ad, ADFLAGS_HF );
1545
1546 renamedir_done:
1547     if ((buf = (char *) realloc( dir->d_name, len + 1 )) == NULL ) {
1548         syslog( LOG_ERR, "renamedir: realloc: %s", strerror(errno) );
1549         return AFPERR_MISC;
1550     }
1551     dir->d_name = buf;
1552     strcpy( dir->d_name, newname );
1553
1554     if (( parent = dir->d_parent ) == NULL ) {
1555         return( AFP_OK );
1556     }
1557     if ( parent == newparent ) {
1558         return( AFP_OK );
1559     }
1560
1561     /* detach from old parent and add to new one. */
1562     dirchildremove(parent, dir);
1563     dir->d_parent = newparent;
1564     dirchildadd(newparent, dir);
1565     return( AFP_OK );
1566 }
1567
1568 #define DOT_APPLEDOUBLE_LEN 13
1569 /* delete an empty directory */
1570 int deletecurdir( vol, path, pathlen )
1571     const struct vol    *vol;
1572     char *path;
1573     int pathlen;
1574 {
1575     struct dirent *de;
1576     struct stat st;
1577     struct dir  *fdir;
1578     DIR *dp;
1579 #ifdef FORCE_UIDGID
1580     uidgidset           *uidgid;
1581
1582     memset(&uidgid, 0, sizeof(uidgid));
1583 #endif /* FORCE_UIDGID */
1584
1585     if ( curdir->d_parent == NULL ) {
1586         return( AFPERR_ACCESS );
1587     }
1588
1589     if ( curdir->d_child != NULL ) {
1590         return( AFPERR_DIRNEMPT );
1591     }
1592
1593     fdir = curdir;
1594
1595 #ifdef FORCE_UIDGID
1596     save_uidgid ( &uidgid );
1597     set_uidgid  ( vol );
1598 #endif /* FORCE_UIDGID */
1599
1600     /* delete stray .AppleDouble files. this happens to get .Parent files
1601        as well. */
1602     if ((dp = opendir(".AppleDouble"))) {
1603       strcpy(path, ".AppleDouble/");
1604       while ((de = readdir(dp))) {
1605         /* skip this and previous directory */
1606         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1607           continue;
1608
1609         /* bail if the file exists in the current directory.
1610          * note: this will not fail with dangling symlinks */
1611         if (stat(de->d_name, &st) == 0) {
1612           closedir(dp);
1613 #ifdef FORCE_UIDGID
1614         restore_uidgid ( &uidgid );
1615 #endif /* FORCE_UIDGID */
1616           return AFPERR_DIRNEMPT;
1617         }
1618
1619         strcpy(path + DOT_APPLEDOUBLE_LEN, de->d_name);
1620         if (unlink(path) < 0) {
1621           closedir(dp);
1622           switch (errno) {
1623           case EPERM:
1624           case EACCES :
1625 #ifdef FORCE_UIDGID
1626             restore_uidgid ( &uidgid );
1627 #endif /* FORCE_UIDGID */
1628             return( AFPERR_ACCESS );
1629           case EROFS:
1630 #ifdef FORCE_UIDGID
1631             restore_uidgid ( &uidgid );
1632 #endif /* FORCE_UIDGID */
1633             return AFPERR_VLOCK;
1634           case ENOENT :
1635             continue;
1636           default :
1637 #ifdef FORCE_UIDGID
1638             restore_uidgid ( &uidgid );
1639 #endif /* FORCE_UIDGID */
1640             return( AFPERR_PARAM );
1641           }
1642         }
1643       }
1644       closedir(dp);
1645     }
1646     
1647     if ( rmdir( ".AppleDouble" ) < 0 ) {
1648         switch ( errno ) {
1649         case ENOENT :
1650             break;
1651         case ENOTEMPTY :
1652 #ifdef FORCE_UIDGID
1653             restore_uidgid ( &uidgid );
1654 #endif /* FORCE_UIDGID */
1655             return( AFPERR_DIRNEMPT );
1656         case EROFS:
1657 #ifdef FORCE_UIDGID
1658             restore_uidgid ( &uidgid );
1659 #endif /* FORCE_UIDGID */
1660             return AFPERR_VLOCK;
1661         case EPERM:
1662         case EACCES :
1663 #ifdef FORCE_UIDGID
1664             restore_uidgid ( &uidgid );
1665 #endif /* FORCE_UIDGID */
1666             return( AFPERR_ACCESS );
1667         default :
1668 #ifdef FORCE_UIDGID
1669             restore_uidgid ( &uidgid );
1670 #endif /* FORCE_UIDGID */
1671             return( AFPERR_PARAM );
1672         }
1673     }
1674
1675     /* now get rid of dangling symlinks */
1676     if ((dp = opendir("."))) {
1677       while ((de = readdir(dp))) {
1678         /* skip this and previous directory */
1679         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
1680           continue;
1681
1682         /* bail if it's not a symlink */
1683         if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
1684 #ifdef FORCE_UIDGID
1685           restore_uidgid ( &uidgid );
1686 #endif /* FORCE_UIDGID */
1687           return AFPERR_DIRNEMPT;
1688         }
1689
1690         if (unlink(de->d_name) < 0) {
1691           switch (errno) {
1692           case EPERM:
1693           case EACCES :
1694 #ifdef FORCE_UIDGID
1695             restore_uidgid ( &uidgid );
1696 #endif /* FORCE_UIDGID */
1697             return( AFPERR_ACCESS );
1698           case EROFS:
1699 #ifdef FORCE_UIDGID
1700             restore_uidgid ( &uidgid );
1701 #endif /* FORCE_UIDGID */
1702             return AFPERR_VLOCK;
1703           case ENOENT :
1704             continue;
1705           default :
1706 #ifdef FORCE_UIDGID
1707             restore_uidgid ( &uidgid );
1708 #endif /* FORCE_UIDGID */
1709             return( AFPERR_PARAM );
1710           }
1711         }
1712       }
1713       closedir(dp);
1714     }
1715
1716     if ( movecwd( vol, curdir->d_parent ) < 0 ) {
1717 #ifdef FORCE_UIDGID
1718         restore_uidgid ( &uidgid );
1719 #endif /* FORCE_UIDGID */
1720         return( AFPERR_NOOBJ );
1721     }
1722
1723     if ( rmdir(mtoupath(vol, fdir->d_name)) < 0 ) {
1724         switch ( errno ) {
1725         case ENOENT :
1726 #ifdef FORCE_UIDGID
1727             restore_uidgid ( &uidgid );
1728 #endif /* FORCE_UIDGID */
1729             return( AFPERR_NOOBJ );
1730         case ENOTEMPTY :
1731 #ifdef FORCE_UIDGID
1732             restore_uidgid ( &uidgid );
1733 #endif /* FORCE_UIDGID */
1734             return( AFPERR_DIRNEMPT );
1735         case EPERM:
1736         case EACCES :
1737 #ifdef FORCE_UIDGID
1738             restore_uidgid ( &uidgid );
1739 #endif /* FORCE_UIDGID */
1740             return( AFPERR_ACCESS );
1741         case EROFS:
1742 #ifdef FORCE_UIDGID
1743             restore_uidgid ( &uidgid );
1744 #endif /* FORCE_UIDGID */
1745             return AFPERR_VLOCK;
1746         default : 
1747 #ifdef FORCE_UIDGID
1748             restore_uidgid ( &uidgid );
1749 #endif /* FORCE_UIDGID */
1750             return( AFPERR_PARAM );
1751         }
1752     }
1753
1754     dirchildremove(curdir, fdir);
1755 #ifdef CNID_DB
1756     cnid_delete(vol->v_db, fdir->d_did);
1757 #endif /* CNID_DB */
1758     dir_remove( vol, fdir );
1759
1760 #ifdef FORCE_UIDGID
1761     restore_uidgid ( &uidgid );
1762 #endif /* FORCE_UIDGID */
1763     return( AFP_OK );
1764 }
1765
1766 int afp_mapid(obj, ibuf, ibuflen, rbuf, rbuflen )
1767     AFPObj      *obj;
1768     char        *ibuf, *rbuf;
1769     int         ibuflen, *rbuflen;
1770 {
1771     struct passwd       *pw;
1772     struct group        *gr;
1773     char                *name;
1774     u_int32_t           id;
1775     int                 len, sfunc;
1776
1777     ibuf++;
1778     sfunc = (unsigned char) *ibuf++;
1779     memcpy( &id, ibuf, sizeof( id ));
1780
1781     id = ntohl(id);
1782
1783     if ( id != 0 ) {
1784         switch ( sfunc ) {
1785         case 1 :
1786             if (( pw = getpwuid( id )) == NULL ) {
1787                 *rbuflen = 0;
1788                 return( AFPERR_NOITEM );
1789             }
1790             name = pw->pw_name;
1791             break;
1792
1793         case 2 :
1794             if (( gr = (struct group *)getgrgid( id )) == NULL ) {
1795                 *rbuflen = 0;
1796                 return( AFPERR_NOITEM );
1797             }
1798             name = gr->gr_name;
1799             break;
1800
1801         default :
1802             *rbuflen = 0;
1803             return( AFPERR_PARAM );
1804         }
1805
1806         len = strlen( name );
1807
1808     } else {
1809         len = 0;
1810         name = NULL;
1811     }
1812
1813     *rbuf++ = len;
1814     if ( len > 0 ) {
1815         memcpy( rbuf, name, len );
1816     }
1817     *rbuflen = len + 1;
1818     return( AFP_OK );
1819 }
1820
1821 int afp_mapname(obj, ibuf, ibuflen, rbuf, rbuflen )
1822     AFPObj      *obj;
1823     char        *ibuf, *rbuf;
1824     int         ibuflen, *rbuflen;
1825 {
1826     struct passwd       *pw;
1827     struct group        *gr;
1828     int                 len, sfunc;
1829     u_int32_t           id;
1830
1831     ibuf++;
1832     sfunc = (unsigned char) *ibuf++;
1833     len = (unsigned char) *ibuf++;
1834     ibuf[ len ] = '\0';
1835
1836     if ( len != 0 ) {
1837         switch ( sfunc ) {
1838         case 3 :
1839             if (( pw = (struct passwd *)getpwnam( ibuf )) == NULL ) {
1840                 *rbuflen = 0;
1841                 return( AFPERR_NOITEM );
1842             }
1843             id = pw->pw_uid;
1844             break;
1845
1846         case 4 :
1847             if (( gr = (struct group *)getgrnam( ibuf )) == NULL ) {
1848                 *rbuflen = 0;
1849                 return( AFPERR_NOITEM );
1850             }
1851             id = gr->gr_gid;
1852             break;
1853         default :
1854             *rbuflen = 0;
1855             return( AFPERR_PARAM );
1856         }
1857     } else {
1858         id = 0;
1859     }
1860     id = htonl(id);
1861     memcpy( rbuf, &id, sizeof( id ));
1862     *rbuflen = sizeof( id );
1863     return( AFP_OK );
1864 }
1865
1866 /* variable DID support */
1867 int afp_closedir(obj, ibuf, ibuflen, rbuf, rbuflen )
1868     AFPObj      *obj;
1869     char        *ibuf, *rbuf;
1870     int         ibuflen, *rbuflen;
1871 {
1872 #if 0
1873     struct vol   *vol;
1874     struct dir   *dir;
1875     u_int16_t    vid;
1876     u_int32_t    did;
1877 #endif /* 0 */
1878
1879    *rbuflen = 0;
1880
1881   /* do nothing as dids are static for the life of the process. */
1882 #if 0
1883     ibuf += 2;
1884
1885     memcpy(&vid,  ibuf, sizeof( vid ));
1886     ibuf += sizeof( vid );
1887     if (( vol = getvolbyvid( vid )) == NULL ) {
1888         return( AFPERR_PARAM );
1889     }
1890
1891     memcpy( &did, ibuf, sizeof( did ));
1892     ibuf += sizeof( did );
1893     if (( dir = dirsearch( vol, did )) == NULL ) {
1894         return( AFPERR_PARAM );
1895     }
1896
1897     /* dir_remove -- deletedid */
1898 #endif /* 0 */
1899
1900     return AFP_OK;
1901 }
1902
1903 /* did creation gets done automatically */
1904 int afp_opendir(obj, ibuf, ibuflen, rbuf, rbuflen )
1905     AFPObj      *obj;
1906     char        *ibuf, *rbuf;
1907     int         ibuflen, *rbuflen;
1908 {
1909     struct vol          *vol;
1910     struct dir          *dir, *parentdir;
1911     struct stat         st;
1912     char                *path, *upath;
1913     u_int32_t           did;
1914     u_int16_t           vid;
1915 #ifdef FORCE_UIDGID
1916     uidgidset           *uidgid;
1917
1918     memset(&uidgid, 0, sizeof(uidgid));
1919 #endif /* FORCE_UIDGID */
1920
1921     *rbuflen = 0;
1922     ibuf += 2;
1923
1924     memcpy(&vid, ibuf, sizeof(vid));
1925     ibuf += sizeof( vid );
1926
1927     if (( vol = getvolbyvid( vid )) == NULL ) {
1928         return( AFPERR_PARAM );
1929     }
1930
1931     memcpy(&did, ibuf, sizeof(did));
1932     ibuf += sizeof(did);
1933
1934     if (( parentdir = dirsearch( vol, did )) == NULL ) {
1935         return( AFPERR_NOOBJ );
1936     }
1937
1938     if (( path = cname( vol, parentdir, &ibuf )) == NULL ) {
1939         return( AFPERR_NOOBJ );
1940     }
1941
1942     /* see if we already have the directory. */
1943     upath = mtoupath(vol, path);
1944     if ( stat( upath, &st ) < 0 ) {
1945         return( AFPERR_NOOBJ );
1946     }
1947
1948     dir = parentdir->d_child;
1949     while (dir) {
1950       if (strdiacasecmp(dir->d_name, path) == 0) {
1951         memcpy(rbuf, &dir->d_did, sizeof(dir->d_did));
1952         *rbuflen = sizeof(dir->d_did);
1953         return AFP_OK;
1954       }    
1955       dir = (dir == parentdir->d_child->d_prev) ? NULL : dir->d_next;
1956     }
1957
1958 #ifdef FORCE_UIDGID
1959     save_uidgid ( &uidgid );
1960     set_uidgid  ( vol );
1961 #endif /* FORCE_UIDGID */
1962
1963     /* we don't already have a did. add one in. */
1964     if ((dir = adddir(vol, parentdir, path, strlen(path), 
1965                       upath, strlen(upath), &st)) == NULL) {
1966 #ifdef FORCE_UIDGID
1967       restore_uidgid ( &uidgid );
1968 #endif /* FORCE_UIDGID */
1969       return AFPERR_MISC;
1970         }
1971
1972     memcpy(rbuf, &dir->d_did, sizeof(dir->d_did));
1973     *rbuflen = sizeof(dir->d_did);
1974 #ifdef FORCE_UIDGID
1975     restore_uidgid ( &uidgid );
1976 #endif /* FORCE_UIDGID */
1977     return AFP_OK;
1978 }