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