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 <stdio.h>
11#include <stdlib.h>
12/* STDC check */
13#if STDC_HEADERS
14#include <string.h>
15#else /* STDC_HEADERS */
16#ifndef HAVE_STRCHR
17#define strchr index
18#define strrchr index
19#endif /* HAVE_STRCHR */
20char *strchr (), *strrchr ();
21#ifndef HAVE_MEMCPY
22#define memcpy(d,s,n) bcopy ((s), (d), (n))
23#define memmove(d,s,n) bcopy ((s), (d), (n))
24#endif /* ! HAVE_MEMCPY */
25#endif /* STDC_HEADERS */
26
27#ifdef HAVE_STRINGS_H
28#include <strings.h>
29#endif
30#include <errno.h>
31#include <sys/param.h>
32
33#include <atalk/adouble.h>
34#include <atalk/vfs.h>
35#include <atalk/afp.h>
36#include <atalk/util.h>
37#include <atalk/cnid.h>
38#include <atalk/logger.h>
39#include <atalk/unix.h>
40#include <atalk/bstrlib.h>
41#include <atalk/bstradd.h>
42#include <atalk/acl.h>
43#include <atalk/globals.h>
44#include <atalk/fce_api.h>
45
46#include "directory.h"
47#include "dircache.h"
48#include "desktop.h"
49#include "volume.h"
50#include "fork.h"
51#include "file.h"
52#include "filedir.h"
53#include "unix.h"
54
55/* foxconn add start, improvemennt of time machine backup rate,
56   Jonathan 2012/08/22 */
57#define TIME_MACHINE_WA
58
59#ifdef DROPKLUDGE
60int matchfile2dirperms(
61/* Since it's kinda' big; I decided against an
62   inline function */
63    char    *upath,
64    struct vol  *vol,
65    int     did)
66/* The below code changes the way file ownership is determined in the name of
67   fixing dropboxes.  It has known security problem.  See the netatalk FAQ for
68   more information */
69{
70    struct stat st, sb;
71    struct dir  *dir;
72    char    *adpath;
73    uid_t       uid;
74    int         ret = AFP_OK;
75#ifdef DEBUG
76    LOG(log_debug9, logtype_afpd, "begin matchfile2dirperms:");
77#endif
78
79    if (stat(upath, &st ) < 0) {
80        LOG(log_error, logtype_afpd, "Could not stat %s: %s", upath, strerror(errno));
81        return AFPERR_NOOBJ ;
82    }
83
84    adpath = vol->vfs->ad_path( upath, ADFLAGS_HF );
85    /* FIXME dirsearch doesn't move cwd to did ! */
86    if (( dir = dirlookup( vol, did )) == NULL ) {
87        LOG(log_error, logtype_afpd, "matchfile2dirperms: Unable to get directory info.");
88        ret = AFPERR_NOOBJ;
89    }
90    else if (stat(".", &sb) < 0) {
91        LOG(log_error, logtype_afpd,
92            "matchfile2dirperms: Error checking directory \"%s\": %s",
93            dir->d_m_name, strerror(errno));
94        ret = AFPERR_NOOBJ;
95    }
96    else {
97        uid=geteuid();
98        if ( uid != sb.st_uid )
99        {
100            seteuid(0);
101            if (ochown(upath, sb.st_uid, sb.st_gid, vol_syml_opt(vol)) < 0)
102            {
103                LOG(log_error, logtype_afpd,
104                    "matchfile2dirperms(%s): Error changing owner/gid: %s",
105                    upath, strerror(errno));
106                ret = AFPERR_ACCESS;
107            }
108            else if (ochmod(upath,
109                            (st.st_mode & ~default_options.umask) | S_IRGRP | S_IROTH,
110                            &sb,
111                            vol_syml_opt(vol) | O_NETATALK_ACL) < 0) {
112                LOG(log_error, logtype_afpd,
113                    "matchfile2dirperms(%s): Error adding file read permissions: %s",
114                    upath, strerror(errno));
115                ret = AFPERR_ACCESS;
116            }
117            else if (ochown(adpath, sb.st_uid, sb.st_gid, vol_syml_opt(vol)) < 0)
118            {
119                LOG(log_error, logtype_afpd,
120                    "matchfile2dirperms(%s): Error changing AppleDouble owner/gid: %s",
121                    adpath, strerror(errno));
122                ret = AFPERR_ACCESS;
123            }
124            else if (ochmod(adpath,
125                            (st.st_mode & ~default_options.umask) | S_IRGRP| S_IROTH,
126                            &st,
127                            vol_syml_opt(vol) | O_NETATALK_ACL) < 0)
128            {
129                LOG(log_error, logtype_afpd,
130                    "matchfile2dirperms(%s):  Error adding AD file read permissions: %s",
131                    adpath, strerror(errno));
132                ret = AFPERR_ACCESS;
133            }
134            seteuid(uid);
135        }
136    } /* end else if stat success */
137
138#ifdef DEBUG
139    LOG(log_debug9, logtype_afpd, "end matchfile2dirperms:");
140#endif
141    return ret;
142}
143#endif
144
145int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
146{
147    struct stat     *st;
148    struct vol      *vol;
149    struct dir      *dir;
150    u_int32_t           did;
151    int         ret;
152    size_t      buflen;
153    u_int16_t       fbitmap, dbitmap, vid;
154    struct path         *s_path;
155
156    *rbuflen = 0;
157    ibuf += 2;
158
159    memcpy( &vid, ibuf, sizeof( vid ));
160    ibuf += sizeof( vid );
161    if (NULL == ( vol = getvolbyvid( vid )) ) {
162        /* was AFPERR_PARAM but it helps OS 10.3 when a volume has been removed
163         * from the list.
164         */
165        return( AFPERR_ACCESS );
166    }
167
168    memcpy( &did, ibuf, sizeof( did ));
169    ibuf += sizeof( did );
170
171    if (NULL == ( dir = dirlookup( vol, did )) ) {
172        return afp_errno;
173    }
174
175    memcpy( &fbitmap, ibuf, sizeof( fbitmap ));
176    fbitmap = ntohs( fbitmap );
177    ibuf += sizeof( fbitmap );
178    memcpy( &dbitmap, ibuf, sizeof( dbitmap ));
179    dbitmap = ntohs( dbitmap );
180    ibuf += sizeof( dbitmap );
181
182    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
183        return get_afp_errno(AFPERR_NOOBJ);
184    }
185
186    LOG(log_debug, logtype_afpd, "getfildirparams(vid:%u, did:%u, f/d:%04x/%04x) {cwdid:%u, cwd: %s, name:'%s'}",
187        ntohs(vid), ntohl(dir->d_did), fbitmap, dbitmap,
188        ntohl(curdir->d_did), cfrombstr(curdir->d_fullpath), s_path->u_name);
189
190    st   = &s_path->st;
191    if (!s_path->st_valid) {
192        /* it's a dir and it should be there
193         * because we chdir in it in cname or
194         * it's curdir (maybe deleted, but then we can't know).
195         * So we need to try harder.
196         */
197        of_statdir(vol, s_path);
198    }
199    if ( s_path->st_errno != 0 ) {
200        if (afp_errno != AFPERR_ACCESS) {
201            return( AFPERR_NOOBJ );
202        }
203    }
204
205
206    buflen = 0;
207    if (S_ISDIR(st->st_mode)) {
208        if (dbitmap) {
209            dir = s_path->d_dir;
210            if (!dir)
211                return AFPERR_NOOBJ;
212
213            ret = getdirparams(vol, dbitmap, s_path, dir,
214                               rbuf + 3 * sizeof( u_int16_t ), &buflen );
215            if (ret != AFP_OK )
216                return( ret );
217        }
218        /* this is a directory */
219        *(rbuf + 2 * sizeof( u_int16_t )) = (char) FILDIRBIT_ISDIR;
220    } else {
221        if (fbitmap && AFP_OK != (ret = getfilparams(vol, fbitmap, s_path, curdir,
222                                                     rbuf + 3 * sizeof( u_int16_t ), &buflen )) ) {
223            return( ret );
224        }
225        /* this is a file */
226        *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISFILE;
227    }
228    *rbuflen = buflen + 3 * sizeof( u_int16_t );
229    fbitmap = htons( fbitmap );
230    memcpy( rbuf, &fbitmap, sizeof( fbitmap ));
231    rbuf += sizeof( fbitmap );
232    dbitmap = htons( dbitmap );
233    memcpy( rbuf, &dbitmap, sizeof( dbitmap ));
234    rbuf += sizeof( dbitmap ) + sizeof( u_char );
235    *rbuf = 0;
236
237    return( AFP_OK );
238}
239
240int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
241{
242    struct stat *st;
243    struct vol  *vol;
244    struct dir  *dir;
245    struct path *path;
246    u_int16_t   vid, bitmap;
247    int     did, rc;
248
249    *rbuflen = 0;
250    ibuf += 2;
251    memcpy( &vid, ibuf, sizeof(vid));
252    ibuf += sizeof( vid );
253
254    if (NULL == ( vol = getvolbyvid( vid )) ) {
255        return( AFPERR_PARAM );
256    }
257
258    if (vol->v_flags & AFPVOL_RO)
259        return AFPERR_VLOCK;
260
261    memcpy( &did, ibuf, sizeof( did));
262    ibuf += sizeof( did);
263
264    if (NULL == ( dir = dirlookup( vol, did )) ) {
265        return afp_errno;
266    }
267
268    memcpy( &bitmap, ibuf, sizeof( bitmap ));
269    bitmap = ntohs( bitmap );
270    ibuf += sizeof( bitmap );
271
272    if (NULL == ( path = cname( vol, dir, &ibuf ))) {
273        return get_afp_errno(AFPERR_NOOBJ);
274    }
275
276    st   = &path->st;
277    if (!path->st_valid) {
278        /* it's a dir and it should be there
279         * because we chdir in it in cname
280         */
281        of_statdir(vol, path);
282    }
283
284    if ( path->st_errno != 0 ) {
285        if (afp_errno != AFPERR_ACCESS)
286            return( AFPERR_NOOBJ );
287    }
288    /*
289     * If ibuf is odd, make it even.
290     */
291    if ((u_long)ibuf & 1 ) {
292        ibuf++;
293    }
294
295    if (S_ISDIR(st->st_mode)) {
296        rc = setdirparams(vol, path, bitmap, ibuf );
297    } else {
298        rc = setfilparams(vol, path, bitmap, ibuf );
299    }
300    if ( rc == AFP_OK ) {
301        setvoltime(obj, vol );
302    }
303
304    return( rc );
305}
306
307/* --------------------------------------------
308   Factorise some checks on a pathname
309*/
310int check_name(const struct vol *vol, char *name)
311{
312    /* check for illegal characters in the unix filename */
313    if (!wincheck(vol, name))
314        return AFPERR_PARAM;
315
316    if ((vol->v_flags & AFPVOL_NOHEX) && strchr(name, '/'))
317        return AFPERR_PARAM;
318
319    if (!vol->vfs->vfs_validupath(vol, name)) {
320        LOG(log_error, logtype_afpd, "check_name: illegal name: '%s'", name);
321        return AFPERR_EXIST;
322    }
323
324    /* check for vetoed filenames */
325    if (veto_file(vol->v_veto, name))
326        return AFPERR_EXIST;
327    return 0;
328}
329
330/* -------------------------
331    move and rename sdir:oldname to curdir:newname in volume vol
332    special care is needed for lock
333*/
334static int moveandrename(const struct vol *vol,
335                         struct dir *sdir,
336                         int sdir_fd,
337                         char *oldname,
338                         char *newname,
339                         int isdir)
340{
341    char            *oldunixname = NULL;
342    char            *upath;
343    int             rc;
344    struct stat     *st, nst;
345    int             adflags;
346    struct adouble	ad;
347    struct adouble	*adp;
348    struct ofork	*opened = NULL;
349    struct path     path;
350    cnid_t          id;
351    int             cwd_fd = -1;
352
353    LOG(log_debug, logtype_afpd,
354        "moveandrename: [\"%s\"/\"%s\"] -> \"%s\"",
355        cfrombstr(sdir->d_u_name), oldname, newname);
356
357    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
358    adp = &ad;
359    adflags = 0;
360
361    if (!isdir) {
362        if ((oldunixname = strdup(mtoupath(vol, oldname, sdir->d_did, utf8_encoding()))) == NULL)
363            return AFPERR_PARAM; /* can't convert */
364        id = cnid_get(vol->v_cdb, sdir->d_did, oldunixname, strlen(oldunixname));
365
366#ifndef HAVE_ATFUNCS
367        /* Need full path */
368        free(oldunixname);
369        if ((oldunixname = strdup(ctoupath(vol, sdir, oldname))) == NULL)
370            return AFPERR_PARAM; /* pathname too long */
371#endif /* HAVE_ATFUNCS */
372
373        path.st_valid = 0;
374        path.u_name = oldunixname;
375
376#ifdef HAVE_ATFUNCS
377        opened = of_findnameat(sdir_fd, &path);
378#else
379	//opened = of_findname(&path);
380        opened = of_findname(vol,&path);
381#endif /* HAVE_ATFUNCS */
382
383        if (opened) {
384            /* reuse struct adouble so it won't break locks */
385            adp = opened->of_ad;
386        }
387    } else {
388        id = sdir->d_did; /* we already have the CNID */
389        if ((oldunixname = strdup(ctoupath( vol, dirlookup(vol, sdir->d_pdid), oldname))) == NULL)
390            return AFPERR_PARAM;
391        adflags = ADFLAGS_DIR;
392    }
393
394    /*
395     * oldunixname now points to either
396     *   a) full pathname of the source fs object (if renameat is not available)
397     *   b) the oldname (renameat is available)
398     * we are in the dest folder so we need to use
399     *   a) oldunixname for ad_open
400     *   b) fchdir sdir_fd before eg ad_open or use *at functions where appropiate
401     */
402
403    if (sdir_fd != -1) {
404        if ((cwd_fd = open(".", O_RDONLY)) == -1)
405            return AFPERR_MISC;
406        if (fchdir(sdir_fd) != 0) {
407            rc = AFPERR_MISC;
408            goto exit;
409        }
410    }
411    if (!ad_metadata(oldunixname, adflags, adp)) {
412        u_int16_t bshort;
413
414        ad_getattr(adp, &bshort);
415        ad_close_metadata( adp);
416        if ((bshort & htons(ATTRBIT_NORENAME))) {
417            rc = AFPERR_OLOCK;
418            goto exit;
419        }
420    }
421    if (sdir_fd != -1) {
422        if (fchdir(cwd_fd) != 0) {
423            LOG(log_error, logtype_afpd, "moveandrename: %s", strerror(errno) );
424            rc = AFPERR_MISC;
425            goto exit;
426        }
427    }
428
429    if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))){
430        rc = AFPERR_PARAM;
431        goto exit;
432    }
433    path.u_name = upath;
434    st = &path.st;
435    if (0 != (rc = check_name(vol, upath))) {
436        goto exit;
437    }
438
439    /* source == destination. we just silently accept this. */
440    if ((!isdir && curdir == sdir) || (isdir && curdir->d_did == sdir->d_pdid)) {
441        if (strcmp(oldname, newname) == 0) {
442            rc = AFP_OK;
443            goto exit;
444        }
445
446        if (stat(upath, st) == 0 || caseenumerate(vol, &path, curdir) == 0) {
447            if (!stat(oldunixname, &nst) && !(nst.st_dev == st->st_dev && nst.st_ino == st->st_ino) ) {
448                /* not the same file */
449                rc = AFPERR_EXIST;
450                goto exit;
451            }
452            errno = 0;
453        }
454    } else if (stat(upath, st ) == 0 || caseenumerate(vol, &path, curdir) == 0) {
455        rc = AFPERR_EXIST;
456        goto exit;
457    }
458
459    if ( !isdir ) {
460        path.st_valid = 1;
461        path.st_errno = errno;
462        if (of_findname(vol, &path)) {
463            rc = AFPERR_EXIST; /* was AFPERR_BUSY; */
464        } else {
465            rc = renamefile(vol, sdir_fd, oldunixname, upath, newname, adp );
466            if (rc == AFP_OK)
467                of_rename(vol, opened, sdir, oldname, curdir, newname);
468        }
469    } else {
470        rc = renamedir(vol, sdir_fd, oldunixname, upath, sdir, curdir, newname);
471    }
472    if ( rc == AFP_OK && id ) {
473        /* renaming may have moved the file/dir across a filesystem */
474        if (stat(upath, st) < 0) {
475            rc = AFPERR_MISC;
476            goto exit;
477        }
478
479        /* Remove it from the cache */
480        struct dir *cacheddir = dircache_search_by_did(vol, id);
481        if (cacheddir) {
482            LOG(log_warning, logtype_afpd,"Still cached: \"%s/%s\"", getcwdpath(), upath);
483            (void)dir_remove(vol, cacheddir);
484        }
485
486        /* Fixup adouble info */
487        if (!ad_metadata(upath, adflags, adp)) {
488            ad_setid(adp, st->st_dev, st->st_ino, id, curdir->d_did, vol->v_stamp);
489            ad_flush(adp);
490            ad_close_metadata(adp);
491        }
492
493        /* fix up the catalog entry */
494        cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath));
495    }
496
497exit:
498    if (cwd_fd != -1)
499        close(cwd_fd);
500    if (oldunixname)
501        free(oldunixname);
502    return rc;
503}
504
505/* -------------------------------------------- */
506int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
507{
508    struct vol  *vol;
509    struct dir  *sdir;
510    char        *oldname, *newname;
511    struct path *path;
512    u_int32_t   did;
513    int         plen;
514    u_int16_t   vid;
515    int         isdir = 0;
516    int         rc;
517
518    *rbuflen = 0;
519    ibuf += 2;
520
521    memcpy( &vid, ibuf, sizeof( vid ));
522    ibuf += sizeof( vid );
523    if (NULL == ( vol = getvolbyvid( vid )) ) {
524        return( AFPERR_PARAM );
525    }
526
527    if (vol->v_flags & AFPVOL_RO)
528        return AFPERR_VLOCK;
529
530    memcpy( &did, ibuf, sizeof( did ));
531    ibuf += sizeof( did );
532    if (NULL == ( sdir = dirlookup( vol, did )) ) {
533        return afp_errno;
534    }
535
536    /* source pathname */
537    if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
538        return get_afp_errno(AFPERR_NOOBJ);
539    }
540
541    sdir = curdir;
542    newname = obj->newtmp;
543    oldname = obj->oldtmp;
544    isdir = path_isadir(path);
545    if ( *path->m_name != '\0' ) {
546        strcpy(oldname, path->m_name); /* an extra copy for of_rename */
547        if (isdir) {
548            /* curdir parent dir, need to move sdir back */
549            sdir = path->d_dir;
550        }
551    }
552    else {
553        if ( sdir->d_did == DIRDID_ROOT ) { /* root directory */
554            return( AFPERR_NORENAME );
555        }
556        /* move to destination dir */
557        if ( movecwd( vol, dirlookup(vol, sdir->d_pdid) ) < 0 ) {
558            return afp_errno;
559        }
560        memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) +1);
561    }
562
563    /* another place where we know about the path type */
564    if ((plen = copy_path_name(vol, newname, ibuf)) < 0) {
565        return( AFPERR_PARAM );
566    }
567
568    if (!plen) {
569        return AFP_OK; /* newname == oldname same dir */
570    }
571
572    rc = moveandrename(vol, sdir, -1, oldname, newname, isdir);
573    if ( rc == AFP_OK ) {
574        setvoltime(obj, vol );
575    }
576
577    return( rc );
578}
579
580/* ------------------------------- */
581int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
582{
583    struct vol      *vol;
584    struct dir      *dir;
585    struct path         *s_path;
586    char        *upath;
587    int         did, rc;
588    u_int16_t       vid;
589
590    *rbuflen = 0;
591    ibuf += 2;
592
593    memcpy( &vid, ibuf, sizeof( vid ));
594    ibuf += sizeof( vid );
595    if (NULL == ( vol = getvolbyvid( vid )) ) {
596        return( AFPERR_PARAM );
597    }
598
599    if (vol->v_flags & AFPVOL_RO)
600        return AFPERR_VLOCK;
601
602    memcpy( &did, ibuf, sizeof( did ));
603    ibuf += sizeof( int );
604
605    if (NULL == ( dir = dirlookup( vol, did )) ) {
606        return afp_errno;
607    }
608
609    if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
610        return get_afp_errno(AFPERR_NOOBJ);
611    }
612
613    upath = s_path->u_name;
614    if ( path_isadir( s_path) ) {
615        if (*s_path->m_name != '\0' || curdir->d_did == DIRDID_ROOT) {
616            rc = AFPERR_ACCESS;
617        } else {
618            /* we have to cache this, the structs are lost in deletcurdir*/
619            /* but we need the positive returncode to send our event */
620            bstring dname;
621            if ((dname = bstrcpy(curdir->d_u_name)) == NULL)
622                return AFPERR_MISC;
623            if ((rc = deletecurdir(vol)) == AFP_OK)
624                fce_register_delete_dir(cfrombstr(dname));
625            bdestroy(dname);
626        }
627    } else if (of_findname(vol, s_path)) {
628        rc = AFPERR_BUSY;
629    } else {
630        /* it's a file st_valid should always be true
631         * only test for ENOENT because EACCES needs
632         * to read meta data in deletefile
633         */
634        if (s_path->st_valid && s_path->st_errno == ENOENT) {
635            rc = AFPERR_NOOBJ;
636        } else {
637            if ((rc = deletefile(vol, -1, upath, 1)) == AFP_OK) {
638				fce_register_delete_file( s_path );
639                if (vol->v_tm_used < s_path->st.st_size)
640                    vol->v_tm_used = 0;
641                else
642                    vol->v_tm_used -= s_path->st.st_size;
643            }
644            struct dir *cachedfile;
645            if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath)))) {
646                dircache_remove(vol, cachedfile, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX);
647                dir_free(cachedfile);
648            }
649        }
650    }
651    if ( rc == AFP_OK ) {
652        curdir->d_offcnt--;
653/* foxconn add start, Jonathan 2012/08/22 */
654#ifdef TIME_MACHINE_WA
655		afp_bandsdid_decreaseOffcnt(curdir->d_did);
656#endif
657        setvoltime(obj, vol );
658    }
659
660    return( rc );
661}
662/* ------------------------ */
663char *absupath(const struct vol *vol, struct dir *dir, char *u)
664{
665    static char pathbuf[MAXPATHLEN + 1];
666    bstring path;
667
668    if (u == NULL || dir == NULL || vol == NULL)
669        return NULL;
670
671    if ((path = bstrcpy(dir->d_fullpath)) == NULL)
672        return NULL;
673    if (bcatcstr(path, "/") != BSTR_OK)
674        return NULL;
675    if (bcatcstr(path, u) != BSTR_OK)
676        return NULL;
677    if (path->slen > MAXPATHLEN)
678        return NULL;
679
680    LOG(log_debug, logtype_afpd, "absupath: %s", cfrombstr(path));
681
682    strncpy(pathbuf, cfrombstr(path), blength(path) + 1);
683    bdestroy(path);
684
685    return(pathbuf);
686}
687
688char *ctoupath(const struct vol *vol, struct dir *dir, char *name)
689{
690    if (vol == NULL || dir == NULL || name == NULL)
691        return NULL;
692    return absupath(vol, dir, mtoupath(vol, name, dir->d_did, utf8_encoding()));
693}
694
695/* ------------------------- */
696int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
697{
698    struct vol  *vol;
699    struct dir  *sdir, *ddir;
700    int         isdir;
701    char    *oldname, *newname;
702    struct path *path;
703    int     did;
704    int     pdid;
705    int         plen;
706    u_int16_t   vid;
707    int         rc;
708#ifdef DROPKLUDGE
709    int     retvalue;
710#endif /* DROPKLUDGE */
711    int     sdir_fd = -1;
712
713
714    *rbuflen = 0;
715    ibuf += 2;
716
717    memcpy( &vid, ibuf, sizeof( vid ));
718    ibuf += sizeof( vid );
719    if (NULL == ( vol = getvolbyvid( vid )) ) {
720        return( AFPERR_PARAM );
721    }
722
723    if (vol->v_flags & AFPVOL_RO)
724        return AFPERR_VLOCK;
725
726    /* source did followed by dest did */
727    memcpy( &did, ibuf, sizeof( did ));
728    ibuf += sizeof( int );
729    if (NULL == ( sdir = dirlookup( vol, did )) ) {
730        return afp_errno; /* was AFPERR_PARAM */
731    }
732
733    memcpy( &did, ibuf, sizeof( did ));
734    ibuf += sizeof( int );
735
736    /* source pathname */
737    if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
738        return get_afp_errno(AFPERR_NOOBJ);
739    }
740
741    sdir = curdir;
742    newname = obj->newtmp;
743    oldname = obj->oldtmp;
744
745    isdir = path_isadir(path);
746    if ( *path->m_name != '\0' ) {
747        if (isdir) {
748            sdir = path->d_dir;
749        }
750        strcpy(oldname, path->m_name); /* an extra copy for of_rename */
751    } else {
752        memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) + 1);
753    }
754
755#ifdef HAVE_ATFUNCS
756    if ((sdir_fd = open(".", O_RDONLY)) == -1)
757        return AFPERR_MISC;
758#endif
759
760    /* get the destination directory */
761    if (NULL == ( ddir = dirlookup( vol, did )) ) {
762        rc = afp_errno; /*  was AFPERR_PARAM */
763        goto exit;
764    }
765    if (NULL == ( path = cname( vol, ddir, &ibuf ))) {
766        rc = AFPERR_NOOBJ;
767        goto exit;
768    }
769    pdid = curdir->d_did;
770    if ( *path->m_name != '\0' ) {
771        rc = path_error(path, AFPERR_NOOBJ);
772        goto exit;
773    }
774
775    /* one more place where we know about path type */
776    if ((plen = copy_path_name(vol, newname, ibuf)) < 0) {
777        rc = AFPERR_PARAM;
778        goto exit;
779    }
780
781    if (!plen) {
782        strcpy(newname, oldname);
783    }
784
785    /* This does the work */
786    LOG(log_debug, logtype_afpd, "afp_move(oldname:'%s', newname:'%s', isdir:%u)",
787        oldname, newname, isdir);
788    rc = moveandrename(vol, sdir, sdir_fd, oldname, newname, isdir);
789
790    if ( rc == AFP_OK ) {
791        char *upath = mtoupath(vol, newname, pdid, utf8_encoding());
792
793        if (NULL == upath) {
794            rc = AFPERR_PARAM;
795            goto exit;
796        }
797        curdir->d_offcnt++;
798/* foxconn add start, Jonathan 2012/08/22 */
799#ifdef TIME_MACHINE_WA
800		afp_bandsdid_IncreaseOffcnt(curdir->d_did);
801#endif
802
803        sdir->d_offcnt--;
804/* foxconn add start, Jonathan 2012/08/22 */
805#ifdef TIME_MACHINE_WA
806		afp_bandsdid_decreaseOffcnt(sdir->d_did);
807#endif
808#ifdef DROPKLUDGE
809        if (vol->v_flags & AFPVOL_DROPBOX) {
810            /* FIXME did is not always the source id */
811            if ((retvalue=matchfile2dirperms (upath, vol, did)) != AFP_OK) {
812                rc = retvalue;
813                goto exit;
814            }
815        }
816        else
817#endif /* DROPKLUDGE */
818            /* if unix priv don't try to match perm with dest folder */
819            if (!isdir && !vol_unix_priv(vol)) {
820                int  admode = ad_mode("", 0777) | vol->v_fperm;
821
822                setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL);
823                vol->vfs->vfs_setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL);
824            }
825        setvoltime(obj, vol );
826    }
827
828exit:
829#ifdef HAVE_ATFUNCS
830    if (sdir_fd != -1)
831        close(sdir_fd);
832#endif
833
834    return( rc );
835}
836
837int veto_file(const char*veto_str, const char*path)
838/* given a veto_str like "abc/zxc/" and path "abc", return 1
839 * veto_str should be '/' delimited
840 * if path matches any one of the veto_str elements exactly, then 1 is returned
841 * otherwise, 0 is returned.
842 */
843{
844    int i;  /* index to veto_str */
845    int j;  /* index to path */
846
847    if ((veto_str == NULL) || (path == NULL))
848        return 0;
849
850    for(i=0, j=0; veto_str[i] != '\0'; i++) {
851        if (veto_str[i] == '/') {
852            if ((j>0) && (path[j] == '\0')) {
853                LOG(log_debug, logtype_afpd, "vetoed file:'%s'", path);
854                return 1;
855            }
856            j = 0;
857        } else {
858            if (veto_str[i] != path[j]) {
859                while ((veto_str[i] != '/')
860                       && (veto_str[i] != '\0'))
861                    i++;
862                j = 0;
863                continue;
864            }
865            j++;
866        }
867    }
868    return 0;
869}
870
871