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