]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/filedir.c
Cleanup header checks in configure.in
[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         ad_close_metadata( adp);
384         if ((bshort & htons(ATTRBIT_NORENAME))) {
385             rc = AFPERR_OLOCK;
386             goto exit;
387         }
388     }
389     if (sdir_fd != -1) {
390         if (fchdir(cwd_fd) != 0) {
391             LOG(log_error, logtype_afpd, "moveandrename: %s", strerror(errno) );
392             rc = AFPERR_MISC;
393             goto exit;
394         }
395     }
396
397     if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))){ 
398         rc = AFPERR_PARAM;
399         goto exit;
400     }
401     path.u_name = upath;
402     st = &path.st;
403     if (0 != (rc = check_name(vol, upath))) {
404         goto exit;
405     }
406
407     /* source == destination. we just silently accept this. */
408     if ((!isdir && curdir == sdir) || (isdir && curdir->d_did == sdir->d_pdid)) {
409         if (strcmp(oldname, newname) == 0) {
410             rc = AFP_OK;
411             goto exit;
412         }
413
414         if (stat(upath, st) == 0 || caseenumerate(vol, &path, curdir) == 0) {
415             if (!stat(p, &nst) && !(nst.st_dev == st->st_dev && nst.st_ino == st->st_ino) ) {
416                 /* not the same file */
417                 rc = AFPERR_EXIST;
418                 goto exit;
419             }
420             errno = 0;
421         }
422     } else if (stat(upath, st ) == 0 || caseenumerate(vol, &path, curdir) == 0) {
423         rc = AFPERR_EXIST;
424         goto exit;
425     }
426
427     if ( !isdir ) {
428         path.st_valid = 1;
429         path.st_errno = errno;
430         if (of_findname(&path)) {
431             rc = AFPERR_EXIST; /* was AFPERR_BUSY; */
432         } else {
433             rc = renamefile(vol, sdir_fd, p, upath, newname, adp );
434             if (rc == AFP_OK)
435                 of_rename(vol, opened, sdir, oldname, curdir, newname);
436         }
437     } else {
438         rc = renamedir(vol, sdir_fd, p, upath, sdir, curdir, newname);
439     }
440     if ( rc == AFP_OK && id ) {
441         /* renaming may have moved the file/dir across a filesystem */
442         if (stat(upath, st) < 0) {
443             rc = AFPERR_MISC;
444             goto exit;
445         }
446
447         /* Remove it from the cache */
448         struct dir *cacheddir = dircache_search_by_did(vol, id);
449         if (cacheddir) {
450             LOG(log_warning, logtype_afpd,"Still cached: \"%s/%s\"", getcwdpath(), upath);
451             (void)dir_remove(vol, cacheddir);
452         }
453
454         /* fix up the catalog entry */
455         cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath));
456     }
457
458 exit:
459     if (cwd_fd != -1)
460         close(cwd_fd);
461     return rc;
462 }
463
464 /* -------------------------------------------- */
465 int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
466 {
467     struct vol  *vol;
468     struct dir  *sdir;
469     char        *oldname, *newname;
470     struct path *path;
471     u_int32_t   did;
472     int         plen;
473     u_int16_t   vid;
474     int         isdir = 0;
475     int         rc;
476
477     *rbuflen = 0;
478     ibuf += 2;
479
480     memcpy( &vid, ibuf, sizeof( vid ));
481     ibuf += sizeof( vid );
482     if (NULL == ( vol = getvolbyvid( vid )) ) {
483         return( AFPERR_PARAM );
484     }
485
486     if (vol->v_flags & AFPVOL_RO)
487         return AFPERR_VLOCK;
488
489     memcpy( &did, ibuf, sizeof( did ));
490     ibuf += sizeof( did );
491     if (NULL == ( sdir = dirlookup( vol, did )) ) {
492         return afp_errno;
493     }
494
495     /* source pathname */
496     if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
497         return get_afp_errno(AFPERR_NOOBJ);
498     }
499
500     sdir = curdir;
501     newname = obj->newtmp;
502     oldname = obj->oldtmp;
503     isdir = path_isadir(path);
504     if ( *path->m_name != '\0' ) {
505         strcpy(oldname, path->m_name); /* an extra copy for of_rename */
506         if (isdir) {
507             /* curdir parent dir, need to move sdir back */
508             sdir = path->d_dir;
509         }
510     }
511     else {
512         if ( sdir->d_did == DIRDID_ROOT ) { /* root directory */
513             return( AFPERR_NORENAME );
514         }
515         /* move to destination dir */
516         if ( movecwd( vol, dirlookup(vol, sdir->d_pdid) ) < 0 ) {
517             return afp_errno;
518         }
519         memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) +1);
520     }
521
522     /* another place where we know about the path type */
523     if ((plen = copy_path_name(vol, newname, ibuf)) < 0) {
524         return( AFPERR_PARAM );
525     }
526
527     if (!plen) {
528         return AFP_OK; /* newname == oldname same dir */
529     }
530     
531     rc = moveandrename(vol, sdir, -1, oldname, newname, isdir);
532     if ( rc == AFP_OK ) {
533         setvoltime(obj, vol );
534     }
535
536     return( rc );
537 }
538
539 /* ------------------------------- */
540 int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
541 {
542     struct vol      *vol;
543     struct dir      *dir;
544     struct path         *s_path;
545     char        *upath;
546     int         did, rc;
547     u_int16_t       vid;
548
549     *rbuflen = 0;
550     ibuf += 2;
551
552     memcpy( &vid, ibuf, sizeof( vid ));
553     ibuf += sizeof( vid );
554     if (NULL == ( vol = getvolbyvid( vid )) ) {
555         return( AFPERR_PARAM );
556     }
557
558     if (vol->v_flags & AFPVOL_RO)
559         return AFPERR_VLOCK;
560
561     memcpy( &did, ibuf, sizeof( did ));
562     ibuf += sizeof( int );
563
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' || curdir->d_did == DIRDID_ROOT)
575             rc = AFPERR_ACCESS;
576         else
577             rc = deletecurdir( vol);
578     } else if (of_findname(s_path)) {
579         rc = AFPERR_BUSY;
580     } else {
581         /* it's a file st_valid should always be true
582          * only test for ENOENT because EACCES needs
583          * to read meta data in deletefile
584          */
585         if (s_path->st_valid && s_path->st_errno == ENOENT) {
586             rc = AFPERR_NOOBJ;
587         }
588         else {
589             rc = deletefile(vol, -1, upath, 1);
590
591             struct dir *cachedfile;
592             if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath), s_path->st.st_ctime))) {
593                 dircache_remove(vol, cachedfile, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX);
594                 dir_free(cachedfile);
595             }
596         }
597     }
598     if ( rc == AFP_OK ) {
599         curdir->offcnt--;
600         setvoltime(obj, vol );
601     }
602
603     return( rc );
604 }
605 /* ------------------------ */
606 char *absupath(const struct vol *vol, struct dir *dir, char *u)
607 {
608     static char pathbuf[MAXPATHLEN + 1];
609     bstring path;
610
611     if (u == NULL || dir == NULL || vol == NULL)
612         return NULL;
613
614     if ((path = bstrcpy(dir->d_fullpath)) == NULL)
615         return NULL;
616     if (bcatcstr(path, "/") != BSTR_OK)
617         return NULL;
618     if (bcatcstr(path, u) != BSTR_OK)
619         return NULL;
620     if (path->slen > MAXPATHLEN)
621         return NULL;
622
623     LOG(log_debug, logtype_afpd, "absupath: %s", cfrombstr(path));
624
625     strncpy(pathbuf, cfrombstr(path), blength(path) + 1);
626     bdestroy(path);
627
628     return(pathbuf);
629 }
630
631 char *ctoupath(const struct vol *vol, struct dir *dir, char *name)
632 {
633     if (vol == NULL || dir == NULL || name == NULL)
634         return NULL;
635     return absupath(vol, dir, mtoupath(vol, name, dir->d_did, utf8_encoding()));
636 }
637
638 /* ------------------------- */
639 int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
640 {
641     struct vol  *vol;
642     struct dir  *sdir, *ddir;
643     int         isdir;
644     char    *oldname, *newname;
645     struct path *path;
646     int     did;
647     int     pdid;
648     int         plen;
649     u_int16_t   vid;
650     int         rc;
651 #ifdef DROPKLUDGE
652     int     retvalue;
653 #endif /* DROPKLUDGE */
654     int     sdir_fd = -1;
655
656
657     *rbuflen = 0;
658     ibuf += 2;
659
660     memcpy( &vid, ibuf, sizeof( vid ));
661     ibuf += sizeof( vid );
662     if (NULL == ( vol = getvolbyvid( vid )) ) {
663         return( AFPERR_PARAM );
664     }
665
666     if (vol->v_flags & AFPVOL_RO)
667         return AFPERR_VLOCK;
668
669     /* source did followed by dest did */
670     memcpy( &did, ibuf, sizeof( did ));
671     ibuf += sizeof( int );
672     if (NULL == ( sdir = dirlookup( vol, did )) ) {
673         return afp_errno; /* was AFPERR_PARAM */
674     }
675
676     memcpy( &did, ibuf, sizeof( did ));
677     ibuf += sizeof( int );
678
679     /* source pathname */
680     if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
681         return get_afp_errno(AFPERR_NOOBJ);
682     }
683
684     sdir = curdir;
685     newname = obj->newtmp;
686     oldname = obj->oldtmp;
687
688     isdir = path_isadir(path);
689     if ( *path->m_name != '\0' ) {
690         if (isdir) {
691             sdir = path->d_dir;
692         }
693         strcpy(oldname, path->m_name); /* an extra copy for of_rename */
694     } else {
695         memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) + 1);
696     }
697
698 #ifdef HAVE_RENAMEAT
699     if ((sdir_fd = open(".", O_RDONLY)) == -1)
700         return AFPERR_MISC;
701 #endif
702
703     /* get the destination directory */
704     if (NULL == ( ddir = dirlookup( vol, did )) ) {
705         rc = afp_errno; /*  was AFPERR_PARAM */
706         goto exit;
707     }
708     if (NULL == ( path = cname( vol, ddir, &ibuf ))) {
709         rc = AFPERR_NOOBJ;
710         goto exit;
711     }
712     pdid = curdir->d_did;
713     if ( *path->m_name != '\0' ) {
714         rc = path_error(path, AFPERR_NOOBJ);
715         goto exit;
716     }
717
718     /* one more place where we know about path type */
719     if ((plen = copy_path_name(vol, newname, ibuf)) < 0) {
720         rc = AFPERR_PARAM;
721         goto exit;
722     }
723
724     if (!plen) {
725         strcpy(newname, oldname);
726     }
727
728     /* This does the work */
729     LOG(log_debug, logtype_afpd, "afp_move(oldname:'%s', newname:'%s', isdir:%u)",
730         oldname, newname, isdir);
731     rc = moveandrename(vol, sdir, sdir_fd, oldname, newname, isdir);
732
733     if ( rc == AFP_OK ) {
734         char *upath = mtoupath(vol, newname, pdid, utf8_encoding());
735
736         if (NULL == upath) {
737             rc = AFPERR_PARAM;
738             goto exit;
739         }
740         curdir->offcnt++;
741         sdir->offcnt--;
742 #ifdef DROPKLUDGE
743         if (vol->v_flags & AFPVOL_DROPBOX) {
744             /* FIXME did is not always the source id */
745             if ((retvalue=matchfile2dirperms (upath, vol, did)) != AFP_OK) {
746                 rc = retvalue;
747                 goto exit;
748             }
749         }
750         else
751 #endif /* DROPKLUDGE */
752             /* if unix priv don't try to match perm with dest folder */
753             if (!isdir && !vol_unix_priv(vol)) {
754                 int  admode = ad_mode("", 0777) | vol->v_fperm;
755
756                 setfilmode(upath, admode, NULL, vol->v_umask);
757                 vol->vfs->vfs_setfilmode(vol, upath, admode, NULL);
758             }
759         setvoltime(obj, vol );
760     }
761
762 exit:
763 #ifdef HAVE_RENAMEAT
764     if (sdir_fd != -1)
765         close(sdir_fd);
766 #endif
767
768     return( rc );
769 }
770
771 int veto_file(const char*veto_str, const char*path)
772 /* given a veto_str like "abc/zxc/" and path "abc", return 1
773  * veto_str should be '/' delimited
774  * if path matches any one of the veto_str elements exactly, then 1 is returned
775  * otherwise, 0 is returned.
776  */
777 {
778     int i;  /* index to veto_str */
779     int j;  /* index to path */
780
781     if ((veto_str == NULL) || (path == NULL))
782         return 0;
783
784     for(i=0, j=0; veto_str[i] != '\0'; i++) {
785         if (veto_str[i] == '/') {
786             if ((j>0) && (path[j] == '\0')) {
787                 LOG(log_debug, logtype_afpd, "vetoed file:'%s'", path);
788                 return 1;
789             }
790             j = 0;
791         } else {
792             if (veto_str[i] != path[j]) {
793                 while ((veto_str[i] != '/')
794                        && (veto_str[i] != '\0'))
795                     i++;
796                 j = 0;
797                 continue;
798             }
799             j++;
800         }
801     }
802     return 0;
803 }
804