]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/enumerate.c
"veto files" patch (Edmund Lam)
[netatalk.git] / etc / afpd / enumerate.c
1 /*
2  * $Id: enumerate.c,v 1.9 2001-09-04 13:52:45 rufustfirefly Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <dirent.h>
16 #include <errno.h>
17
18 #include <sys/syslog.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/file.h>
22 #include <sys/param.h>
23
24 #include <netatalk/endian.h>
25 #include <atalk/afp.h>
26 #include <atalk/adouble.h>
27 #ifdef CNID_DB
28 #include <atalk/cnid.h>
29 #endif /* CNID_DB */
30 #include "desktop.h"
31 #include "directory.h"
32 #include "volume.h"
33 #include "globals.h"
34 #include "file.h"
35
36 /* check for mtab DID code */
37 #ifdef DID_MTAB
38 #include "parse_mtab.h"
39 #endif /* DID_MTAB */
40
41 struct dir *
42 adddir( vol, dir, name, namlen, upath, upathlen, st )
43     struct vol  *vol;
44     struct dir  *dir;
45     char        *name, *upath;
46     int         namlen, upathlen;
47     struct stat *st;
48 {
49     struct dir  *cdir, *edir;
50 #if AD_VERSION > AD_VERSION1
51     struct adouble ad;
52 #endif /* AD_VERSION > AD_VERSION1 */
53
54 #ifndef USE_LASTDID
55     struct stat lst, *lstp;
56 #endif /* USE_LASTDID */
57
58     if ((cdir = dirnew(namlen + 1)) == NULL) {
59         syslog( LOG_ERR, "adddir: malloc: %s", strerror(errno) );
60         return NULL;
61     }
62     strcpy( cdir->d_name, name );
63     cdir->d_name[namlen] = '\0';
64
65     cdir->d_did = 0;
66
67 #if AD_VERSION > AD_VERSION1
68     /* look in AD v2 header */
69     memset(&ad, 0, sizeof(ad));
70     if (ad_open(upath, ADFLAGS_HF|ADFLAGS_DIR, O_RDONLY, 0, &ad) >= 0) {
71         /* if we can parse the AppleDouble header, retrieve the DID entry into cdir->d_did */
72             memcpy(&cdir->d_did, ad_entry(&ad, ADEID_DID), sizeof(cdir->d_did));
73             ad_close(&ad, ADFLAGS_HF);
74         }
75 #endif /* AD_VERSION */
76
77 #ifdef CNID_DB
78         /* add to cnid db */
79     cdir->d_did = cnid_add(vol->v_db, st, dir->d_did, upath,
80                                    upathlen, cdir->d_did);
81 #endif /* CNID_DB */
82
83         if (cdir->d_did == 0) {
84 #ifdef USE_LASTDID
85         /* last way of doing DIDs */
86         cdir->d_did = htonl( vol->v_lastdid++ );
87 #else /* USE_LASTDID */
88         lstp = lstat(upath, &lst) < 0 ? st : &lst;
89 #ifdef DID_MTAB
90         /* mtab way of doing DIDs */
91         cdir->d_did = htonl( afpd_st_cnid ( lstp ) );
92 #else /* DID_MTAB */
93         /* the old way of doing DIDs (default) */
94         cdir->d_did = htonl( CNID(lstp, 0) );
95 #endif /* DID_MTAB */
96 #endif /* USE_LASTDID */
97     }
98
99     if ((edir = dirinsert( vol, cdir ))) {
100             if (edir->d_name) {
101                     if (strcmp(edir->d_name, cdir->d_name)) {
102                             syslog(LOG_INFO, "WARNING: DID conflict for '%s' and '%s'. Are these the same file?", edir->d_name, cdir->d_name);
103                     }
104                     free(cdir->d_name);
105                     free(cdir);
106                     return edir;
107             }
108             edir->d_name = cdir->d_name;
109             free(cdir);
110             cdir = edir;
111     }
112
113     /* parent/child directories */
114     cdir->d_parent = dir;
115     dirchildadd(dir, cdir);
116     return( cdir );
117 }
118
119 /*
120  * Struct to save directory reading context in. Used to prevent
121  * O(n^2) searches on a directory.
122  */
123 struct savedir {
124     u_short     sd_vid;
125     int         sd_did;
126     int         sd_buflen;
127     char        *sd_buf;
128     char        *sd_last;
129     int         sd_sindex;
130 };
131 #define SDBUFBRK        1024
132
133 int afp_enumerate(obj, ibuf, ibuflen, rbuf, rbuflen )
134     AFPObj      *obj;
135     char        *ibuf, *rbuf;
136     int         ibuflen, *rbuflen;
137 {
138     struct stat                 st;
139     static struct savedir       sd = { 0, 0, 0, NULL, NULL, 0 };
140     struct vol                  *vol;
141     struct dir                  *dir;
142     struct dirent               *de;
143     DIR                         *dp;
144     int                         did, ret, esz, len, first = 1;
145     char                        *path, *data, *end, *start;
146     u_int16_t                   vid, fbitmap, dbitmap, reqcnt, actcnt = 0;
147     u_int16_t                   sindex, maxsz, sz = 0;
148
149     if ( sd.sd_buflen == 0 ) {
150         if (( sd.sd_buf = (char *)malloc( SDBUFBRK )) == NULL ) {
151             syslog( LOG_ERR, "afp_enumerate: malloc: %s", strerror(errno) );
152             *rbuflen = 0;
153             return AFPERR_MISC;
154         }
155         sd.sd_buflen = SDBUFBRK;
156     }
157
158     ibuf += 2;
159
160     memcpy( &vid, ibuf, sizeof( vid ));
161     ibuf += sizeof( vid );
162
163     if (( vol = getvolbyvid( vid )) == NULL ) {
164         *rbuflen = 0;
165         return( AFPERR_PARAM );
166     }
167
168     memcpy( &did, ibuf, sizeof( did ));
169     ibuf += sizeof( did );
170
171     if (( dir = dirsearch( vol, did )) == NULL ) {
172         *rbuflen = 0;
173         return( AFPERR_NODIR );
174     }
175
176     memcpy( &fbitmap, ibuf, sizeof( fbitmap ));
177     fbitmap = ntohs( fbitmap );
178     ibuf += sizeof( fbitmap );
179
180     memcpy( &dbitmap, ibuf, sizeof( dbitmap ));
181     dbitmap = ntohs( dbitmap );
182     ibuf += sizeof( dbitmap );
183
184     /* check for proper bitmaps -- the stuff in comments is for
185      * variable directory ids. */
186     if (!(fbitmap || dbitmap) 
187         /*|| (fbitmap & (1 << FILPBIT_PDID)) || 
188           (dbitmap & (1 << DIRPBIT_PDID))*/) {
189       *rbuflen = 0;
190       return AFPERR_BITMAP;
191     }
192
193     memcpy( &reqcnt, ibuf, sizeof( reqcnt ));
194     reqcnt = ntohs( reqcnt );
195     ibuf += sizeof( reqcnt );
196
197     memcpy( &sindex, ibuf, sizeof( sindex ));
198     sindex = ntohs( sindex );
199     ibuf += sizeof( sindex );
200
201     memcpy( &maxsz, ibuf, sizeof( maxsz ));
202     maxsz = ntohs( maxsz );
203     ibuf += sizeof( maxsz );
204
205     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
206         *rbuflen = 0;
207         return( AFPERR_NODIR );
208     }
209     data = rbuf + 3 * sizeof( u_int16_t );
210     sz = 3 * sizeof( u_int16_t );
211
212     /*
213      * Read the directory into a pre-malloced buffer, stored
214      *          len <name> \0
215      * The end is indicated by a len of 0.
216      */
217     if ( sindex == 1 || curdir->d_did != sd.sd_did || vid != sd.sd_vid ) {
218         sd.sd_last = sd.sd_buf;
219
220         if (( dp = opendir( mtoupath(vol, path ))) == NULL ) {
221             *rbuflen = 0;
222             return (errno == ENOTDIR) ? AFPERR_BADTYPE : AFPERR_NODIR;
223         }
224
225         end = sd.sd_buf + sd.sd_buflen;
226         for ( de = readdir( dp ); de != NULL; de = readdir( dp )) {
227             if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, "."))
228               continue;
229
230             if (!(validupath(vol, de->d_name)))
231               continue;
232
233             /* check for vetoed filenames */
234             if (veto_file(vol->v_veto, de->d_name))
235               continue;
236
237             /* now check against too big a file */
238             if (strlen(utompath(vol, de->d_name)) > MACFILELEN)
239               continue;
240
241             len = strlen(de->d_name);
242             *(sd.sd_last)++ = len;
243
244             if ( sd.sd_last + len + 2 > end ) {
245                 char *buf;
246
247                 start = sd.sd_buf;
248                 if ((buf = (char *) realloc( sd.sd_buf, sd.sd_buflen + 
249                                              SDBUFBRK )) == NULL ) {
250                     syslog( LOG_ERR, "afp_enumerate: realloc: %s",
251                             strerror(errno) );
252                     closedir(dp);
253                     *rbuflen = 0;
254                     return AFPERR_MISC;
255                 }
256                 sd.sd_buf = buf;
257                 sd.sd_buflen += SDBUFBRK;
258                 sd.sd_last = ( sd.sd_last - start ) + sd.sd_buf;
259                 end = sd.sd_buf + sd.sd_buflen;
260             }
261
262             memcpy( sd.sd_last, de->d_name, len + 1 );
263             sd.sd_last += len + 1;
264         }
265         *sd.sd_last = 0;
266
267         sd.sd_last = sd.sd_buf;
268         sd.sd_sindex = 1;
269
270         closedir( dp );
271         sd.sd_vid = vid;
272         sd.sd_did = did;
273     }
274
275     /*
276      * Position sd_last as dictated by sindex.
277      */
278     if ( sindex < sd.sd_sindex ) {
279         sd.sd_sindex = 1;
280         sd.sd_last = sd.sd_buf;
281     }
282     while ( sd.sd_sindex < sindex ) {
283         len = *(sd.sd_last)++;
284         if ( len == 0 ) {
285             sd.sd_did = -1;     /* invalidate sd struct to force re-read */
286             *rbuflen = 0;
287             return( AFPERR_NOOBJ );
288         }
289         sd.sd_last += len + 1;
290         sd.sd_sindex++;
291     }
292
293     while (( len = *(sd.sd_last)) != 0 ) {
294         /*
295          * If we've got all we need, send it.
296          */
297         if ( actcnt == reqcnt ) {
298             break;
299         }
300
301         /*
302          * Save the start position, in case we exceed the buffer
303          * limitation, and have to back up one.
304          */
305         start = sd.sd_last;
306         sd.sd_last++;
307
308         if ( stat( sd.sd_last, &st ) < 0 ) {
309             syslog( LOG_DEBUG, "afp_enumerate: stat %s: %s",
310                     sd.sd_last, strerror(errno) );
311             sd.sd_last += len + 1;
312             continue;
313         }
314
315         /*
316          * If a fil/dir is not a dir, it's a file. This is slightly
317          * inaccurate, since that means /dev/null is a file, /dev/printer
318          * is a file, etc.
319          */
320         if ( S_ISDIR(st.st_mode)) {
321             if ( dbitmap == 0 ) {
322                 sd.sd_last += len + 1;
323                 continue;
324             }
325             path = utompath(vol, sd.sd_last);
326             dir = curdir->d_child; 
327             while (dir) {
328                 if ( strcmp( dir->d_name, path ) == 0 ) {
329                     break;
330                 }
331                 dir = (dir == curdir->d_child->d_prev) ? NULL : dir->d_next;
332             }
333             if (!dir && ((dir = adddir( vol, curdir, path, strlen( path ),
334                                         sd.sd_last, len, &st)) == NULL)) {
335               *rbuflen = 0;
336               return AFPERR_MISC;
337             }
338               
339
340             if (( ret = getdirparams(vol, dbitmap, sd.sd_last, dir,
341                     &st, data + 2 * sizeof( u_char ), &esz )) != AFP_OK ) {
342                 *rbuflen = 0;
343                 return( ret );
344             }
345
346         } else {
347             if ( fbitmap == 0 ) {
348                 sd.sd_last += len + 1;
349                 continue;
350             }
351             
352             if (( ret = getfilparams(vol, fbitmap, utompath(vol, sd.sd_last),
353                     curdir, &st, data + 2 * sizeof( u_char ), &esz )) !=
354                     AFP_OK ) {
355                 *rbuflen = 0;
356                 return( ret );
357             }
358         }
359
360         /*
361          * Make sure entry is an even length, possibly with a null
362          * byte on the end.
363          */
364         if ( esz & 1 ) {
365             *(data + 2 * sizeof( u_char ) + esz ) = '\0';
366             esz++;
367         }
368
369         /*
370          * Check if we've exceeded the size limit.
371          */
372         if ( maxsz < sz + esz + 2 * sizeof( u_char )) {
373             if (first) { /* maxsz can't hold a single reply */
374               *rbuflen = 0; 
375               return AFPERR_PARAM;
376             }
377             sd.sd_last = start;
378             break;
379         }
380
381         if (first)
382           first = 0;
383
384         sz += esz + 2 * sizeof( u_char );
385         *data++ = esz + 2 * sizeof( u_char );
386         *data++ = S_ISDIR(st.st_mode) ? FILDIRBIT_ISDIR : FILDIRBIT_ISFILE;
387         data += esz;
388         actcnt++;
389         sd.sd_last += len + 1;
390     }
391
392     if ( actcnt == 0 ) {
393         *rbuflen = 0;
394         sd.sd_did = -1;         /* invalidate sd struct to force re-read */
395         return( AFPERR_NOOBJ );
396     }
397     sd.sd_sindex = sindex + actcnt;
398
399     /*
400      * All done, fill in misc junk in rbuf
401      */
402     fbitmap = htons( fbitmap );
403     memcpy( rbuf, &fbitmap, sizeof( fbitmap ));
404     rbuf += sizeof( fbitmap );
405     dbitmap = htons( dbitmap );
406     memcpy( rbuf, &dbitmap, sizeof( dbitmap ));
407     rbuf += sizeof( dbitmap );
408     actcnt = htons( actcnt );
409     memcpy( rbuf, &actcnt, sizeof( actcnt ));
410     rbuf += sizeof( actcnt );
411     *rbuflen = sz;
412     return( AFP_OK );
413 }
414
415
416 /* why is this here? well, FPCatSearch is essentially an FPEnumerate
417  * with filters. */
418 int afp_catsearch(AFPObj *obj, char *ibuf, int ibuflen, 
419                   char *rbuf, int *rbuflen)
420 {
421     struct vol *vol;
422     u_int16_t   vid;
423
424     ibuf += 2;
425     memcpy(&vid, ibuf, sizeof(vid));
426     ibuf += sizeof(vid);
427
428     *rbuflen = 0;
429     if ((vol = getvolbyvid(vid)) == NULL)
430        return AFPERR_PARAM;
431
432     /* the ritual:
433      * do a breadth-first search of directories:
434      *   lookup did/name info.
435      *   add to result if match
436      *   check to see if we've exceeded our timelimit
437      *     if yes, return current position
438      *     if not, continue
439      * 
440      *   we keep a copy of our current position in struct vol.
441      *   if the next catsearch request for that volume isn't at
442      *   at the current position, bail and return catchanged.
443      */
444
445     /* eof when done */
446     return AFPERR_EOF;
447 }