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