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