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