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