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