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