]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/directory.c
9917dd43358173c6e0a0fed5e3757b495476d325
[netatalk.git] / etc / afpd / directory.c
1 /*
2  * $Id: directory.c,v 1.125 2010-01-06 11:08:53 franklahm 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 /* STDC check */
16 #if STDC_HEADERS
17 #include <string.h>
18 #else /* STDC_HEADERS */
19 #ifndef HAVE_STRCHR
20 #define strchr index
21 #define strrchr index
22 #endif /* HAVE_STRCHR */
23 char *strchr (), *strrchr ();
24 #ifndef HAVE_MEMCPY
25 #define memcpy(d,s,n) bcopy ((s), (d), (n))
26 #define memmove(d,s,n) bcopy ((s), (d), (n))
27 #endif /* ! HAVE_MEMCPY */
28 #endif /* STDC_HEADERS */
29 #ifdef HAVE_STRINGS_H
30 #include <strings.h>
31 #endif
32 #include <stdio.h>
33 #include <stdlib.h>
34
35 #include <grp.h>
36 #include <pwd.h>
37 #include <sys/param.h>
38 #include <errno.h>
39 #include <utime.h>
40
41 #include <atalk/adouble.h>
42 #include <atalk/vfs.h>
43 #include <atalk/afp.h>
44 #include <atalk/util.h>
45 #include <atalk/cnid.h>
46 #include <atalk/logger.h>
47 #include <atalk/uuid.h>
48 #include <atalk/unix.h>
49
50 #include "directory.h"
51 #include "desktop.h"
52 #include "volume.h"
53 #include "fork.h"
54 #include "file.h"
55 #include "filedir.h"
56 #include "globals.h"
57 #include "unix.h"
58 #include "mangle.h"
59 #include "hash.h"
60
61 #ifdef HAVE_NFSv4_ACLS
62 extern void addir_inherit_acl(const struct vol *vol);
63 #endif
64
65 struct dir  *curdir;
66 int             afp_errno;
67
68 #define SENTINEL (&sentinel)
69 static struct dir sentinel = { SENTINEL, SENTINEL, NULL, DIRTREE_COLOR_BLACK,
70                                NULL, NULL, NULL, NULL, NULL, 0, 0,
71                                0, 0, NULL, NULL, 0, NULL};
72 static struct dir rootpar  = { SENTINEL, SENTINEL, NULL, 0,
73                                NULL, NULL, NULL, NULL, NULL, 0, 0,
74                                0, 0, NULL, NULL, 0, NULL};
75
76 /* (from IM: Toolbox Essentials)
77  * dirFinderInfo (DInfo) fields:
78  * field        bytes
79  * frRect       8    folder's window rectangle
80  * frFlags      2    flags
81  * frLocation   4    folder's location in window
82  * frView       2    folder's view (default == closedView (256))
83  *
84  * extended dirFinderInfo (DXInfo) fields:
85  * frScroll     4    scroll position
86  * frOpenChain: 4    directory ID chain of open folders
87  * frScript:    1    script flag and code
88  * frXFlags:    1    reserved
89  * frComment:   2    comment ID
90  * frPutAway:   4    home directory ID
91  */
92
93 static struct dir *
94 vol_tree_root(const struct vol *vol, u_int32_t did)
95 {
96     struct dir *dir;
97
98     if (vol->v_curdir && vol->v_curdir->d_did == did) {
99         dir = vol->v_curdir;
100     }
101     else {
102         dir = vol->v_root;
103     }
104     return dir;
105 }
106
107 /*
108  * redid did assignment for directories. now we use red-black trees.
109  * how exciting.
110  */
111 struct dir *
112 dirsearch(const struct vol *vol, u_int32_t did)
113 {
114     struct dir  *dir;
115
116
117     /* check for 0 did */
118     if (!did) {
119         afp_errno = AFPERR_PARAM;
120         return NULL;
121     }
122     if ( did == DIRDID_ROOT_PARENT ) {
123         if (!rootpar.d_did)
124             rootpar.d_did = DIRDID_ROOT_PARENT;
125         rootpar.d_child = vol->v_dir;
126         return( &rootpar );
127     }
128
129     dir = vol_tree_root(vol, did);
130
131     afp_errno = AFPERR_NOOBJ;
132     while ( dir != SENTINEL ) {
133         if (dir->d_did == did)
134             return dir->d_m_name ? dir : NULL;
135         dir = (dir->d_did > did) ? dir->d_left : dir->d_right;
136     }
137     return NULL;
138 }
139
140 /* ------------------- */
141 int get_afp_errno(const int param)
142 {
143     if (afp_errno != AFPERR_DID1)
144         return afp_errno;
145     return param;
146 }
147
148 /* ------------------- */
149 struct dir *
150 dirsearch_byname( const struct vol *vol, struct dir *cdir, char *name)
151 {
152     struct dir *dir = NULL;
153
154     if ((cdir->d_did != DIRDID_ROOT_PARENT) && (cdir->d_child)) {
155         struct dir key;
156         hnode_t *hn;
157
158         key.d_parent = cdir;
159         key.d_u_name = name;
160         key.d_u_name_len = strlen(name);
161         hn = hash_lookup(vol->v_hash, &key);
162         if (hn) {
163             dir = hnode_get(hn);
164         }
165     }
166     return dir;
167 }
168
169 /* -----------------------------------------
170  * if did is not in the cache resolve it with cnid
171  *
172  * FIXME
173  * OSX call it with bogus id, ie file ID not folder ID,
174  * and we are really bad in this case.
175  */
176 struct dir *
177 dirlookup( struct vol *vol, u_int32_t did)
178 {
179     struct dir   *ret;
180     char     *upath;
181     cnid_t       id, cnid;
182     static char  path[MAXPATHLEN + 1];
183     size_t len,  pathlen;
184     char         *ptr;
185     static char  buffer[12 + MAXPATHLEN + 1];
186     int          buflen = 12 + MAXPATHLEN + 1;
187     char         *mpath;
188     int          utf8;
189     size_t       maxpath;
190
191     ret = dirsearch(vol, did);
192     if (ret != NULL || afp_errno == AFPERR_PARAM)
193         return ret;
194
195     utf8 = utf8_encoding();
196     maxpath = (utf8)?MAXPATHLEN -7:255;
197     id = did;
198     if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen)) ) {
199         afp_errno = AFPERR_NOOBJ;
200         return NULL;
201     }
202     ptr = path + MAXPATHLEN;
203     if (NULL == ( mpath = utompath(vol, upath, did, utf8) ) ) {
204         afp_errno = AFPERR_NOOBJ;
205         return NULL;
206     }
207     len = strlen(mpath);
208     pathlen = len;          /* no 0 in the last part */
209     len++;
210     strcpy(ptr - len, mpath);
211     ptr -= len;
212     while (1) {
213         ret = dirsearch(vol,id);
214         if (ret != NULL) {
215             break;
216         }
217         cnid = id;
218         if ( NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, buflen))
219              ||
220              NULL == (mpath = utompath(vol, upath, cnid, utf8))
221             ) {
222             afp_errno = AFPERR_NOOBJ;
223             return NULL;
224         }
225
226         len = strlen(mpath) + 1;
227         pathlen += len;
228         if (pathlen > maxpath) {
229             afp_errno = AFPERR_PARAM;
230             return NULL;
231         }
232         strcpy(ptr - len, mpath);
233         ptr -= len;
234     }
235
236     /* fill the cache, another place where we know about the path type */
237     if (utf8) {
238         u_int16_t temp16;
239         u_int32_t temp;
240
241         ptr -= 2;
242         temp16 = htons(pathlen);
243         memcpy(ptr, &temp16, sizeof(temp16));
244
245         temp = htonl(kTextEncodingUTF8);
246         ptr -= 4;
247         memcpy(ptr, &temp, sizeof(temp));
248         ptr--;
249         *ptr = 3;
250     }
251     else {
252         ptr--;
253         *ptr = (unsigned char)pathlen;
254         ptr--;
255         *ptr = 2;
256     }
257     /* cname is not efficient */
258     if (cname( vol, ret, &ptr ) == NULL )
259         return NULL;
260
261     return dirsearch(vol, did);
262 }
263
264 /* child addition/removal */
265 static void dirchildadd(const struct vol *vol, struct dir *a, struct dir *b)
266 {
267     if (!a->d_child)
268         a->d_child = b;
269     else {
270         b->d_next = a->d_child;
271         b->d_prev = b->d_next->d_prev;
272         b->d_next->d_prev = b;
273         b->d_prev->d_next = b;
274     }
275     if (!hash_alloc_insert(vol->v_hash, b, b)) {
276         LOG(log_error, logtype_afpd, "dirchildadd: can't hash %s", b->d_u_name);
277     }
278 }
279
280 static void dirchildremove(struct dir *a,struct dir *b)
281 {
282     if (a->d_child == b)
283         a->d_child = (b == b->d_next) ? NULL : b->d_next;
284     b->d_next->d_prev = b->d_prev;
285     b->d_prev->d_next = b->d_next;
286     b->d_next = b->d_prev = b;
287 }
288
289 /* --------------------------- */
290 /* rotate the tree to the left */
291 static void dir_leftrotate(struct vol *vol, struct dir *dir)
292 {
293     struct dir *right = dir->d_right;
294
295     /* whee. move the right's left tree into dir's right tree */
296     dir->d_right = right->d_left;
297     if (right->d_left != SENTINEL)
298         right->d_left->d_back = dir;
299
300     if (right != SENTINEL) {
301         right->d_back = dir->d_back;
302         right->d_left = dir;
303     }
304
305     if (!dir->d_back) /* no parent. move the right tree to the top. */
306         vol->v_root = right;
307     else if (dir == dir->d_back->d_left) /* we were on the left */
308         dir->d_back->d_left = right;
309     else
310         dir->d_back->d_right = right; /* we were on the right */
311
312     /* re-insert dir on the left tree */
313     if (dir != SENTINEL)
314         dir->d_back = right;
315 }
316
317
318
319 /* rotate the tree to the right */
320 static void dir_rightrotate(struct vol *vol, struct dir *dir)
321 {
322     struct dir *left = dir->d_left;
323
324     /* whee. move the left's right tree into dir's left tree */
325     dir->d_left = left->d_right;
326     if (left->d_right != SENTINEL)
327         left->d_right->d_back = dir;
328
329     if (left != SENTINEL) {
330         left->d_back = dir->d_back;
331         left->d_right = dir;
332     }
333
334     if (!dir->d_back) /* no parent. move the left tree to the top. */
335         vol->v_root = left;
336     else if (dir == dir->d_back->d_right) /* we were on the right */
337         dir->d_back->d_right = left;
338     else
339         dir->d_back->d_left = left; /* we were on the left */
340
341     /* re-insert dir on the right tree */
342     if (dir != SENTINEL)
343         dir->d_back = left;
344 }
345
346 #if 0
347 /* recolor after a removal */
348 static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir)
349 {
350     struct dir *leaf;
351
352     while ((dir != vol->v_root) && (dir->d_color == DIRTREE_COLOR_BLACK)) {
353         /* are we on the left tree? */
354         if (dir == dir->d_back->d_left) {
355             leaf = dir->d_back->d_right; /* get right side */
356             if (leaf->d_color == DIRTREE_COLOR_RED) {
357                 /* we're red. we need to change to black. */
358                 leaf->d_color = DIRTREE_COLOR_BLACK;
359                 dir->d_back->d_color = DIRTREE_COLOR_RED;
360                 dir_leftrotate(vol, dir->d_back);
361                 leaf = dir->d_back->d_right;
362             }
363
364             /* right leaf has black end nodes */
365             if ((leaf->d_left->d_color == DIRTREE_COLOR_BLACK) &&
366                 (leaf->d_right->d_color = DIRTREE_COLOR_BLACK)) {
367                 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
368                 dir = dir->d_back; /* ascend */
369             } else {
370                 if (leaf->d_right->d_color == DIRTREE_COLOR_BLACK) {
371                     leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
372                     leaf->d_color = DIRTREE_COLOR_RED;
373                     dir_rightrotate(vol, leaf);
374                     leaf = dir->d_back->d_right;
375                 }
376                 leaf->d_color = dir->d_back->d_color;
377                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
378                 leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
379                 dir_leftrotate(vol, dir->d_back);
380                 dir = vol->v_root;
381             }
382         } else { /* right tree */
383             leaf = dir->d_back->d_left; /* left tree */
384             if (leaf->d_color == DIRTREE_COLOR_RED) {
385                 leaf->d_color = DIRTREE_COLOR_BLACK;
386                 dir->d_back->d_color = DIRTREE_COLOR_RED;
387                 dir_rightrotate(vol, dir->d_back);
388                 leaf = dir->d_back->d_left;
389             }
390
391             /* left leaf has black end nodes */
392             if ((leaf->d_right->d_color == DIRTREE_COLOR_BLACK) &&
393                 (leaf->d_left->d_color = DIRTREE_COLOR_BLACK)) {
394                 leaf->d_color = DIRTREE_COLOR_RED; /* recolor leaf as red */
395                 dir = dir->d_back; /* ascend */
396             } else {
397                 if (leaf->d_left->d_color == DIRTREE_COLOR_BLACK) {
398                     leaf->d_right->d_color = DIRTREE_COLOR_BLACK;
399                     leaf->d_color = DIRTREE_COLOR_RED;
400                     dir_leftrotate(vol, leaf);
401                     leaf = dir->d_back->d_left;
402                 }
403                 leaf->d_color = dir->d_back->d_color;
404                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
405                 leaf->d_left->d_color = DIRTREE_COLOR_BLACK;
406                 dir_rightrotate(vol, dir->d_back);
407                 dir = vol->v_root;
408             }
409         }
410     }
411     dir->d_color = DIRTREE_COLOR_BLACK;
412
413     return dir;
414 }
415 #endif /* 0 */
416
417 /* --------------------- */
418 static void dir_hash_del(const struct vol *vol, struct dir *dir)
419 {
420     hnode_t *hn;
421
422     hn = hash_lookup(vol->v_hash, dir);
423     if (!hn) {
424         LOG(log_error, logtype_afpd, "dir_hash_del: %s not hashed", dir->d_u_name);
425     }
426     else {
427         hash_delete(vol->v_hash, hn);
428     }
429 }
430
431 /* remove the node from the tree. this is just like insertion, but
432  * different. actually, it has to worry about a bunch of things that
433  * insertion doesn't care about. */
434
435 static void dir_remove( struct vol *vol, struct dir *dir)
436 {
437 #ifdef REMOVE_NODES
438     struct ofork *of, *last;
439     struct dir *node, *leaf;
440 #endif /* REMOVE_NODES */
441
442     if (!dir || (dir == SENTINEL))
443         return;
444
445     /* i'm not sure if it really helps to delete stuff. */
446     dir_hash_del(vol, dir);
447     vol->v_curdir = NULL;
448 #ifndef REMOVE_NODES
449     dirfreename(dir);
450     dir->d_m_name = NULL;
451     dir->d_u_name = NULL;
452     dir->d_m_name_ucs2 = NULL;
453 #else /* ! REMOVE_NODES */
454
455     /* go searching for a node with at most one child */
456     if ((dir->d_left == SENTINEL) || (dir->d_right == SENTINEL)) {
457         node = dir;
458     } else {
459         node = dir->d_right;
460         while (node->d_left != SENTINEL)
461             node = node->d_left;
462     }
463
464     /* get that child */
465     leaf = (node->d_left != SENTINEL) ? node->d_left : node->d_right;
466
467     /* detach node */
468     leaf->d_back = node->d_back;
469     if (!node->d_back) {
470         vol->v_root = leaf;
471     } else if (node == node->d_back->d_left) { /* left tree */
472         node->d_back->d_left = leaf;
473     } else {
474         node->d_back->d_right = leaf;
475     }
476
477     /* we want to free node, but we also want to free the data in dir.
478      * currently, that's d_name and the directory traversal bits.
479      * we just copy the necessary bits and then fix up all the
480      * various pointers to the directory. needless to say, there are
481      * a bunch of places that store the directory struct. */
482     if (node != dir) {
483         struct dir save, *tmp;
484
485         memcpy(&save, dir, sizeof(save));
486         memcpy(dir, node, sizeof(struct dir));
487
488         /* restore the red-black bits */
489         dir->d_left = save.d_left;
490         dir->d_right = save.d_right;
491         dir->d_back = save.d_back;
492         dir->d_color = save.d_color;
493
494         if (node == vol->v_dir) {/* we may need to fix up this pointer */
495             vol->v_dir = dir;
496             rootpar.d_child = vol->v_dir;
497         } else {
498             /* if we aren't the root directory, we have parents and
499              * siblings to worry about */
500             if (dir->d_parent->d_child == node)
501                 dir->d_parent->d_child = dir;
502             dir->d_next->d_prev = dir;
503             dir->d_prev->d_next = dir;
504         }
505
506         /* fix up children. */
507         tmp = dir->d_child;
508         while (tmp) {
509             tmp->d_parent = dir;
510             tmp = (tmp == dir->d_child->d_prev) ? NULL : tmp->d_next;
511         }
512
513         if (node == curdir) /* another pointer to fixup */
514             curdir = dir;
515
516         /* we also need to fix up oforks. bleah */
517         if ((of = dir->d_ofork)) {
518             last = of->of_d_prev;
519             while (of) {
520                 of->of_dir = dir;
521                 of = (last == of) ? NULL : of->of_d_next;
522             }
523         }
524
525         /* set the node's d_name */
526         node->d_m_name = save.d_m_name;
527         node->d_u_name = save.d_u_name;
528         node->d_m_name_ucs2 = save.d_m_name_ucs2;
529     }
530
531     if (node->d_color == DIRTREE_COLOR_BLACK)
532         dir_rmrecolor(vol, leaf);
533
534     if (node->d_m_name_ucs2)
535         free(node->d_u_name_ucs2);
536     if (node->d_u_name != node->d_m_name) {
537         free(node->d_u_name);
538     }
539     free(node->d_m_name);
540     free(node);
541 #endif /* ! REMOVE_NODES */
542 }
543
544 /* ---------------------------------------
545  * remove the node and its childs from the tree
546  *
547  * FIXME what about opened forks with refs to it?
548  * it's an afp specs violation because you can't delete
549  * an opened forks. Now afpd doesn't care about forks opened by other
550  * process. It's fixable within afpd if fnctl_lock, doable with smb and
551  * next to impossible for nfs and local filesystem access.
552  */
553 static void dir_invalidate( struct vol *vol, struct dir *dir)
554 {
555     if (curdir == dir) {
556         /* v_root can't be deleted */
557         if (movecwd(vol, vol->v_root) < 0) {
558             LOG(log_error, logtype_afpd, "cname can't chdir to : %s", vol->v_root);
559         }
560     }
561     /* FIXME */
562     dirchildremove(dir->d_parent, dir);
563     dir_remove( vol, dir );
564 }
565
566 /* ------------------------------------ */
567 static struct dir *dir_insert(const struct vol *vol, struct dir *dir)
568 {
569     struct dir  *pdir;
570
571     pdir = vol_tree_root(vol, dir->d_did);
572     while (pdir->d_did != dir->d_did ) {
573         if ( pdir->d_did > dir->d_did ) {
574             if ( pdir->d_left == SENTINEL ) {
575                 pdir->d_left = dir;
576                 dir->d_back = pdir;
577                 return NULL;
578             }
579             pdir = pdir->d_left;
580         } else {
581             if ( pdir->d_right == SENTINEL ) {
582                 pdir->d_right = dir;
583                 dir->d_back = pdir;
584                 return NULL;
585             }
586             pdir = pdir->d_right;
587         }
588     }
589     return pdir;
590 }
591
592 #define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/"
593
594 int
595 caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
596 {
597     DIR               *dp;
598     struct dirent     *de;
599     int               ret;
600     static u_int32_t  did = 0;
601     static char       cname[MAXPATHLEN];
602     static char       lname[MAXPATHLEN];
603     ucs2_t        u2_path[MAXPATHLEN];
604     ucs2_t        u2_dename[MAXPATHLEN];
605     char          *tmp, *savepath;
606
607     if (!(vol->v_flags & AFPVOL_CASEINSEN))
608         return -1;
609
610     if (veto_file(ENUMVETO, path->u_name))
611         return -1;
612
613     savepath = path->u_name;
614
615     /* very simple cache */
616     if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) {
617         path->u_name = cname;
618         path->d_dir = NULL;
619         if (of_stat( path ) == 0 ) {
620             return 0;
621         }
622         /* something changed, we cannot stat ... */
623         did = 0;
624     }
625
626     if (NULL == ( dp = opendir( "." )) ) {
627         LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name);
628         return -1;
629     }
630
631
632     /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */
633     if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, -1, u2_path, sizeof(u2_path)) )
634         LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name);
635
636     /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */
637     ret = -1;
638     for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
639         if (NULL == check_dirent(vol, de->d_name))
640             continue;
641
642         if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, -1, u2_dename, sizeof(u2_dename)) )
643             continue;
644
645         if (strcasecmp_w( u2_path, u2_dename) == 0) {
646             tmp = path->u_name;
647             strlcpy(cname, de->d_name, sizeof(cname));
648             path->u_name = cname;
649             path->d_dir = NULL;
650             if (of_stat( path ) == 0 ) {
651                 LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name);
652                 strlcpy(lname, tmp, sizeof(lname));
653                 did = dir->d_did;
654                 ret = 0;
655                 break;
656             }
657             else
658                 path->u_name = tmp;
659         }
660
661     }
662     closedir(dp);
663
664     if (ret) {
665         /* invalidate cache */
666         cname[0] = 0;
667         did = 0;
668         path->u_name = savepath;
669     }
670     /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */
671     return ret;
672 }
673
674
675 /*
676  * attempt to extend the current dir. tree to include path
677  * as a side-effect, movecwd to that point and return the new dir
678  */
679 static struct dir *
680 extenddir(struct vol *vol, struct dir *dir, struct path *path)
681 {
682     path->d_dir = NULL;
683
684     if ( path->u_name == NULL) {
685         afp_errno = AFPERR_PARAM;
686         return NULL;
687     }
688
689     if (check_name(vol, path->u_name)) {
690         /* the name is illegal */
691         LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name);
692         path->u_name = NULL;
693         afp_errno = AFPERR_PARAM;
694         return NULL;
695     }
696
697     if (of_stat( path ) != 0 ) {
698         if (!(vol->v_flags & AFPVOL_CASEINSEN))
699             return NULL;
700         else if(caseenumerate(vol, path, dir) != 0)
701             return(NULL);
702     }
703
704     if (!S_ISDIR(path->st.st_mode)) {
705         return( NULL );
706     }
707
708     /* mac name is always with the right encoding (from cname()) */
709     if (( dir = adddir( vol, dir, path)) == NULL ) {
710         return( NULL );
711     }
712
713     path->d_dir = dir;
714     if ( movecwd( vol, dir ) < 0 ) {
715         return( NULL );
716     }
717
718     return( dir );
719 }
720
721 /* -------------------------
722    appledouble mkdir afp error code.
723 */
724 static int netatalk_mkdir(const char *name)
725 {
726     if (ad_mkdir(name, DIRBITS | 0777) < 0) {
727         switch ( errno ) {
728         case ENOENT :
729             return( AFPERR_NOOBJ );
730         case EROFS :
731             return( AFPERR_VLOCK );
732         case EPERM:
733         case EACCES :
734             return( AFPERR_ACCESS );
735         case EEXIST :
736             return( AFPERR_EXIST );
737         case ENOSPC :
738         case EDQUOT :
739             return( AFPERR_DFULL );
740         default :
741             return( AFPERR_PARAM );
742         }
743     }
744     return AFP_OK;
745 }
746
747 /* ------------------- */
748 static int deletedir(char *dir)
749 {
750     char path[MAXPATHLEN + 1];
751     DIR *dp;
752     struct dirent   *de;
753     struct stat st;
754     size_t len;
755     int err = AFP_OK;
756     size_t remain;
757
758     if ((len = strlen(dir)) +2 > sizeof(path))
759         return AFPERR_PARAM;
760
761     /* already gone */
762     if ((dp = opendir(dir)) == NULL)
763         return AFP_OK;
764
765     strcpy(path, dir);
766     strcat(path, "/");
767     len++;
768     remain = sizeof(path) -len -1;
769     while ((de = readdir(dp)) && err == AFP_OK) {
770         /* skip this and previous directory */
771         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
772             continue;
773
774         if (strlen(de->d_name) > remain) {
775             err = AFPERR_PARAM;
776             break;
777         }
778         strcpy(path + len, de->d_name);
779         if (stat(path, &st)) {
780             continue;
781         }
782         if (S_ISDIR(st.st_mode)) {
783             err = deletedir(path);
784         } else {
785             err = netatalk_unlink(path);
786         }
787     }
788     closedir(dp);
789
790     /* okay. the directory is empty. delete it. note: we already got rid
791        of .AppleDouble.  */
792     if (err == AFP_OK) {
793         err = netatalk_rmdir(dir);
794     }
795     return err;
796 }
797
798 /* do a recursive copy. */
799 static int copydir(const struct vol *vol, char *src, char *dst)
800 {
801     char spath[MAXPATHLEN + 1], dpath[MAXPATHLEN + 1];
802     DIR *dp;
803     struct dirent   *de;
804     struct stat st;
805     struct utimbuf      ut;
806     size_t slen, dlen;
807     size_t srem, drem;
808     int err;
809
810     /* doesn't exist or the path is too long. */
811     if (((slen = strlen(src)) > sizeof(spath) - 2) ||
812         ((dlen = strlen(dst)) > sizeof(dpath) - 2) ||
813         ((dp = opendir(src)) == NULL))
814         return AFPERR_PARAM;
815
816     /* try to create the destination directory */
817     if (AFP_OK != (err = netatalk_mkdir(dst)) ) {
818         closedir(dp);
819         return err;
820     }
821
822     /* set things up to copy */
823     strcpy(spath, src);
824     strcat(spath, "/");
825     slen++;
826     srem = sizeof(spath) - slen -1;
827
828     strcpy(dpath, dst);
829     strcat(dpath, "/");
830     dlen++;
831     drem = sizeof(dpath) - dlen -1;
832
833     err = AFP_OK;
834     while ((de = readdir(dp))) {
835         /* skip this and previous directory */
836         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
837             continue;
838
839         if (strlen(de->d_name) > srem) {
840             err = AFPERR_PARAM;
841             break;
842         }
843         strcpy(spath + slen, de->d_name);
844
845         if (stat(spath, &st) == 0) {
846             if (strlen(de->d_name) > drem) {
847                 err = AFPERR_PARAM;
848                 break;
849             }
850             strcpy(dpath + dlen, de->d_name);
851
852             if (S_ISDIR(st.st_mode)) {
853                 if (AFP_OK != (err = copydir(vol, spath, dpath)))
854                     goto copydir_done;
855             } else if (AFP_OK != (err = copyfile(vol, vol, spath, dpath, NULL, NULL))) {
856                 goto copydir_done;
857
858             } else {
859                 /* keep the same time stamp. */
860                 ut.actime = ut.modtime = st.st_mtime;
861                 utime(dpath, &ut);
862             }
863         }
864     }
865
866     /* keep the same time stamp. */
867     if (stat(src, &st) == 0) {
868         ut.actime = ut.modtime = st.st_mtime;
869         utime(dst, &ut);
870     }
871
872 copydir_done:
873     closedir(dp);
874     return err;
875 }
876
877
878 /* --- public functions follow --- */
879
880 /* NOTE: we start off with at least one node (the root directory). */
881 static struct dir *dirinsert(struct vol *vol, struct dir *dir)
882 {
883     struct dir *node;
884
885     if ((node = dir_insert(vol, dir)))
886         return node;
887
888     /* recolor the tree. the current node is red. */
889     dir->d_color = DIRTREE_COLOR_RED;
890
891     /* parent of this node has to be black. if the parent node
892      * is red, then we have a grandparent. */
893     while ((dir != vol->v_root) &&
894            (dir->d_back->d_color == DIRTREE_COLOR_RED)) {
895         /* are we on the left tree? */
896         if (dir->d_back == dir->d_back->d_back->d_left) {
897             node = dir->d_back->d_back->d_right;  /* get the right node */
898             if (node->d_color == DIRTREE_COLOR_RED) {
899                 /* we're red. we need to change to black. */
900                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
901                 node->d_color = DIRTREE_COLOR_BLACK;
902                 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
903                 dir = dir->d_back->d_back; /* finished. go up. */
904             } else {
905                 if (dir == dir->d_back->d_right) {
906                     dir = dir->d_back;
907                     dir_leftrotate(vol, dir);
908                 }
909                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
910                 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
911                 dir_rightrotate(vol, dir->d_back->d_back);
912             }
913         } else {
914             node = dir->d_back->d_back->d_left;
915             if (node->d_color == DIRTREE_COLOR_RED) {
916                 /* we're red. we need to change to black. */
917                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
918                 node->d_color = DIRTREE_COLOR_BLACK;
919                 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
920                 dir = dir->d_back->d_back; /* finished. ascend */
921             } else {
922                 if (dir == dir->d_back->d_left) {
923                     dir = dir->d_back;
924                     dir_rightrotate(vol, dir);
925                 }
926                 dir->d_back->d_color = DIRTREE_COLOR_BLACK;
927                 dir->d_back->d_back->d_color = DIRTREE_COLOR_RED;
928                 dir_leftrotate(vol, dir->d_back->d_back);
929             }
930         }
931     }
932
933     vol->v_root->d_color = DIRTREE_COLOR_BLACK;
934     return NULL;
935 }
936
937 /* ---------------------------- */
938 struct dir *
939 adddir(struct vol *vol, struct dir *dir, struct path *path)
940 {
941     struct dir  *cdir, *edir;
942     int     upathlen;
943     char        *name;
944     char        *upath;
945     struct stat *st;
946     int         deleted;
947     cnid_t      id;
948
949     upath = path->u_name;
950     st    = &path->st;
951     upathlen = strlen(upath);
952
953     id = get_id(vol, NULL, st, dir->d_did, upath, upathlen);
954     if (id == 0) {
955         return NULL;
956     }
957     if (!path->m_name && !(path->m_name = utompath(vol, upath, id , utf8_encoding()))) {
958         return NULL;
959     }
960     name  = path->m_name;
961     if ((cdir = dirnew(name, upath)) == NULL) {
962         LOG(log_error, logtype_afpd, "adddir: malloc: %s", strerror(errno) );
963         return NULL;
964     }
965     if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, path->m_name, -1, (char **)&cdir->d_m_name_ucs2)) {
966         LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name);
967         cdir->d_m_name_ucs2 = NULL;
968     }
969
970     cdir->d_did = id;
971
972     if ((edir = dirinsert( vol, cdir ))) {
973         /* it's not possible with LASTDID
974            for CNID:
975            - someone else have moved the directory.
976            - it's a symlink inside the share.
977            - it's an ID reused, the old directory was deleted but not
978            the cnid record and the server've reused the inode for
979            the new dir.
980            for HASH (we should get ride of HASH)
981            - someone else have moved the directory.
982            - it's an ID reused as above
983            - it's a hash duplicate and we are in big trouble
984         */
985         deleted = (edir->d_m_name == NULL);
986         if (!deleted)
987             dir_hash_del(vol, edir);
988         dirfreename(edir);
989         edir->d_m_name = cdir->d_m_name;
990         edir->d_u_name = cdir->d_u_name;
991         edir->d_u_name_len = cdir->d_u_name_len;
992         edir->d_m_name_ucs2 = cdir->d_m_name_ucs2;
993         free(cdir);
994         cdir = edir;
995         LOG(log_error, logtype_afpd, "adddir: insert %s", edir->d_m_name);
996         if (!cdir->d_parent || (cdir->d_parent == dir && !deleted)) {
997             hash_alloc_insert(vol->v_hash, cdir, cdir);
998             return cdir;
999         }
1000         /* the old was not in the same folder */
1001         if (!deleted)
1002             dirchildremove(cdir->d_parent, cdir);
1003     }
1004
1005     /* parent/child directories */
1006     cdir->d_parent = dir;
1007     dirchildadd(vol, dir, cdir);
1008     return( cdir );
1009 }
1010
1011 /* --- public functions follow --- */
1012 /* free everything down. we don't bother to recolor as this is only
1013  * called to free the entire tree */
1014 void dirfreename(struct dir *dir)
1015 {
1016     if (dir->d_u_name != dir->d_m_name) {
1017         free(dir->d_u_name);
1018     }
1019     if (dir->d_m_name_ucs2)
1020         free(dir->d_m_name_ucs2);
1021     free(dir->d_m_name);
1022 }
1023
1024 void dirfree(struct dir *dir)
1025 {
1026     if (!dir || (dir == SENTINEL))
1027         return;
1028
1029     if ( dir->d_left != SENTINEL ) {
1030         dirfree( dir->d_left );
1031     }
1032     if ( dir->d_right != SENTINEL ) {
1033         dirfree( dir->d_right );
1034     }
1035
1036     if (dir != SENTINEL) {
1037         dirfreename(dir);
1038         free( dir );
1039     }
1040 }
1041
1042 /* --------------------------------------------
1043  * most of the time mac name and unix name are the same
1044  */
1045 struct dir *dirnew(const char *m_name, const char *u_name)
1046 {
1047     struct dir *dir;
1048
1049     dir = (struct dir *) calloc(1, sizeof( struct dir ));
1050     if (!dir)
1051         return NULL;
1052
1053     if ((dir->d_m_name = strdup(m_name)) == NULL) {
1054         free(dir);
1055         return NULL;
1056     }
1057
1058     if (m_name == u_name || !strcmp(m_name, u_name)) {
1059         dir->d_u_name = dir->d_m_name;
1060     }
1061     else if ((dir->d_u_name = strdup(u_name)) == NULL) {
1062         free(dir->d_m_name);
1063         free(dir);
1064         return NULL;
1065     }
1066
1067     dir->d_u_name_len = strlen(dir->d_u_name);
1068     dir->d_m_name_ucs2 = NULL;
1069     dir->d_left = dir->d_right = SENTINEL;
1070     dir->d_next = dir->d_prev = dir;
1071     return dir;
1072 }
1073
1074 /* ------------------ */
1075 static hash_val_t hash_fun_dir(const void *key)
1076 {
1077     const struct dir *k = key;
1078
1079     static unsigned long randbox[] = {
1080         0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U,
1081         0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU,
1082         0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU,
1083         0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU,
1084     };
1085
1086     const unsigned char *str = (unsigned char *)(k->d_u_name);
1087     hash_val_t acc = k->d_parent->d_did;
1088
1089     while (*str) {
1090         acc ^= randbox[(*str + acc) & 0xf];
1091         acc = (acc << 1) | (acc >> 31);
1092         acc &= 0xffffffffU;
1093         acc ^= randbox[((*str++ >> 4) + acc) & 0xf];
1094         acc = (acc << 2) | (acc >> 30);
1095         acc &= 0xffffffffU;
1096     }
1097     return acc;
1098 }
1099
1100 #undef get16bits
1101 #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)    \
1102     || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
1103 #define get16bits(d) (*((const uint16_t *) (d)))
1104 #endif
1105
1106 #if !defined (get16bits)
1107 #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)    \
1108                       +(uint32_t)(((const uint8_t *)(d))[0]) )
1109 #endif
1110
1111 static hash_val_t hash_fun2_dir(const void *key)
1112 {
1113     const struct dir *k = key;
1114     const char *data = k->d_u_name;
1115     int len = k->d_u_name_len;
1116     hash_val_t hash = k->d_parent->d_did, tmp;
1117
1118     int rem = len & 3;
1119     len >>= 2;
1120
1121     /* Main loop */
1122     for (;len > 0; len--) {
1123         hash  += get16bits (data);
1124         tmp    = (get16bits (data+2) << 11) ^ hash;
1125         hash   = (hash << 16) ^ tmp;
1126         data  += 2*sizeof (uint16_t);
1127         hash  += hash >> 11;
1128     }
1129
1130     /* Handle end cases */
1131     switch (rem) {
1132     case 3: hash += get16bits (data);
1133         hash ^= hash << 16;
1134         hash ^= data[sizeof (uint16_t)] << 18;
1135         hash += hash >> 11;
1136         break;
1137     case 2: hash += get16bits (data);
1138         hash ^= hash << 11;
1139         hash += hash >> 17;
1140         break;
1141     case 1: hash += *data;
1142         hash ^= hash << 10;
1143         hash += hash >> 1;
1144     }
1145
1146     /* Force "avalanching" of final 127 bits */
1147     hash ^= hash << 3;
1148     hash += hash >> 5;
1149     hash ^= hash << 4;
1150     hash += hash >> 17;
1151     hash ^= hash << 25;
1152     hash += hash >> 6;
1153
1154     return hash;
1155 }
1156
1157 /* ---------------- */
1158 static int hash_comp_dir(const void *key1, const void *key2)
1159 {
1160     const struct dir *k1 = key1;
1161     const struct dir *k2 = key2;
1162
1163     return !(k1->d_parent->d_did == k2->d_parent->d_did && !strcmp(k1->d_u_name, k2->d_u_name));
1164 }
1165
1166 /* ---------------- */
1167 hash_t *
1168 dirhash(void)
1169 {
1170     return hash_create(HASHCOUNT_T_MAX, hash_comp_dir, hash_fun2_dir);
1171 }
1172
1173 /* ------------------ */
1174 static struct path *invalidate (struct vol *vol, struct dir *dir, struct path *ret)
1175 {
1176     /* it's tricky:
1177        movecwd failed some of dir path are not there anymore.
1178        FIXME Is it true with other errors?
1179        so we remove dir from the cache
1180     */
1181     if (dir->d_did == DIRDID_ROOT_PARENT)
1182         return NULL;
1183     if (afp_errno == AFPERR_ACCESS) {
1184         if ( movecwd( vol, dir->d_parent ) < 0 ) {
1185             return NULL;
1186         }
1187         /* FIXME should we set these?, don't need to call stat() after:
1188            ret->st_valid = 1;
1189            ret->st_errno = EACCES;
1190         */
1191         ret->m_name = dir->d_m_name;
1192         ret->u_name = dir->d_u_name;
1193         ret->d_dir = dir;
1194         return ret;
1195     } else if (afp_errno == AFPERR_NOOBJ) {
1196         if ( movecwd( vol, dir->d_parent ) < 0 ) {
1197             return NULL;
1198         }
1199         strcpy(ret->m_name, dir->d_m_name);
1200         if (dir->d_m_name == dir->d_u_name) {
1201             ret->u_name = ret->m_name;
1202         }
1203         else {
1204             size_t tp = strlen(ret->m_name)+1;
1205
1206             ret->u_name =  ret->m_name +tp;
1207             strcpy(ret->u_name, dir->d_u_name);
1208         }
1209         /* FIXME should we set :
1210            ret->st_valid = 1;
1211            ret->st_errno = ENOENT;
1212         */
1213         dir_invalidate(vol, dir);
1214         return ret;
1215     }
1216     dir_invalidate(vol, dir);
1217     return NULL;
1218 }
1219
1220 /* -------------------------------------------------- */
1221 /* cname
1222    return
1223    if it's a filename:
1224    in extenddir:
1225    compute unix name
1226    stat the file or errno
1227    return
1228    filename
1229    curdir: filename parent directory
1230
1231    if it's a dirname:
1232    not in the cache
1233    in extenddir
1234    compute unix name
1235    stat the dir or errno
1236    return
1237    if chdir error
1238    dirname
1239    curdir: dir parent directory
1240    sinon
1241    dirname: ""
1242    curdir: dir
1243    in the cache
1244    return
1245    if chdir error
1246    dirname
1247    curdir: dir parent directory
1248    else
1249    dirname: ""
1250    curdir: dir
1251
1252 */
1253 struct path *
1254 cname(struct vol *vol, struct dir *dir, char **cpath)
1255 {
1256     struct dir         *cdir, *scdir=NULL;
1257     static char        path[ MAXPATHLEN + 1];
1258     static struct path ret;
1259
1260     char        *data, *p;
1261     int         extend = 0;
1262     int         len;
1263     u_int32_t   hint;
1264     u_int16_t   len16;
1265     int         size = 0;
1266     char        sep;
1267     int         toUTF8 = 0;
1268
1269     data = *cpath;
1270     afp_errno = AFPERR_NOOBJ;
1271     memset(&ret, 0, sizeof(ret));
1272     switch (ret.m_type = *data) { /* path type */
1273     case 2:
1274         data++;
1275         len = (unsigned char) *data++;
1276         size = 2;
1277         sep = 0;
1278         if (afp_version >= 30) {
1279             ret.m_type = 3;
1280             toUTF8 = 1;
1281         }
1282         break;
1283     case 3:
1284         if (afp_version >= 30) {
1285             data++;
1286             memcpy(&hint, data, sizeof(hint));
1287             hint = ntohl(hint);
1288             data += sizeof(hint);
1289
1290             memcpy(&len16, data, sizeof(len16));
1291             len = ntohs(len16);
1292             data += 2;
1293             size = 7;
1294             sep = 0; /* '/';*/
1295             break;
1296         }
1297         /* else it's an error */
1298     default:
1299         afp_errno = AFPERR_PARAM;
1300         return( NULL );
1301     }
1302     *cpath += len + size;
1303     *path = '\0';
1304     ret.m_name = path;
1305     for ( ;; ) {
1306         if ( len == 0 ) {
1307             if (movecwd( vol, dir ) < 0 ) {
1308                 return invalidate(vol, dir, &ret );
1309             }
1310             if (*path == '\0') {
1311                 ret.u_name = ".";
1312                 ret.d_dir = dir;
1313             }
1314             return &ret;
1315         }
1316
1317         if (*data == sep ) {
1318             data++;
1319             len--;
1320         }
1321         while (*data == sep && len > 0 ) {
1322             if ( dir->d_parent == NULL ) {
1323                 return NULL;
1324             }
1325             dir = dir->d_parent;
1326             data++;
1327             len--;
1328         }
1329
1330         /* would this be faster with strlen + strncpy? */
1331         p = path;
1332         while ( *data != sep && len > 0 ) {
1333             *p++ = *data++;
1334             if (p > &path[ MAXPATHLEN]) {
1335                 afp_errno = AFPERR_PARAM;
1336                 return( NULL );
1337             }
1338             len--;
1339         }
1340
1341         /* short cut bits by chopping off a trailing \0. this also
1342            makes the traversal happy w/ filenames at the end of the
1343            cname. */
1344         if (len == 1)
1345             len--;
1346
1347         *p = '\0';
1348
1349         if ( p == path ) { /* end of the name parameter */
1350             continue;
1351         }
1352         ret.u_name = NULL;
1353         if (afp_version >= 30) {
1354             char *t;
1355             cnid_t fileid;
1356
1357             if (toUTF8) {
1358                 static char temp[ MAXPATHLEN + 1];
1359
1360                 if (dir->d_did == DIRDID_ROOT_PARENT) {
1361                     /*
1362                       With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981.
1363                       So we compare it with the longname from the current volume and if they match
1364                       we overwrite the requested path with the utf8 volume name so that the following
1365                       strcmp can match.
1366                     */
1367                     ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1);
1368                     if (strcasecmp( path, temp) == 0)
1369                         ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN);
1370                 } else {
1371                     /* toUTF8 */
1372                     if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) {
1373                         afp_errno = AFPERR_PARAM;
1374                         return( NULL );
1375                     }
1376                     strcpy(path, temp);
1377                 }
1378             }
1379             /* check for OS X mangled filename :( */
1380
1381             t = demangle_osx(vol, path, dir->d_did, &fileid);
1382             if (t != path) {
1383                 ret.u_name = t;
1384                 /* duplicate work but we can't reuse all convert_char we did in demangle_osx
1385                  * flags weren't the same
1386                  */
1387                 if ( (t = utompath(vol, ret.u_name, fileid, utf8_encoding())) ) {
1388                     /* at last got our view of mac name */
1389                     strcpy(path,t);
1390                 }
1391             }
1392         }
1393         if (ret.u_name == NULL) {
1394             if (!(ret.u_name = mtoupath(vol, ret.m_name, dir->d_did, utf8_encoding()))) {
1395                 afp_errno = AFPERR_PARAM;
1396                 return NULL;
1397             }
1398         }
1399         if ( !extend ) {
1400             ucs2_t *tmpname;
1401             cdir = dir->d_child;
1402             scdir = NULL;
1403             if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) &&
1404                  (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset),
1405                                                        CH_UCS2, path, -1, (char **)&tmpname) )
1406             {
1407                 while (cdir) {
1408                     if (!cdir->d_m_name_ucs2) {
1409                         LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) );
1410                         /* this shouldn't happen !!!! */
1411                         goto noucsfallback;
1412                     }
1413
1414                     if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1415                         break;
1416                     }
1417                     if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) {
1418                         scdir = cdir;
1419                     }
1420                     cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next;
1421                 }
1422                 free(tmpname);
1423             }
1424             else {
1425             noucsfallback:
1426                 if (dir->d_did == DIRDID_ROOT_PARENT) {
1427                     /*
1428                       root parent (did 1) has one child: the volume. Requests for did=1 with some <name>
1429                       must check against the volume name.
1430                     */
1431                     if (!strcmp(vol->v_dir->d_m_name, ret.m_name))
1432                         cdir = vol->v_dir;
1433                     else
1434                         cdir = NULL;
1435                 }
1436                 else {
1437                     cdir = dirsearch_byname(vol, dir, ret.u_name);
1438                 }
1439             }
1440
1441             if (cdir == NULL && scdir != NULL) {
1442                 cdir = scdir;
1443                 /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */
1444             }
1445
1446             if ( cdir == NULL ) {
1447                 ++extend;
1448                 /* if dir == curdir it always succeed,
1449                    even if curdir is deleted.
1450                    it's not a pb because it will fail in extenddir
1451                 */
1452                 if ( movecwd( vol, dir ) < 0 ) {
1453                     /* dir is not valid anymore
1454                        we delete dir from the cache and abort.
1455                     */
1456                     if ( dir->d_did == DIRDID_ROOT_PARENT) {
1457                         afp_errno = AFPERR_NOOBJ;
1458                         return NULL;
1459                     }
1460                     if (afp_errno == AFPERR_ACCESS)
1461                         return NULL;
1462                     dir_invalidate(vol, dir);
1463                     return NULL;
1464                 }
1465                 cdir = extenddir( vol, dir, &ret );
1466             }
1467
1468         } else {
1469             cdir = extenddir( vol, dir, &ret );
1470         } /* if (!extend) */
1471
1472         if ( cdir == NULL ) {
1473
1474             if ( len > 0 || !ret.u_name ) {
1475                 return NULL;
1476             }
1477
1478         } else {
1479             dir = cdir;
1480             *path = '\0';
1481         }
1482     } /* for (;;) */
1483 }
1484
1485 /*
1486  * Move curdir to dir, with a possible chdir()
1487  */
1488 int movecwd(struct vol *vol, struct dir *dir)
1489 {
1490     char path[MAXPATHLEN + 1];
1491     struct dir  *d;
1492     char    *p, *u;
1493     int     n;
1494
1495     if ( dir == curdir ) {
1496         return( 0 );
1497     }
1498     if ( dir->d_did == DIRDID_ROOT_PARENT) {
1499         afp_errno = AFPERR_DID1; /* AFPERR_PARAM;*/
1500         return( -1 );
1501     }
1502
1503     p = path + sizeof(path) - 1;
1504     *p-- = '\0';
1505     *p = '.';
1506     for ( d = dir; d->d_parent != NULL && d != curdir; d = d->d_parent ) {
1507         u = d->d_u_name;
1508         if (!u) {
1509             /* parent directory is deleted */
1510             afp_errno = AFPERR_NOOBJ;
1511             return -1;
1512         }
1513         n = strlen( u );
1514         if (p -n -1 < path) {
1515             afp_errno = AFPERR_PARAM;
1516             return -1;
1517         }
1518         *--p = '/';
1519         p -= n;
1520         memcpy( p, u, n );
1521     }
1522     if ( d != curdir ) {
1523         n = strlen( vol->v_path );
1524         if (p -n -1 < path) {
1525             afp_errno = AFPERR_PARAM;
1526             return -1;
1527         }
1528         *--p = '/';
1529         p -= n;
1530         memcpy( p, vol->v_path, n );
1531     }
1532     if ( chdir( p ) < 0 ) {
1533         switch (errno) {
1534         case EACCES:
1535         case EPERM:
1536             afp_errno = AFPERR_ACCESS;
1537             break;
1538         default:
1539             afp_errno = AFPERR_NOOBJ;
1540
1541         }
1542         return( -1 );
1543     }
1544     vol->v_curdir = curdir = dir;
1545     return( 0 );
1546 }
1547
1548 /*
1549  * We can't use unix file's perm to support Apple's inherited protection modes.
1550  * If we aren't the file's owner we can't change its perms when moving it and smb
1551  * nfs,... don't even try.
1552  */
1553 #define AFP_CHECK_ACCESS
1554
1555 int check_access(char *path, int mode)
1556 {
1557 #ifdef AFP_CHECK_ACCESS
1558     struct maccess ma;
1559     char *p;
1560
1561     p = ad_dir(path);
1562     if (!p)
1563         return -1;
1564
1565     accessmode(p, &ma, curdir, NULL);
1566     if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1567         return -1;
1568     if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1569         return -1;
1570 #endif
1571     return 0;
1572 }
1573
1574 /* --------------------- */
1575 int file_access(struct path *path, int mode)
1576 {
1577     struct maccess ma;
1578
1579     accessmode(path->u_name, &ma, curdir, &path->st);
1580     if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
1581         return -1;
1582     if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
1583         return -1;
1584     return 0;
1585
1586 }
1587
1588 /* --------------------- */
1589 void setdiroffcnt(struct dir *dir, struct stat *st,  u_int32_t count)
1590 {
1591     dir->offcnt = count;
1592     dir->ctime = st->st_ctime;
1593     dir->d_flags &= ~DIRF_CNID;
1594 }
1595
1596 /* ---------------------
1597  * is our cached offspring count valid?
1598  */
1599
1600 static int diroffcnt(struct dir *dir, struct stat *st)
1601 {
1602     return st->st_ctime == dir->ctime;
1603 }
1604
1605 /* ---------------------
1606  * is our cached also for reenumerate id?
1607  */
1608
1609 int dirreenumerate(struct dir *dir, struct stat *st)
1610 {
1611     return st->st_ctime == dir->ctime && (dir->d_flags & DIRF_CNID);
1612 }
1613
1614 /* --------------------- */
1615 static int invisible_dots(const struct vol *vol, const char *name)
1616 {
1617     return vol_inv_dots(vol) && *name  == '.' && strcmp(name, ".") && strcmp(name, "..");
1618 }
1619
1620 /* ------------------------------
1621    (".", curdir)
1622    (name, dir) with curdir:name == dir, from afp_enumerate
1623 */
1624
1625 int getdirparams(const struct vol *vol,
1626                  u_int16_t bitmap, struct path *s_path,
1627                  struct dir *dir,
1628                  char *buf, size_t *buflen )
1629 {
1630     struct maccess  ma;
1631     struct adouble  ad;
1632     char        *data, *l_nameoff = NULL, *utf_nameoff = NULL;
1633     int         bit = 0, isad = 0;
1634     u_int32_t           aint;
1635     u_int16_t       ashort;
1636     int                 ret;
1637     u_int32_t           utf8 = 0;
1638     cnid_t              pdid;
1639     struct stat *st = &s_path->st;
1640     char *upath = s_path->u_name;
1641
1642     if ((bitmap & ((1 << DIRPBIT_ATTR)  |
1643                    (1 << DIRPBIT_CDATE) |
1644                    (1 << DIRPBIT_MDATE) |
1645                    (1 << DIRPBIT_BDATE) |
1646                    (1 << DIRPBIT_FINFO)))) {
1647
1648         ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1649         if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
1650             isad = 1;
1651         }
1652     }
1653
1654     if ( dir->d_did == DIRDID_ROOT) {
1655         pdid = DIRDID_ROOT_PARENT;
1656     } else if (dir->d_did == DIRDID_ROOT_PARENT) {
1657         pdid = 0;
1658     } else {
1659         pdid = dir->d_parent->d_did;
1660     }
1661
1662     data = buf;
1663     while ( bitmap != 0 ) {
1664         while (( bitmap & 1 ) == 0 ) {
1665             bitmap = bitmap>>1;
1666             bit++;
1667         }
1668
1669         switch ( bit ) {
1670         case DIRPBIT_ATTR :
1671             if ( isad ) {
1672                 ad_getattr(&ad, &ashort);
1673             } else if (invisible_dots(vol, dir->d_u_name)) {
1674                 ashort = htons(ATTRBIT_INVISIBLE);
1675             } else
1676                 ashort = 0;
1677             ashort |= htons(ATTRBIT_SHARED);
1678             memcpy( data, &ashort, sizeof( ashort ));
1679             data += sizeof( ashort );
1680             break;
1681
1682         case DIRPBIT_PDID :
1683             memcpy( data, &pdid, sizeof( pdid ));
1684             data += sizeof( pdid );
1685             break;
1686
1687         case DIRPBIT_CDATE :
1688             if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1689                 aint = AD_DATE_FROM_UNIX(st->st_mtime);
1690             memcpy( data, &aint, sizeof( aint ));
1691             data += sizeof( aint );
1692             break;
1693
1694         case DIRPBIT_MDATE :
1695             aint = AD_DATE_FROM_UNIX(st->st_mtime);
1696             memcpy( data, &aint, sizeof( aint ));
1697             data += sizeof( aint );
1698             break;
1699
1700         case DIRPBIT_BDATE :
1701             if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
1702                 aint = AD_DATE_START;
1703             memcpy( data, &aint, sizeof( aint ));
1704             data += sizeof( aint );
1705             break;
1706
1707         case DIRPBIT_FINFO :
1708             if ( isad ) {
1709                 memcpy( data, ad_entry( &ad, ADEID_FINDERI ), 32 );
1710             } else { /* no appledouble */
1711                 memset( data, 0, 32 );
1712                 /* set default view -- this also gets done in ad_open() */
1713                 ashort = htons(FINDERINFO_CLOSEDVIEW);
1714                 memcpy(data + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
1715
1716                 /* dot files are by default visible */
1717                 if (invisible_dots(vol, dir->d_u_name)) {
1718                     ashort = htons(FINDERINFO_INVISIBLE);
1719                     memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
1720                 }
1721             }
1722             data += 32;
1723             break;
1724
1725         case DIRPBIT_LNAME :
1726             if (dir->d_m_name) /* root of parent can have a null name */
1727                 l_nameoff = data;
1728             else
1729                 memset(data, 0, sizeof(u_int16_t));
1730             data += sizeof( u_int16_t );
1731             break;
1732
1733         case DIRPBIT_SNAME :
1734             memset(data, 0, sizeof(u_int16_t));
1735             data += sizeof( u_int16_t );
1736             break;
1737
1738         case DIRPBIT_DID :
1739             memcpy( data, &dir->d_did, sizeof( aint ));
1740             data += sizeof( aint );
1741             break;
1742
1743         case DIRPBIT_OFFCNT :
1744             ashort = 0;
1745             /* this needs to handle current directory access rights */
1746             if (diroffcnt(dir, st)) {
1747                 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1748             }
1749             else if ((ret = for_each_dirent(vol, upath, NULL,NULL)) >= 0) {
1750                 setdiroffcnt(dir, st,  ret);
1751                 ashort = (dir->offcnt > 0xffff)?0xffff:dir->offcnt;
1752             }
1753             ashort = htons( ashort );
1754             memcpy( data, &ashort, sizeof( ashort ));
1755             data += sizeof( ashort );
1756             break;
1757
1758         case DIRPBIT_UID :
1759             aint = htonl(st->st_uid);
1760             memcpy( data, &aint, sizeof( aint ));
1761             data += sizeof( aint );
1762             break;
1763
1764         case DIRPBIT_GID :
1765             aint = htonl(st->st_gid);
1766             memcpy( data, &aint, sizeof( aint ));
1767             data += sizeof( aint );
1768             break;
1769
1770         case DIRPBIT_ACCESS :
1771             accessmode( upath, &ma, dir , st);
1772
1773             *data++ = ma.ma_user;
1774             *data++ = ma.ma_world;
1775             *data++ = ma.ma_group;
1776             *data++ = ma.ma_owner;
1777             break;
1778
1779             /* Client has requested the ProDOS information block.
1780                Just pass back the same basic block for all
1781                directories. <shirsch@ibm.net> */
1782         case DIRPBIT_PDINFO :
1783             if (afp_version >= 30) { /* UTF8 name */
1784                 utf8 = kTextEncodingUTF8;
1785                 if (dir->d_m_name) /* root of parent can have a null name */
1786                     utf_nameoff = data;
1787                 else
1788                     memset(data, 0, sizeof(u_int16_t));
1789                 data += sizeof( u_int16_t );
1790                 aint = 0;
1791                 memcpy(data, &aint, sizeof( aint ));
1792                 data += sizeof( aint );
1793             }
1794             else { /* ProDOS Info Block */
1795                 *data++ = 0x0f;
1796                 *data++ = 0;
1797                 ashort = htons( 0x0200 );
1798                 memcpy( data, &ashort, sizeof( ashort ));
1799                 data += sizeof( ashort );
1800                 memset( data, 0, sizeof( ashort ));
1801                 data += sizeof( ashort );
1802             }
1803             break;
1804
1805         case DIRPBIT_UNIXPR :
1806             aint = htonl(st->st_uid);
1807             memcpy( data, &aint, sizeof( aint ));
1808             data += sizeof( aint );
1809             aint = htonl(st->st_gid);
1810             memcpy( data, &aint, sizeof( aint ));
1811             data += sizeof( aint );
1812
1813             aint = st->st_mode;
1814             aint = htonl ( aint & ~S_ISGID );  /* Remove SGID, OSX doesn't like it ... */
1815             memcpy( data, &aint, sizeof( aint ));
1816             data += sizeof( aint );
1817
1818             accessmode( upath, &ma, dir , st);
1819
1820             *data++ = ma.ma_user;
1821             *data++ = ma.ma_world;
1822             *data++ = ma.ma_group;
1823             *data++ = ma.ma_owner;
1824             break;
1825
1826         default :
1827             if ( isad ) {
1828                 ad_close_metadata( &ad );
1829             }
1830             return( AFPERR_BITMAP );
1831         }
1832         bitmap = bitmap>>1;
1833         bit++;
1834     }
1835     if ( l_nameoff ) {
1836         ashort = htons( data - buf );
1837         memcpy( l_nameoff, &ashort, sizeof( ashort ));
1838         data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, 0);
1839     }
1840     if ( utf_nameoff ) {
1841         ashort = htons( data - buf );
1842         memcpy( utf_nameoff, &ashort, sizeof( ashort ));
1843         data = set_name(vol, data, pdid, dir->d_m_name, dir->d_did, utf8);
1844     }
1845     if ( isad ) {
1846         ad_close_metadata( &ad );
1847     }
1848     *buflen = data - buf;
1849     return( AFP_OK );
1850 }
1851
1852 /* ----------------------------- */
1853 int path_error(struct path *path, int error)
1854 {
1855 /* - a dir with access error
1856  * - no error it's a file
1857  * - file not found
1858  */
1859     if (path_isadir(path))
1860         return afp_errno;
1861     if (path->st_valid && path->st_errno)
1862         return error;
1863     return AFPERR_BADTYPE ;
1864 }
1865
1866 /* ----------------------------- */
1867 int afp_setdirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1868 {
1869     struct vol  *vol;
1870     struct dir  *dir;
1871     struct path *path;
1872     u_int16_t   vid, bitmap;
1873     u_int32_t   did;
1874     int     rc;
1875
1876     *rbuflen = 0;
1877     ibuf += 2;
1878     memcpy( &vid, ibuf, sizeof( vid ));
1879     ibuf += sizeof( vid );
1880
1881     if (NULL == ( vol = getvolbyvid( vid )) ) {
1882         return( AFPERR_PARAM );
1883     }
1884
1885     if (vol->v_flags & AFPVOL_RO)
1886         return AFPERR_VLOCK;
1887
1888     memcpy( &did, ibuf, sizeof( did ));
1889     ibuf += sizeof( int );
1890
1891     if (NULL == ( dir = dirlookup( vol, did )) ) {
1892         return afp_errno;
1893     }
1894
1895     memcpy( &bitmap, ibuf, sizeof( bitmap ));
1896     bitmap = ntohs( bitmap );
1897     ibuf += sizeof( bitmap );
1898
1899     if (NULL == ( path = cname( vol, dir, &ibuf )) ) {
1900         return get_afp_errno(AFPERR_NOOBJ);
1901     }
1902
1903     if ( *path->m_name != '\0' ) {
1904         rc = path_error(path, AFPERR_NOOBJ);
1905         /* maybe we are trying to set perms back */
1906         if (rc != AFPERR_ACCESS)
1907             return rc;
1908     }
1909
1910     /*
1911      * If ibuf is odd, make it even.
1912      */
1913     if ((u_long)ibuf & 1 ) {
1914         ibuf++;
1915     }
1916
1917     if (AFP_OK == ( rc = setdirparams(vol, path, bitmap, ibuf )) ) {
1918         setvoltime(obj, vol );
1919     }
1920     return( rc );
1921 }
1922
1923 /*
1924  * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
1925  *
1926  * assume path == '\0' eg. it's a directory in canonical form
1927  */
1928
1929 struct path Cur_Path = {
1930     0,
1931     "",  /* mac name */
1932     ".", /* unix name */
1933     0,   /* id */
1934     NULL,/* struct dir */
1935     0,   /* stat is not set */
1936 };
1937
1938 /* ------------------ */
1939 static int set_dir_errors(struct path *path, const char *where, int err)
1940 {
1941     switch ( err ) {
1942     case EPERM :
1943     case EACCES :
1944         return AFPERR_ACCESS;
1945     case EROFS :
1946         return AFPERR_VLOCK;
1947     }
1948     LOG(log_error, logtype_afpd, "setdirparam(%s): %s: %s", fullpathname(path->u_name), where, strerror(err) );
1949     return AFPERR_PARAM;
1950 }
1951
1952 /* ------------------ */
1953 int setdirparams(struct vol *vol,
1954                  struct path *path, u_int16_t d_bitmap, char *buf )
1955 {
1956     struct maccess  ma;
1957     struct adouble  ad;
1958     struct utimbuf      ut;
1959     struct timeval      tv;
1960
1961     char                *upath;
1962     struct dir          *dir;
1963     int         bit, isad = 1;
1964     int                 cdate, bdate;
1965     int                 owner, group;
1966     u_int16_t       ashort, bshort;
1967     int                 err = AFP_OK;
1968     int                 change_mdate = 0;
1969     int                 change_parent_mdate = 0;
1970     int                 newdate = 0;
1971     u_int16_t           bitmap = d_bitmap;
1972     u_char              finder_buf[32];
1973     u_int32_t       upriv;
1974     mode_t              mpriv = 0;
1975     u_int16_t           upriv_bit = 0;
1976
1977     bit = 0;
1978     upath = path->u_name;
1979     dir   = path->d_dir;
1980     while ( bitmap != 0 ) {
1981         while (( bitmap & 1 ) == 0 ) {
1982             bitmap = bitmap>>1;
1983             bit++;
1984         }
1985
1986         switch( bit ) {
1987         case DIRPBIT_ATTR :
1988             change_mdate = 1;
1989             memcpy( &ashort, buf, sizeof( ashort ));
1990             buf += sizeof( ashort );
1991             break;
1992         case DIRPBIT_CDATE :
1993             change_mdate = 1;
1994             memcpy(&cdate, buf, sizeof(cdate));
1995             buf += sizeof( cdate );
1996             break;
1997         case DIRPBIT_MDATE :
1998             memcpy(&newdate, buf, sizeof(newdate));
1999             buf += sizeof( newdate );
2000             break;
2001         case DIRPBIT_BDATE :
2002             change_mdate = 1;
2003             memcpy(&bdate, buf, sizeof(bdate));
2004             buf += sizeof( bdate );
2005             break;
2006         case DIRPBIT_FINFO :
2007             change_mdate = 1;
2008             memcpy( finder_buf, buf, 32 );
2009             buf += 32;
2010             break;
2011         case DIRPBIT_UID :  /* What kind of loser mounts as root? */
2012             change_parent_mdate = 1;
2013             memcpy( &owner, buf, sizeof(owner));
2014             buf += sizeof( owner );
2015             break;
2016         case DIRPBIT_GID :
2017             change_parent_mdate = 1;
2018             memcpy( &group, buf, sizeof( group ));
2019             buf += sizeof( group );
2020             break;
2021         case DIRPBIT_ACCESS :
2022             change_mdate = 1;
2023             change_parent_mdate = 1;
2024             ma.ma_user = *buf++;
2025             ma.ma_world = *buf++;
2026             ma.ma_group = *buf++;
2027             ma.ma_owner = *buf++;
2028             mpriv = mtoumode( &ma ) | vol->v_dperm;
2029             if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2030                 err = set_dir_errors(path, "setdirmode", errno);
2031                 bitmap = 0;
2032             }
2033             break;
2034             /* Ignore what the client thinks we should do to the
2035                ProDOS information block.  Skip over the data and
2036                report nothing amiss. <shirsch@ibm.net> */
2037         case DIRPBIT_PDINFO :
2038             if (afp_version < 30) {
2039                 buf += 6;
2040             }
2041             else {
2042                 err = AFPERR_BITMAP;
2043                 bitmap = 0;
2044             }
2045             break;
2046         case DIRPBIT_UNIXPR :
2047             if (vol_unix_priv(vol)) {
2048                 memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
2049                 buf += sizeof( owner );
2050                 memcpy( &group, buf, sizeof( group ));
2051                 buf += sizeof( group );
2052
2053                 change_mdate = 1;
2054                 change_parent_mdate = 1;
2055                 memcpy( &upriv, buf, sizeof( upriv ));
2056                 buf += sizeof( upriv );
2057                 upriv = ntohl (upriv) | vol->v_dperm;
2058                 if (dir_rx_set(upriv)) {
2059                     /* maybe we are trying to set perms back */
2060                     if ( setdirunixmode(vol, upath, upriv) < 0 ) {
2061                         bitmap = 0;
2062                         err = set_dir_errors(path, "setdirunixmode", errno);
2063                     }
2064                 }
2065                 else {
2066                     /* do it later */
2067                     upriv_bit = 1;
2068                 }
2069                 break;
2070             }
2071             /* fall through */
2072         default :
2073             err = AFPERR_BITMAP;
2074             bitmap = 0;
2075             break;
2076         }
2077
2078         bitmap = bitmap>>1;
2079         bit++;
2080     }
2081     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2082
2083     if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
2084         /*
2085          * Check to see what we're trying to set.  If it's anything
2086          * but ACCESS, UID, or GID, give an error.  If it's any of those
2087          * three, we don't need the ad to be open, so just continue.
2088          *
2089          * note: we also don't need to worry about mdate. also, be quiet
2090          *       if we're using the noadouble option.
2091          */
2092         if (!vol_noadouble(vol) && (d_bitmap &
2093                                     ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
2094                                       (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
2095                                       (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
2096             return AFPERR_ACCESS;
2097         }
2098
2099         isad = 0;
2100     } else {
2101         /*
2102          * Check to see if a create was necessary. If it was, we'll want
2103          * to set our name, etc.
2104          */
2105         if ( (ad_get_HF_flags( &ad ) & O_CREAT)) {
2106             ad_setname(&ad, curdir->d_m_name);
2107         }
2108     }
2109
2110     bit = 0;
2111     bitmap = d_bitmap;
2112     while ( bitmap != 0 ) {
2113         while (( bitmap & 1 ) == 0 ) {
2114             bitmap = bitmap>>1;
2115             bit++;
2116         }
2117
2118         switch( bit ) {
2119         case DIRPBIT_ATTR :
2120             if (isad) {
2121                 ad_getattr(&ad, &bshort);
2122                 if ((bshort & htons(ATTRBIT_INVISIBLE)) !=
2123                     (ashort & htons(ATTRBIT_INVISIBLE) & htons(ATTRBIT_SETCLR)) )
2124                     change_parent_mdate = 1;
2125                 if ( ntohs( ashort ) & ATTRBIT_SETCLR ) {
2126                     bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR );
2127                 } else {
2128                     bshort &= ~ashort;
2129                 }
2130                 ad_setattr(&ad, bshort);
2131             }
2132             break;
2133         case DIRPBIT_CDATE :
2134             if (isad) {
2135                 ad_setdate(&ad, AD_DATE_CREATE, cdate);
2136             }
2137             break;
2138         case DIRPBIT_MDATE :
2139             break;
2140         case DIRPBIT_BDATE :
2141             if (isad) {
2142                 ad_setdate(&ad, AD_DATE_BACKUP, bdate);
2143             }
2144             break;
2145         case DIRPBIT_FINFO :
2146             if (isad) {
2147                 /* Fixes #2802236 */
2148                 u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF);
2149                 *fflags &= htons(~FINDERINFO_ISHARED);
2150                 /* #2802236 end */
2151                 if (  dir->d_did == DIRDID_ROOT ) {
2152                     /*
2153                      * Alright, we admit it, this is *really* sick!
2154                      * The 4 bytes that we don't copy, when we're dealing
2155                      * with the root of a volume, are the directory's
2156                      * location information. This eliminates that annoying
2157                      * behavior one sees when mounting above another mount
2158                      * point.
2159                      */
2160                     memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 10 );
2161                     memcpy( ad_entry( &ad, ADEID_FINDERI ) + 14, finder_buf + 14, 18 );
2162                 } else {
2163                     memcpy( ad_entry( &ad, ADEID_FINDERI ), finder_buf, 32 );
2164                 }
2165             }
2166             break;
2167         case DIRPBIT_UID :  /* What kind of loser mounts as root? */
2168             if ( (dir->d_did == DIRDID_ROOT) &&
2169                  (setdeskowner( ntohl(owner), -1 ) < 0)) {
2170                 err = set_dir_errors(path, "setdeskowner", errno);
2171                 if (isad && err == AFPERR_PARAM) {
2172                     err = AFP_OK; /* ???*/
2173                 }
2174                 else {
2175                     goto setdirparam_done;
2176                 }
2177             }
2178             if ( setdirowner(vol, upath, ntohl(owner), -1 ) < 0 ) {
2179                 err = set_dir_errors(path, "setdirowner", errno);
2180                 goto setdirparam_done;
2181             }
2182             break;
2183         case DIRPBIT_GID :
2184             if (dir->d_did == DIRDID_ROOT)
2185                 setdeskowner( -1, ntohl(group) );
2186             if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2187                 err = set_dir_errors(path, "setdirowner", errno);
2188                 goto setdirparam_done;
2189             }
2190             break;
2191         case DIRPBIT_ACCESS :
2192             if (dir->d_did == DIRDID_ROOT) {
2193                 setdeskmode(mpriv);
2194                 if (!dir_rx_set(mpriv)) {
2195                     /* we can't remove read and search for owner on volume root */
2196                     err = AFPERR_ACCESS;
2197                     goto setdirparam_done;
2198                 }
2199             }
2200
2201             if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
2202                 err = set_dir_errors(path, "setdirmode", errno);
2203                 goto setdirparam_done;
2204             }
2205             break;
2206         case DIRPBIT_PDINFO :
2207             if (afp_version >= 30) {
2208                 err = AFPERR_BITMAP;
2209                 goto setdirparam_done;
2210             }
2211             break;
2212         case DIRPBIT_UNIXPR :
2213             if (vol_unix_priv(vol)) {
2214                 if (dir->d_did == DIRDID_ROOT) {
2215                     if (!dir_rx_set(upriv)) {
2216                         /* we can't remove read and search for owner on volume root */
2217                         err = AFPERR_ACCESS;
2218                         goto setdirparam_done;
2219                     }
2220                     setdeskowner( -1, ntohl(group) );
2221                     setdeskmode( upriv );
2222                 }
2223                 if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
2224                     err = set_dir_errors(path, "setdirowner", errno);
2225                     goto setdirparam_done;
2226                 }
2227
2228                 if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
2229                     err = set_dir_errors(path, "setdirunixmode", errno);
2230                     goto setdirparam_done;
2231                 }
2232             }
2233             else {
2234                 err = AFPERR_BITMAP;
2235                 goto setdirparam_done;
2236             }
2237             break;
2238         default :
2239             err = AFPERR_BITMAP;
2240             goto setdirparam_done;
2241             break;
2242         }
2243
2244         bitmap = bitmap>>1;
2245         bit++;
2246     }
2247
2248 setdirparam_done:
2249     if (change_mdate && newdate == 0 && gettimeofday(&tv, NULL) == 0) {
2250         newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2251     }
2252     if (newdate) {
2253         if (isad)
2254             ad_setdate(&ad, AD_DATE_MODIFY, newdate);
2255         ut.actime = ut.modtime = AD_DATE_TO_UNIX(newdate);
2256         utime(upath, &ut);
2257     }
2258
2259     if ( isad ) {
2260         if (path->st_valid && !path->st_errno) {
2261             struct stat *st = &path->st;
2262
2263             if (dir && dir->d_parent) {
2264                 ad_setid(&ad, st->st_dev, st->st_ino,  dir->d_did, dir->d_parent->d_did, vol->v_stamp);
2265             }
2266         }
2267         ad_flush( &ad);
2268         ad_close_metadata( &ad);
2269     }
2270
2271     if (change_parent_mdate && dir->d_did != DIRDID_ROOT
2272         && gettimeofday(&tv, NULL) == 0) {
2273         if (!movecwd(vol, dir->d_parent)) {
2274             newdate = AD_DATE_FROM_UNIX(tv.tv_sec);
2275             /* be careful with bitmap because now dir is null */
2276             bitmap = 1<<DIRPBIT_MDATE;
2277             setdirparams(vol, &Cur_Path, bitmap, (char *)&newdate);
2278             /* should we reset curdir ?*/
2279         }
2280     }
2281
2282     return err;
2283 }
2284
2285 int afp_syncdir(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2286 {
2287 #ifdef HAVE_DIRFD
2288     DIR                  *dp;
2289 #endif
2290     int                  dfd;
2291     struct vol           *vol;
2292     struct dir           *dir;
2293     u_int32_t            did;
2294     u_int16_t            vid;
2295
2296     *rbuflen = 0;
2297     ibuf += 2;
2298
2299     memcpy( &vid, ibuf, sizeof( vid ));
2300     ibuf += sizeof( vid );
2301     if (NULL == (vol = getvolbyvid( vid )) ) {
2302         return( AFPERR_PARAM );
2303     }
2304
2305     memcpy( &did, ibuf, sizeof( did ));
2306     ibuf += sizeof( did );
2307
2308     /*
2309      * Here's the deal:
2310      * if it's CNID 2 our only choice to meet the specs is call sync.
2311      * For any other CNID just sync that dir. To my knowledge the
2312      * intended use of FPSyncDir is to sync the volume so all we're
2313      * ever going to see here is probably CNID 2. Anyway, we' prepared.
2314      */
2315
2316     if ( ntohl(did) == 2 ) {
2317         sync();
2318     } else {
2319         if (NULL == ( dir = dirlookup( vol, did )) ) {
2320             return afp_errno; /* was AFPERR_NOOBJ */
2321         }
2322
2323         if (movecwd( vol, dir ) < 0 )
2324             return ( AFPERR_NOOBJ );
2325
2326         /*
2327          * Assuming only OSens that have dirfd also may require fsyncing directories
2328          * in order to flush metadata e.g. Linux.
2329          */
2330
2331 #ifdef HAVE_DIRFD
2332         if (NULL == ( dp = opendir( "." )) ) {
2333             switch( errno ) {
2334             case ENOENT :
2335                 return( AFPERR_NOOBJ );
2336             case EACCES :
2337                 return( AFPERR_ACCESS );
2338             default :
2339                 return( AFPERR_PARAM );
2340             }
2341         }
2342
2343         LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name);
2344
2345         dfd = dirfd( dp );
2346         if ( fsync ( dfd ) < 0 )
2347             LOG(log_error, logtype_afpd, "afp_syncdir(%s):  %s",
2348                 dir->d_u_name, strerror(errno) );
2349         closedir(dp); /* closes dfd too */
2350 #endif
2351
2352         if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) {
2353             switch( errno ) {
2354             case ENOENT:
2355                 return( AFPERR_NOOBJ );
2356             case EACCES:
2357                 return( AFPERR_ACCESS );
2358             default:
2359                 return( AFPERR_PARAM );
2360             }
2361         }
2362
2363         LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'",
2364             vol->ad_path(".", ADFLAGS_DIR) );
2365
2366         if ( fsync(dfd) < 0 )
2367             LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s",
2368                 vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) );
2369         close(dfd);
2370     }
2371
2372     return ( AFP_OK );
2373 }
2374
2375 int afp_createdir(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2376 {
2377     struct adouble  ad;
2378     struct vol      *vol;
2379     struct dir      *dir;
2380     char        *upath;
2381     struct path         *s_path;
2382     u_int32_t       did;
2383     u_int16_t       vid;
2384     int                 err;
2385
2386     *rbuflen = 0;
2387     ibuf += 2;
2388
2389     memcpy( &vid, ibuf, sizeof( vid ));
2390     ibuf += sizeof( vid );
2391     if (NULL == ( vol = getvolbyvid( vid )) ) {
2392         return( AFPERR_PARAM );
2393     }
2394
2395     if (vol->v_flags & AFPVOL_RO)
2396         return AFPERR_VLOCK;
2397
2398     memcpy( &did, ibuf, sizeof( did ));
2399     ibuf += sizeof( did );
2400     if (NULL == ( dir = dirlookup( vol, did )) ) {
2401         return afp_errno; /* was AFPERR_NOOBJ */
2402     }
2403     /* for concurrent access we need to be sure we are not in the
2404      * folder we want to create...
2405      */
2406     movecwd(vol, dir);
2407
2408     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
2409         return get_afp_errno(AFPERR_PARAM);
2410     }
2411     /* cname was able to move curdir to it! */
2412     if (*s_path->m_name == '\0')
2413         return AFPERR_EXIST;
2414
2415     upath = s_path->u_name;
2416
2417     if (AFP_OK != (err = netatalk_mkdir( upath))) {
2418         return err;
2419     }
2420
2421     if (of_stat(s_path) < 0) {
2422         return AFPERR_MISC;
2423     }
2424     curdir->offcnt++;
2425     if ((dir = adddir( vol, curdir, s_path)) == NULL) {
2426         return AFPERR_MISC;
2427     }
2428
2429     if ( movecwd( vol, dir ) < 0 ) {
2430         return( AFPERR_PARAM );
2431     }
2432
2433     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2434     if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0)  {
2435         if (vol_noadouble(vol))
2436             goto createdir_done;
2437         return( AFPERR_ACCESS );
2438     }
2439     ad_setname(&ad, s_path->m_name);
2440     ad_setid( &ad, s_path->st.st_dev, s_path->st.st_ino, dir->d_did, did, vol->v_stamp);
2441
2442     ad_flush( &ad);
2443     ad_close_metadata( &ad);
2444
2445 createdir_done:
2446 #ifdef HAVE_NFSv4_ACLS
2447     /* FIXME: are we really inside the created dir? */
2448     addir_inherit_acl(vol);
2449 #endif
2450
2451     memcpy( rbuf, &dir->d_did, sizeof( u_int32_t ));
2452     *rbuflen = sizeof( u_int32_t );
2453     setvoltime(obj, vol );
2454     return( AFP_OK );
2455 }
2456
2457 /*
2458  * dst       new unix filename (not a pathname)
2459  * newname   new mac name
2460  * newparent curdir
2461  *
2462  */
2463 int renamedir(const struct vol *vol, char *src, char *dst,
2464               struct dir *dir,
2465               struct dir *newparent,
2466               char *newname)
2467 {
2468     struct adouble  ad;
2469     struct dir      *parent;
2470     char                *buf;
2471     int         len, err;
2472
2473     /* existence check moved to afp_moveandrename */
2474     if ( unix_rename( src, dst ) < 0 ) {
2475         switch ( errno ) {
2476         case ENOENT :
2477             return( AFPERR_NOOBJ );
2478         case EACCES :
2479             return( AFPERR_ACCESS );
2480         case EROFS:
2481             return AFPERR_VLOCK;
2482         case EINVAL:
2483             /* tried to move directory into a subdirectory of itself */
2484             return AFPERR_CANTMOVE;
2485         case EXDEV:
2486             /* this needs to copy and delete. bleah. that means we have
2487              * to deal with entire directory hierarchies. */
2488             if ((err = copydir(vol, src, dst)) < 0) {
2489                 deletedir(dst);
2490                 return err;
2491             }
2492             if ((err = deletedir(src)) < 0)
2493                 return err;
2494             break;
2495         default :
2496             return( AFPERR_PARAM );
2497         }
2498     }
2499
2500     vol->vfs->vfs_renamedir(vol, src, dst);
2501
2502     len = strlen( newname );
2503     /* rename() succeeded so we need to update our tree even if we can't open
2504      * metadata
2505      */
2506
2507     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2508
2509     if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
2510         ad_setname(&ad, newname);
2511         ad_flush( &ad);
2512         ad_close_metadata( &ad);
2513     }
2514
2515     dir_hash_del(vol, dir);
2516     if (dir->d_m_name == dir->d_u_name)
2517         dir->d_u_name = NULL;
2518
2519     if ((buf = (char *) realloc( dir->d_m_name, len + 1 )) == NULL ) {
2520         LOG(log_error, logtype_afpd, "renamedir: realloc mac name: %s", strerror(errno) );
2521         /* FIXME : fatal ? */
2522         return AFPERR_MISC;
2523     }
2524     dir->d_m_name = buf;
2525     strcpy( dir->d_m_name, newname );
2526
2527     if (newname == dst) {
2528         free(dir->d_u_name);
2529         dir->d_u_name = dir->d_m_name;
2530     }
2531     else {
2532         if ((buf = (char *) realloc( dir->d_u_name, strlen(dst) + 1 )) == NULL ) {
2533             LOG(log_error, logtype_afpd, "renamedir: realloc unix name: %s", strerror(errno) );
2534             return AFPERR_MISC;
2535         }
2536         dir->d_u_name = buf;
2537         strcpy( dir->d_u_name, dst );
2538     }
2539     dir->d_u_name_len = strlen(dir->d_u_name);
2540
2541     if (dir->d_m_name_ucs2)
2542         free(dir->d_m_name_ucs2);
2543
2544     dir->d_m_name_ucs2 = NULL;
2545     if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, dir->d_m_name, -1, (char**)&dir->d_m_name_ucs2))
2546         dir->d_m_name_ucs2 = NULL;
2547
2548     if (( parent = dir->d_parent ) == NULL ) {
2549         return( AFP_OK );
2550     }
2551     if ( parent == newparent ) {
2552         hash_alloc_insert(vol->v_hash, dir, dir);
2553         return( AFP_OK );
2554     }
2555
2556     /* detach from old parent and add to new one. */
2557     dirchildremove(parent, dir);
2558     dir->d_parent = newparent;
2559     dirchildadd(vol, newparent, dir);
2560     return( AFP_OK );
2561 }
2562
2563 /* delete an empty directory */
2564 int deletecurdir(struct vol *vol)
2565 {
2566     struct dirent *de;
2567     struct stat st;
2568     struct dir  *fdir;
2569     DIR *dp;
2570     struct adouble  ad;
2571     u_int16_t       ashort;
2572     int err;
2573
2574     if ( curdir->d_parent == NULL ) {
2575         return( AFPERR_ACCESS );
2576     }
2577
2578     fdir = curdir;
2579
2580     ad_init(&ad, vol->v_adouble, vol->v_ad_options);
2581     /* we never want to create a resource fork here, we are going to delete it */
2582     if ( ad_metadata( ".", ADFLAGS_DIR, &ad) == 0 ) {
2583
2584         ad_getattr(&ad, &ashort);
2585         ad_close( &ad, ADFLAGS_HF );
2586         if ((ashort & htons(ATTRBIT_NODELETE))) {
2587             return  AFPERR_OLOCK;
2588         }
2589     }
2590     err = vol->vfs->vfs_deletecurdir(vol);
2591     if (err) {
2592         return err;
2593     }
2594
2595     /* now get rid of dangling symlinks */
2596     if ((dp = opendir("."))) {
2597         while ((de = readdir(dp))) {
2598             /* skip this and previous directory */
2599             if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
2600                 continue;
2601
2602             /* bail if it's not a symlink */
2603             if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
2604                 closedir(dp);
2605                 return AFPERR_DIRNEMPT;
2606             }
2607
2608             if ((err = netatalk_unlink(de->d_name))) {
2609                 closedir(dp);
2610                 return err;
2611             }
2612         }
2613     }
2614
2615     if ( movecwd( vol, curdir->d_parent ) < 0 ) {
2616         err = afp_errno;
2617         goto delete_done;
2618     }
2619
2620     if ( !(err = netatalk_rmdir(fdir->d_u_name))) {
2621         dirchildremove(curdir, fdir);
2622         cnid_delete(vol->v_cdb, fdir->d_did);
2623         dir_remove( vol, fdir );
2624         err = AFP_OK;
2625     }
2626 delete_done:
2627     if (dp) {
2628         /* inode is used as key for cnid.
2629          * Close the descriptor only after cnid_delete
2630          * has been called.
2631          */
2632         closedir(dp);
2633     }
2634     return err;
2635 }
2636
2637 int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2638 {
2639     struct passwd   *pw;
2640     struct group    *gr;
2641     char        *name;
2642     u_int32_t           id;
2643     int         len, sfunc;
2644     int         utf8 = 0;
2645
2646     ibuf++;
2647     sfunc = (unsigned char) *ibuf++;
2648     *rbuflen = 0;
2649
2650
2651     if (sfunc >= 3 && sfunc <= 6) {
2652         if (afp_version < 30) {
2653             return( AFPERR_PARAM );
2654         }
2655         utf8 = 1;
2656     }
2657
2658     switch ( sfunc ) {
2659     case 1 :
2660     case 3 :/* unicode */
2661         memcpy( &id, ibuf, sizeof( id ));
2662         id = ntohl(id);
2663         if ( id != 0 ) {
2664             if (( pw = getpwuid( id )) == NULL ) {
2665                 return( AFPERR_NOITEM );
2666             }
2667             len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC),
2668                                            pw->pw_name, -1, &name);
2669         } else {
2670             len = 0;
2671             name = NULL;
2672         }
2673         break;
2674     case 2 :
2675     case 4 : /* unicode */
2676         memcpy( &id, ibuf, sizeof( id ));
2677         id = ntohl(id);
2678         if ( id != 0 ) {
2679             if (NULL == ( gr = (struct group *)getgrgid( id ))) {
2680                 return( AFPERR_NOITEM );
2681             }
2682             len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC,
2683                                            gr->gr_name, -1, &name);
2684         } else {
2685             len = 0;
2686             name = NULL;
2687         }
2688         break;
2689 #ifdef HAVE_NFSv4_ACLS
2690     case 5 : /* UUID -> username */
2691     case 6 : /* UUID -> groupname */
2692         if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2693             return AFPERR_PARAM;
2694         LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
2695         uuidtype_t type;
2696         len = getnamefromuuid( ibuf, &name, &type);
2697         if (len != 0)       /* its a error code, not len */
2698             return AFPERR_NOITEM;
2699         if (type == UUID_USER) {
2700             if (( pw = getpwnam( name )) == NULL )
2701                 return( AFPERR_NOITEM );
2702             LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid);
2703             id = htonl(UUID_USER);
2704             memcpy( rbuf, &id, sizeof( id ));
2705             id = htonl( pw->pw_uid);
2706             rbuf += sizeof( id );
2707             memcpy( rbuf, &id, sizeof( id ));
2708             rbuf += sizeof( id );
2709             *rbuflen = 2 * sizeof( id );
2710         } else {        /* type == UUID_GROUP */
2711             if (( gr = getgrnam( name )) == NULL )
2712                 return( AFPERR_NOITEM );
2713             LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid);
2714             id = htonl(UUID_GROUP);
2715             memcpy( rbuf, &id, sizeof( id ));
2716             rbuf += sizeof( id );
2717             id = htonl( gr->gr_gid);
2718             memcpy( rbuf, &id, sizeof( id ));
2719             rbuf += sizeof( id );
2720             *rbuflen = 2 * sizeof( id );
2721         }
2722         break;
2723 #endif
2724     default :
2725         return( AFPERR_PARAM );
2726     }
2727
2728     if (name)
2729         len = strlen( name );
2730
2731     if (utf8) {
2732         u_int16_t tp = htons(len);
2733         memcpy(rbuf, &tp, sizeof(tp));
2734         rbuf += sizeof(tp);
2735         *rbuflen += 2;
2736     }
2737     else {
2738         *rbuf++ = len;
2739         *rbuflen += 1;
2740     }
2741     if ( len > 0 ) {
2742         memcpy( rbuf, name, len );
2743     }
2744     *rbuflen += len;
2745     if (name)
2746         free(name);
2747     return( AFP_OK );
2748 }
2749
2750 int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
2751 {
2752     struct passwd   *pw;
2753     struct group    *gr;
2754     int             len, sfunc;
2755     u_int32_t       id;
2756     u_int16_t       ulen;
2757
2758     ibuf++;
2759     sfunc = (unsigned char) *ibuf++;
2760     *rbuflen = 0;
2761     LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version);
2762     switch ( sfunc ) {
2763     case 1 :
2764     case 2 : /* unicode */
2765         if (afp_version < 30) {
2766             return( AFPERR_PARAM );
2767         }
2768         memcpy(&ulen, ibuf, sizeof(ulen));
2769         len = ntohs(ulen);
2770         ibuf += 2;
2771         LOG(log_debug, logtype_afpd, "afp_mapname: alive");
2772         break;
2773     case 3 :
2774     case 4 :
2775         len = (unsigned char) *ibuf++;
2776         break;
2777 #ifdef HAVE_NFSv4_ACLS
2778     case 5 : /* username -> UUID  */
2779     case 6 : /* groupname -> UUID */
2780         if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID ))
2781             return AFPERR_PARAM;
2782         memcpy(&ulen, ibuf, sizeof(ulen));
2783         len = ntohs(ulen);
2784         ibuf += 2;
2785         break;
2786 #endif
2787     default :
2788         return( AFPERR_PARAM );
2789     }
2790
2791     ibuf[ len ] = '\0';
2792
2793     if ( len == 0 )
2794         return AFPERR_PARAM;
2795     else {
2796         switch ( sfunc ) {
2797         case 1 : /* unicode */
2798         case 3 :
2799             if (NULL == ( pw = (struct passwd *)getpwnam( ibuf )) ) {
2800                 return( AFPERR_NOITEM );
2801             }
2802             id = pw->pw_uid;
2803             id = htonl(id);
2804             memcpy( rbuf, &id, sizeof( id ));
2805             *rbuflen = sizeof( id );
2806             break;
2807
2808         case 2 : /* unicode */
2809         case 4 :
2810             LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf);
2811             if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) {
2812                 return( AFPERR_NOITEM );
2813             }
2814             id = gr->gr_gid;
2815             LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id);
2816             id = htonl(id);
2817             memcpy( rbuf, &id, sizeof( id ));
2818             *rbuflen = sizeof( id );
2819             break;
2820 #ifdef HAVE_NFSv4_ACLS
2821         case 5 :        /* username -> UUID */
2822             LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2823             if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
2824                 return AFPERR_NOITEM;
2825             *rbuflen = UUID_BINSIZE;
2826             break;
2827         case 6 :        /* groupname -> UUID */
2828             LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
2829             if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
2830                 return AFPERR_NOITEM;
2831             *rbuflen = UUID_BINSIZE;
2832             break;
2833 #endif
2834         }
2835     }
2836     return( AFP_OK );
2837 }
2838
2839 /* ------------------------------------
2840    variable DID support
2841 */
2842 int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
2843 {
2844 #if 0
2845     struct vol   *vol;
2846     struct dir   *dir;
2847     u_int16_t    vid;
2848     u_int32_t    did;
2849 #endif /* 0 */
2850
2851     *rbuflen = 0;
2852
2853     /* do nothing as dids are static for the life of the process. */
2854 #if 0
2855     ibuf += 2;
2856
2857     memcpy(&vid,  ibuf, sizeof( vid ));
2858     ibuf += sizeof( vid );
2859     if (( vol = getvolbyvid( vid )) == NULL ) {
2860         return( AFPERR_PARAM );
2861     }
2862
2863     memcpy( &did, ibuf, sizeof( did ));
2864     ibuf += sizeof( did );
2865     if (( dir = dirlookup( vol, did )) == NULL ) {
2866         return( AFPERR_PARAM );
2867     }
2868
2869     /* dir_remove -- deletedid */
2870 #endif /* 0 */
2871
2872     return AFP_OK;
2873 }
2874
2875 /* did creation gets done automatically
2876  * there's a pb again with case but move it to cname
2877  */
2878 int afp_opendir(AFPObj *obj _U_, char *ibuf, size_t ibuflen  _U_, char *rbuf, size_t *rbuflen)
2879 {
2880     struct vol      *vol;
2881     struct dir      *parentdir;
2882     struct path     *path;
2883     u_int32_t       did;
2884     u_int16_t       vid;
2885
2886     *rbuflen = 0;
2887     ibuf += 2;
2888
2889     memcpy(&vid, ibuf, sizeof(vid));
2890     ibuf += sizeof( vid );
2891
2892     if (NULL == ( vol = getvolbyvid( vid )) ) {
2893         return( AFPERR_PARAM );
2894     }
2895
2896     memcpy(&did, ibuf, sizeof(did));
2897     ibuf += sizeof(did);
2898
2899     if (NULL == ( parentdir = dirlookup( vol, did )) ) {
2900         return afp_errno;
2901     }
2902
2903     if (NULL == ( path = cname( vol, parentdir, &ibuf )) ) {
2904         return get_afp_errno(AFPERR_PARAM);
2905     }
2906
2907     if ( *path->m_name != '\0' ) {
2908         return path_error(path, AFPERR_NOOBJ);
2909     }
2910
2911     if ( !path->st_valid && of_stat(path ) < 0 ) {
2912         return( AFPERR_NOOBJ );
2913     }
2914     if ( path->st_errno ) {
2915         return( AFPERR_NOOBJ );
2916     }
2917
2918     memcpy(rbuf, &curdir->d_did, sizeof(curdir->d_did));
2919     *rbuflen = sizeof(curdir->d_did);
2920     return AFP_OK;
2921 }