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