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