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