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