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