]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/filedir.c
234a26e550e11f47d8faf208a97371a746107773
[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         AFP_CNID_START("cnid_get");
252         id = cnid_get(vol->v_cdb, sdir->d_did, oldunixname, strlen(oldunixname));
253         AFP_CNID_DONE();
254
255 #ifndef HAVE_ATFUNCS
256         /* Need full path */
257         free(oldunixname);
258         if ((oldunixname = strdup(ctoupath(vol, sdir, oldname))) == NULL)
259             return AFPERR_PARAM; /* pathname too long */
260 #endif /* HAVE_ATFUNCS */
261
262         path.st_valid = 0;
263         path.u_name = oldunixname;
264
265 #ifdef HAVE_ATFUNCS
266         opened = of_findnameat(sdir_fd, &path);
267 #else
268         opened = of_findname(vol, &path);
269 #endif /* HAVE_ATFUNCS */
270
271         if (opened) {
272             /* reuse struct adouble so it won't break locks */
273             adp = opened->of_ad;
274         }
275     } else {
276         id = sdir->d_did; /* we already have the CNID */
277         if ((oldunixname = strdup(ctoupath( vol, dirlookup(vol, sdir->d_pdid), oldname))) == NULL)
278             return AFPERR_PARAM;
279         adflags = ADFLAGS_DIR;
280     }
281
282     /*
283      * oldunixname now points to either
284      *   a) full pathname of the source fs object (if renameat is not available)
285      *   b) the oldname (renameat is available)
286      * we are in the dest folder so we need to use 
287      *   a) oldunixname for ad_open
288      *   b) fchdir sdir_fd before eg ad_open or use *at functions where appropiate
289      */
290
291     if (sdir_fd != -1) {
292         if ((cwd_fd = open(".", O_RDONLY)) == -1)
293             return AFPERR_MISC;
294         if (fchdir(sdir_fd) != 0) {
295             rc = AFPERR_MISC;
296             goto exit;
297         }
298     }
299     if (!ad_metadata(oldunixname, adflags, adp)) {
300         uint16_t bshort;
301
302         ad_getattr(adp, &bshort);
303         
304         ad_close(adp, ADFLAGS_HF);
305         if (!(vol->v_ignattr & ATTRBIT_NORENAME) && (bshort & htons(ATTRBIT_NORENAME))) {
306             rc = AFPERR_OLOCK;
307             goto exit;
308         }
309     }
310     if (sdir_fd != -1) {
311         if (fchdir(cwd_fd) != 0) {
312             LOG(log_error, logtype_afpd, "moveandrename: %s", strerror(errno) );
313             rc = AFPERR_MISC;
314             goto exit;
315         }
316     }
317
318     if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding(vol->v_obj)))){ 
319         rc = AFPERR_PARAM;
320         goto exit;
321     }
322     path.u_name = upath;
323     st = &path.st;
324     if (0 != (rc = check_name(vol, upath))) {
325         goto exit;
326     }
327
328     /* source == destination. we just silently accept this. */
329     if ((!isdir && curdir == sdir) || (isdir && curdir->d_did == sdir->d_pdid)) {
330         if (strcmp(oldname, newname) == 0) {
331             rc = AFP_OK;
332             goto exit;
333         }
334
335         if (stat(upath, st) == 0) {
336             if (!stat(oldunixname, &nst) && !(nst.st_dev == st->st_dev && nst.st_ino == st->st_ino) ) {
337                 /* not the same file */
338                 rc = AFPERR_EXIST;
339                 goto exit;
340             }
341             errno = 0;
342         }
343     } else if (stat(upath, st ) == 0) {
344         rc = AFPERR_EXIST;
345         goto exit;
346     }
347
348     if ( !isdir ) {
349         path.st_valid = 1;
350         path.st_errno = errno;
351         if (of_findname(vol, &path)) {
352             rc = AFPERR_EXIST; /* was AFPERR_BUSY; */
353         } else {
354             rc = renamefile(vol, curdir, sdir_fd, oldunixname, upath, newname, adp );
355             if (rc == AFP_OK)
356                 of_rename(vol, opened, sdir, oldname, curdir, newname);
357         }
358     } else {
359         rc = renamedir(vol, sdir_fd, oldunixname, upath, sdir, curdir, newname);
360     }
361     if ( rc == AFP_OK && id ) {
362         /* renaming may have moved the file/dir across a filesystem */
363         if (stat(upath, st) < 0) {
364             rc = AFPERR_MISC;
365             goto exit;
366         }
367
368         /* Remove it from the cache */
369         struct dir *cacheddir = dircache_search_by_did(vol, id);
370         if (cacheddir) {
371             LOG(log_warning, logtype_afpd,"Still cached: \"%s/%s\"", getcwdpath(), upath);
372             (void)dir_remove(vol, cacheddir);
373         }
374
375         /* Fixup adouble info */
376         if (!ad_metadata(upath, adflags, adp)) {
377             ad_setid(adp, st->st_dev, st->st_ino, id, curdir->d_did, vol->v_stamp);
378             ad_flush(adp);
379             ad_close(adp, ADFLAGS_HF);
380         }
381
382         /* fix up the catalog entry */
383         AFP_CNID_START("cnid_update");
384         cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath));
385         AFP_CNID_DONE();
386     }
387
388 exit:
389     if (cwd_fd != -1)
390         close(cwd_fd);
391     if (oldunixname)
392         free(oldunixname);
393     return rc;
394 }
395
396 /* -------------------------------------------- */
397 int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
398 {
399     struct vol  *vol;
400     struct dir  *sdir;
401     char        *oldname, *newname;
402     struct path *path;
403     uint32_t   did;
404     int         plen;
405     uint16_t   vid;
406     int         isdir = 0;
407     int         rc;
408
409     *rbuflen = 0;
410     ibuf += 2;
411
412     memcpy( &vid, ibuf, sizeof( vid ));
413     ibuf += sizeof( vid );
414     if (NULL == ( vol = getvolbyvid( vid )) ) {
415         return( AFPERR_PARAM );
416     }
417
418     if (vol->v_flags & AFPVOL_RO)
419         return AFPERR_VLOCK;
420
421     memcpy( &did, ibuf, sizeof( did ));
422     ibuf += sizeof( did );
423     if (NULL == ( sdir = dirlookup( vol, did )) ) {
424         return afp_errno;
425     }
426
427     /* source pathname */
428     if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
429         return get_afp_errno(AFPERR_NOOBJ);
430     }
431
432     sdir = curdir;
433     newname = obj->newtmp;
434     oldname = obj->oldtmp;
435     isdir = path_isadir(path);
436     if ( *path->m_name != '\0' ) {
437         strcpy(oldname, path->m_name); /* an extra copy for of_rename */
438         if (isdir) {
439             /* curdir parent dir, need to move sdir back */
440             sdir = path->d_dir;
441         }
442     }
443     else {
444         if ( sdir->d_did == DIRDID_ROOT ) { /* root directory */
445             return( AFPERR_NORENAME );
446         }
447         /* move to destination dir */
448         if ( movecwd( vol, dirlookup(vol, sdir->d_pdid) ) < 0 ) {
449             return afp_errno;
450         }
451         memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) +1);
452     }
453
454     /* another place where we know about the path type */
455     if ((plen = copy_path_name(vol, newname, ibuf)) < 0) {
456         return( AFPERR_PARAM );
457     }
458
459     if (!plen) {
460         return AFP_OK; /* newname == oldname same dir */
461     }
462     
463     rc = moveandrename(vol, sdir, -1, oldname, newname, isdir);
464     if ( rc == AFP_OK ) {
465         setvoltime(obj, vol );
466     }
467
468     return( rc );
469 }
470
471 /* ------------------------------- */
472 int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
473 {
474     struct vol  *vol;
475     struct dir  *dir;
476     struct path *s_path;
477     char        *upath;
478     int         did;
479     int         rc = AFP_OK;
480     uint16_t    vid;
481
482     *rbuflen = 0;
483     ibuf += 2;
484
485     memcpy( &vid, ibuf, sizeof( vid ));
486     ibuf += sizeof( vid );
487     if (NULL == ( vol = getvolbyvid( vid )) ) {
488         return( AFPERR_PARAM );
489     }
490
491     if (vol->v_flags & AFPVOL_RO)
492         return AFPERR_VLOCK;
493
494     memcpy( &did, ibuf, sizeof( did ));
495     ibuf += sizeof( int );
496
497     if (NULL == ( dir = dirlookup( vol, did )) ) {
498         return afp_errno;
499     }
500
501     if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
502         return get_afp_errno(AFPERR_NOOBJ);
503     }
504
505     upath = s_path->u_name;
506     if (path_isadir(s_path)) {
507         if (*s_path->m_name != '\0' || curdir->d_did == DIRDID_ROOT) {
508             if (vol->v_adouble == AD_VERSION2)
509                 return AFPERR_ACCESS;
510             if (*s_path->m_name == '\0' && curdir->d_did == DIRDID_ROOT)
511                 return AFPERR_ACCESS;
512             if (rmdir(upath) != 0) {
513                 switch (errno) {
514                 case ENOTEMPTY:
515                     return AFPERR_DIRNEMPT;
516                 case EACCES:
517                     return AFPERR_ACCESS;
518                 default:
519                     return AFPERR_MISC;
520                 }
521             }
522             struct dir *deldir;
523             cnid_t delcnid = CNID_INVALID;
524             if ((deldir = dircache_search_by_name(vol, curdir, upath, strlen(upath)))) {
525                 delcnid = deldir->d_did;
526                 dir_remove(vol, deldir);
527             }
528             if (delcnid == CNID_INVALID) {
529                 AFP_CNID_START("cnid_get");
530                 delcnid = cnid_get(vol->v_cdb, curdir->d_did, upath, strlen(upath));
531                 AFP_CNID_DONE();
532             }
533             if (delcnid != CNID_INVALID) {
534                 AFP_CNID_START("cnid_delete");
535                 cnid_delete(vol->v_cdb, delcnid);
536                 AFP_CNID_DONE();
537             }
538             fce_register(FCE_DIR_DELETE, fullpathname(upath), NULL, fce_dir);
539         } else {
540             /* we have to cache this, the structs are lost in deletcurdir*/
541             /* but we need the positive returncode to send our event */
542             bstring dname;
543             if ((dname = bstrcpy(curdir->d_u_name)) == NULL)
544                 return AFPERR_MISC;
545             if ((rc = deletecurdir(vol)) == AFP_OK)
546                 fce_register(FCE_DIR_DELETE, fullpathname(cfrombstr(dname)), NULL, fce_dir);
547             bdestroy(dname);
548         }
549     } else if (of_findname(vol, s_path)) {
550         rc = AFPERR_BUSY;
551     } else {
552         /* it's a file st_valid should always be true
553          * only test for ENOENT because EACCES needs
554          * to read meta data in deletefile
555          */
556         if (s_path->st_valid && s_path->st_errno == ENOENT) {
557             rc = AFPERR_NOOBJ;
558         } else {
559             if ((rc = deletefile(vol, -1, upath, 1)) == AFP_OK) {
560                                 fce_register(FCE_FILE_DELETE, fullpathname(upath), NULL, fce_file);
561                 if (vol->v_tm_used < s_path->st.st_size)
562                     vol->v_tm_used = 0;
563                 else 
564                     vol->v_tm_used -= s_path->st.st_size;
565             }
566             struct dir *cachedfile;
567             if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath)))) {
568                 dircache_remove(vol, cachedfile, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX);
569                 dir_free(cachedfile);
570             }
571         }
572     }
573     if ( rc == AFP_OK ) {
574         curdir->d_offcnt--;
575         setvoltime(obj, vol );
576     }
577
578     return( rc );
579 }
580 /* ------------------------ */
581 char *absupath(const struct vol *vol, struct dir *dir, char *u)
582 {
583     static char pathbuf[MAXPATHLEN + 1];
584     bstring path;
585
586     if (u == NULL || dir == NULL || vol == NULL)
587         return NULL;
588
589     if ((path = bstrcpy(dir->d_fullpath)) == NULL)
590         return NULL;
591     if (bcatcstr(path, "/") != BSTR_OK)
592         return NULL;
593     if (bcatcstr(path, u) != BSTR_OK)
594         return NULL;
595     if (path->slen > MAXPATHLEN) {
596         bdestroy(path);
597         return NULL;
598     }
599
600     LOG(log_debug, logtype_afpd, "absupath: %s", cfrombstr(path));
601
602     strncpy(pathbuf, cfrombstr(path), blength(path) + 1);
603     bdestroy(path);
604
605     return(pathbuf);
606 }
607
608 char *ctoupath(const struct vol *vol, struct dir *dir, char *name)
609 {
610     if (vol == NULL || dir == NULL || name == NULL)
611         return NULL;
612     return absupath(vol, dir, mtoupath(vol, name, dir->d_did, utf8_encoding(vol->v_obj)));
613 }
614
615 /* ------------------------- */
616 int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
617 {
618     struct vol  *vol;
619     struct dir  *sdir, *ddir;
620     int         isdir;
621     char    *oldname, *newname;
622     struct path *path;
623     int     did;
624     int     pdid;
625     int         plen;
626     uint16_t   vid;
627     int         rc;
628     int     sdir_fd = -1;
629
630
631     *rbuflen = 0;
632     ibuf += 2;
633
634     memcpy( &vid, ibuf, sizeof( vid ));
635     ibuf += sizeof( vid );
636     if (NULL == ( vol = getvolbyvid( vid )) ) {
637         return( AFPERR_PARAM );
638     }
639
640     if (vol->v_flags & AFPVOL_RO)
641         return AFPERR_VLOCK;
642
643     /* source did followed by dest did */
644     memcpy( &did, ibuf, sizeof( did ));
645     ibuf += sizeof( int );
646     if (NULL == ( sdir = dirlookup( vol, did )) ) {
647         return afp_errno; /* was AFPERR_PARAM */
648     }
649
650     memcpy( &did, ibuf, sizeof( did ));
651     ibuf += sizeof( int );
652
653     /* source pathname */
654     if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
655         return get_afp_errno(AFPERR_NOOBJ);
656     }
657
658     sdir = curdir;
659     newname = obj->newtmp;
660     oldname = obj->oldtmp;
661
662     isdir = path_isadir(path);
663     if ( *path->m_name != '\0' ) {
664         if (isdir) {
665             sdir = path->d_dir;
666         }
667         strcpy(oldname, path->m_name); /* an extra copy for of_rename */
668     } else {
669         memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) + 1);
670     }
671
672 #ifdef HAVE_ATFUNCS
673     if ((sdir_fd = open(".", O_RDONLY)) == -1)
674         return AFPERR_MISC;
675 #endif
676
677     /* get the destination directory */
678     if (NULL == ( ddir = dirlookup( vol, did )) ) {
679         rc = afp_errno; /*  was AFPERR_PARAM */
680         goto exit;
681     }
682     if (NULL == ( path = cname( vol, ddir, &ibuf ))) {
683         rc = AFPERR_NOOBJ;
684         goto exit;
685     }
686     pdid = curdir->d_did;
687     if ( *path->m_name != '\0' ) {
688         rc = path_error(path, AFPERR_NOOBJ);
689         goto exit;
690     }
691
692     /* one more place where we know about path type */
693     if ((plen = copy_path_name(vol, newname, ibuf)) < 0) {
694         rc = AFPERR_PARAM;
695         goto exit;
696     }
697
698     if (!plen) {
699         strcpy(newname, oldname);
700     }
701
702     /* This does the work */
703     LOG(log_debug, logtype_afpd, "afp_move(oldname:'%s', newname:'%s', isdir:%u)",
704         oldname, newname, isdir);
705     rc = moveandrename(vol, sdir, sdir_fd, oldname, newname, isdir);
706
707     if ( rc == AFP_OK ) {
708         char *upath = mtoupath(vol, newname, pdid, utf8_encoding(obj));
709
710         if (NULL == upath) {
711             rc = AFPERR_PARAM;
712             goto exit;
713         }
714         /* if unix priv don't try to match perm with dest folder */
715         if (!isdir && !vol_unix_priv(vol)) {
716             int  admode = ad_mode("", 0777) | vol->v_fperm;
717
718             setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL);
719             vol->vfs->vfs_setfilmode(vol, upath, admode, path->st_valid ? &path->st : NULL);
720         }
721         setvoltime(obj, vol );
722     }
723
724 exit:
725 #ifdef HAVE_ATFUNCS
726     if (sdir_fd != -1)
727         close(sdir_fd);
728 #endif
729
730     return( rc );
731 }
732
733 int veto_file(const char*veto_str, const char*path)
734 /* given a veto_str like "abc/zxc/" and path "abc", return 1
735  * veto_str should be '/' delimited
736  * if path matches any one of the veto_str elements exactly, then 1 is returned
737  * otherwise, 0 is returned.
738  */
739 {
740     int i;  /* index to veto_str */
741     int j;  /* index to path */
742
743     if ((veto_str == NULL) || (path == NULL))
744         return 0;
745
746     for(i=0, j=0; veto_str[i] != '\0'; i++) {
747         if (veto_str[i] == '/') {
748             if ((j>0) && (path[j] == '\0')) {
749                 LOG(log_debug, logtype_afpd, "vetoed file:'%s'", path);
750                 return 1;
751             }
752             j = 0;
753         } else {
754             if (veto_str[i] != path[j]) {
755                 while ((veto_str[i] != '/')
756                        && (veto_str[i] != '\0'))
757                     i++;
758                 j = 0;
759                 continue;
760             }
761             j++;
762         }
763     }
764     return 0;
765 }
766