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