]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/catsearch.c
Removed the --with-catsearch option from configure and enabled FPCatSearch
[netatalk.git] / etc / afpd / catsearch.c
1 /* 
2  * Netatalk 2002 (c)
3  * Copyright (C) 1990, 1993 Regents of The University of Michigan
4  * All Rights Reserved. See COPYRIGHT
5  */
6
7
8 /*
9  * This file contains FPCatSearch implementation. FPCatSearch performs
10  * file/directory search based on specified criteria. It is used by client
11  * to perform fast searches on (propably) big volumes. So, it has to be
12  * pretty fast.
13  *
14  * This implementation bypasses most of adouble/libatalk stuff as long as
15  * possible and does a standard filesystem search. It calls higher-level
16  * libatalk/afpd functions only when it is really needed, mainly while
17  * returning some non-UNIX information or filtering by non-UNIX criteria.
18  *
19  * Initial version written by Rafal Lewczuk <rlewczuk@pronet.pl>
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif /* HAVE_CONFIG_H */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <dirent.h>
30 #include <errno.h>
31 #include <syslog.h>
32 #include <unistd.h>
33
34 #if STDC_HEADERS
35 #include <string.h>
36 #else
37 #ifndef HAVE_MEMCPY
38 #define memcpy(d,s,n) bcopy ((s), (d), (n))
39 #define memmove(d,s,n) bcopy ((s), (d), (n))
40 #endif /* ! HAVE_MEMCPY */
41 #endif
42
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/file.h>
46 #include <netinet/in.h>
47
48 #include <netatalk/endian.h>
49 #include <atalk/afp.h>
50 #include <atalk/adouble.h>
51 #ifdef CNID_DB
52 #include <atalk/cnid.h>
53 #endif /* CNID_DB */
54 #include "desktop.h"
55 #include "directory.h"
56 #include "file.h"
57 #include "volume.h"
58 #include "globals.h"
59 #include "filedir.h"
60 #include "fork.h"
61
62 struct finderinfo {
63         u_int32_t f_type;
64         u_int32_t creator;
65         u_int8_t attrs;    /* File attributes (8 bits)*/
66         u_int8_t label;    /* Label (8 bits)*/
67         char reserved[22]; /* Unknown (at least for now...) */
68 };
69
70 /* Known attributes:
71  * 0x04 - has a custom icon
72  * 0x20 - name/icon is locked
73  * 0x40 - is invisible
74  * 0x80 - is alias
75  *
76  * Known labels:
77  * 0x02 - project 2
78  * 0x04 - project 1
79  * 0x06 - personal
80  * 0x08 - cool
81  * 0x0a - in progress
82  * 0x0c - hot
83  * 0x0e - essential
84  */
85
86 /* This is our search-criteria structure. */
87 struct scrit {
88         u_int32_t rbitmap;          /* Request bitmap - which values should we check ? */
89         u_int16_t fbitmap, dbitmap; /* file & directory bitmap - which values should we return ? */
90         u_int16_t attr;             /* File attributes */
91         time_t cdate;               /* Creation date */
92         time_t mdate;               /* Last modification date */
93         time_t bdate;               /* Last backup date */
94         u_int32_t pdid;             /* Parent DID */
95         u_int16_t offcnt;           /* Offspring count */
96         struct finderinfo finfo;    /* Finder info */
97         char lname[32];             /* Long name */
98 };
99
100 /*
101  * Directory tree search is recursive by its nature. But AFP specification
102  * requires FPCatSearch to pause after returning n results and be able to
103  * resume the search later. So we have to do recursive search using flat
104  * (iterative) algorithm and remember all directories to look into in an
105  * stack-like structure. The structure below is one item of directory stack.
106  *
107  */
108 struct dsitem {
109         char *lname;     /* Long name */
110         struct dir *dir; /* Structure describing this directory */
111         int pidx;        /* Parent's dsitem structure index. */
112         int checked;     /* Have we checked this directory ? */
113         char *path;      /* UNIX path to this directory */
114 };
115  
116
117 #define DS_BSIZE 128
118 static int cur_pos = 0;    /* Saved position index (ID) - used to remember "position" across FPCatSearch calls */
119 static DIR *dirpos = NULL; /* UNIX structure describing currently opened directory. */
120 static int save_cidx = -1; /* Saved index of currently scanned directory. */
121
122 static struct dsitem *dstack = NULL; /* Directory stack data... */
123 static int dssize = 0;               /* Directory stack (allocated) size... */
124 static int dsidx = 0;                /* First free item index... */
125
126 static struct scrit c1, c2;          /* search criteria */
127
128 /* Puts new item onto directory stack. */
129 static int addstack(char *lname, struct dir *dir, int pidx)
130 {
131         struct dsitem *ds;
132
133         /* check if we have some space on stack... */
134         if (dsidx >= dssize) {
135                 dssize += DS_BSIZE;
136                 dstack = realloc(dstack, dssize * sizeof(struct dsitem));       
137                 if (dstack == NULL)
138                         return -1;
139         }
140
141         /* Put new element. Allocate and copy lname and path. */
142         ds = dstack + dsidx++;
143         ds->lname = strdup(lname);
144         ds->dir = dir;
145         ds->pidx = pidx;
146         if (pidx >= 0) {
147                 ds->path = malloc(strlen(dstack[pidx].path) + strlen(ds->lname) + 2);
148                 strcpy(ds->path, dstack[pidx].path);
149                 strcat(ds->path, "/");
150                 strcat(ds->path, ds->lname);
151         }
152
153         ds->checked = 0;
154
155         return 0;
156 }
157
158 /* Removes checked items from top of directory stack. Returns index of the first unchecked elements or -1. */
159 static int reducestack()
160 {
161         int r;
162         if (save_cidx != -1) {
163                 r = save_cidx;
164                 save_cidx = -1;
165                 return r;
166         }
167
168         while (dsidx > 0) {
169                 if (dstack[dsidx-1].checked) {
170                         dsidx--;
171                         free(dstack[dsidx].lname);
172                         free(dstack[dsidx].path);
173                         /* Check if we need to free (or release) dir structures */
174                 } else
175                         return dsidx - 1;
176         } // while
177         return -1;
178 } /* reducestack() */
179
180 /* Clears directory stack. */
181 static void clearstack() 
182 {
183         save_cidx = -1;
184         while (dsidx > 0) {
185                 dsidx--;
186                 free(dstack[dsidx].lname);
187                 free(dstack[dsidx].path);
188                 /* Check if we need to free (or release) dir structures */
189         }
190 } /* clearstack() */
191
192 /* Fills in dir field of dstack[cidx]. Must fill parent dirs' fields if needed... */
193 static int resolve_dir(struct vol *vol, int cidx)
194 {
195         struct dir *dir, *curdir;
196         struct stat statbuf;
197
198         if (dstack[cidx].dir != NULL)
199                 return 1;
200
201         if (dstack[cidx].pidx < 0)
202                 return 0;
203
204         if (dstack[dstack[cidx].pidx].dir == NULL && resolve_dir(vol, dstack[cidx].pidx) == 0)
205                return 0;
206
207         curdir = dstack[dstack[cidx].pidx].dir;
208         dir = curdir->d_child;
209         while (dir) {
210                 if (strcmp(dir->d_name, dstack[cidx].lname) == 0)
211                         break;
212                 dir = (dir == curdir->d_child->d_prev) ? NULL : dir->d_next;
213         } /* while */
214
215         if (!dir)
216                 if (stat(dstack[cidx].path, &statbuf)==-1) {
217                         syslog(LOG_DEBUG, "resolve_dir: stat %s: %s", dstack[cidx].path, strerror(errno));
218                         return 0;
219                 }
220
221         if (!dir && ((dir = adddir(vol, curdir, dstack[cidx].lname, strlen(dstack[cidx].lname),
222                                                 dstack[cidx].path, strlen(dstack[cidx].path), &statbuf)) == NULL))
223                         return 0;
224         dstack[cidx].dir = dir;
225
226         return 1;
227 } /* resolve_dir */
228
229 /* Looks up for an opened adouble structure, opens resource fork of selected file. */
230 static struct adouble *adl_lkup(char *upath, struct stat *sb)
231 {
232         static struct adouble ad;
233         struct adouble *adp;
234         struct ofork *of;
235         int isdir = S_ISDIR(sb->st_mode);
236
237         if (!isdir && (of = of_findname(upath, sb ))) {
238                 adp = of->of_ad;
239         } else {
240                 memset(&ad, 0, sizeof(ad));
241                 adp = &ad;
242         } 
243
244         if ( ad_open( upath, ADFLAGS_HF | (isdir)?ADFLAGS_DIR:0, O_RDONLY, 0, adp) < 0 ) {
245                 return NULL;
246         } 
247         return adp;     
248 }
249
250 #define CATPBIT_PARTIAL 31
251 /* Criteria checker. This function returns a 2-bit value. */
252 /* bit 0 means if checked file meets given criteria. */
253 /* bit 1 means if it is a directory and we should descent into it. */
254 /* uname - UNIX name 
255  * fname - our fname (translated to UNIX)
256  * cidx - index in directory stack
257  */
258 static int crit_check(struct vol *vol, char *uname, char *fname, int cidx) {
259         int r = 0;
260         struct stat sbuf;
261         u_int16_t attr;
262         struct finderinfo *finfo = NULL;
263         struct adouble *adp = NULL;
264         time_t c_date, b_date;
265
266         if (stat(uname, &sbuf) < 0)
267                 return 0;
268         
269         if (S_ISDIR(sbuf.st_mode)) {
270                 r = 2;
271                 if (!c1.dbitmap)
272                         return r;
273         }
274         else if (!c1.fbitmap)
275                 return 0;
276                 
277         /* Kind of optimization: 
278          * -- first check things we've already have - filename
279          * -- last check things we get from ad_open()
280          */
281
282         /* Check for filename */
283         if (c1.rbitmap & (1<<DIRPBIT_LNAME)) { 
284                 if (c1.rbitmap & (1<<CATPBIT_PARTIAL)) {
285                         if (strstr(fname, c1.lname) == NULL)
286                                 goto crit_check_ret;
287                 } else
288                         if (strcmp(fname, c1.lname) != 0)
289                                 goto crit_check_ret;
290         } /* if (c1.rbitmap & ... */
291
292
293         /* FIXME */
294         if ((unsigned)c2.mdate > 0x7fffffff)
295                 c2.mdate = 0x7fffffff;
296         if ((unsigned)c2.cdate > 0x7fffffff)
297                 c2.cdate = 0x7fffffff;
298         if ((unsigned)c2.bdate > 0x7fffffff)
299                 c2.bdate = 0x7fffffff;
300
301         /* Check for modification date FIXME: should we look at adouble structure ? */
302         if ((c1.rbitmap & (1<<DIRPBIT_MDATE))) 
303                 if (sbuf.st_mtime < c1.mdate || sbuf.st_mtime > c2.mdate)
304                         goto crit_check_ret;
305
306         /* Check for creation date... */
307         if (c1.rbitmap & (1<<DIRPBIT_CDATE)) {
308                 if (adp || (adp = adl_lkup(uname, &sbuf))) {
309                         if (ad_getdate(adp, AD_DATE_CREATE, (u_int32_t*)&c_date) >= 0)
310                                 c_date = AD_DATE_TO_UNIX(c_date);
311                         else c_date = sbuf.st_mtime;
312                 } else c_date = sbuf.st_mtime;
313                 if (c_date < c1.cdate || c_date > c2.cdate)
314                         goto crit_check_ret;
315         }
316
317         /* Check for backup date... */
318         if (c1.rbitmap & (1<<DIRPBIT_BDATE)) {
319                 if (adp || (adp == adl_lkup(uname, &sbuf))) {
320                         if (ad_getdate(adp, AD_DATE_BACKUP, (u_int32_t*)&b_date) >= 0)
321                                 b_date = AD_DATE_TO_UNIX(b_date);
322                         else b_date = sbuf.st_mtime;
323                 } else b_date = sbuf.st_mtime;
324                 if (b_date < c1.bdate || b_date > c2.bdate)
325                         goto crit_check_ret;
326         }
327                                 
328         /* Check attributes */
329         if ((c1.rbitmap & (1<<DIRPBIT_ATTR)) && c2.attr != 0)
330                 if (adp || (adp = adl_lkup(uname, &sbuf))) {
331                         ad_getattr(adp, &attr);
332                         if ((attr & c2.attr) != c1.attr)
333                                 goto crit_check_ret;
334                 } else goto crit_check_ret;
335                 
336
337         /* Check file type ID */
338         if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.f_type != 0)
339                 if (adp || (adp = adl_lkup(uname, &sbuf))) {
340                         finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
341                         if (finfo->f_type != c1.finfo.f_type)
342                                 goto crit_check_ret;
343                 } else goto crit_check_ret;
344
345         /* Check creator ID */
346         if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.creator != 0)
347                 if (adp || (adp = adl_lkup(uname, &sbuf))) {
348                         finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
349                         if (finfo->creator != c1.finfo.creator)
350                                 goto crit_check_ret;
351                 } else goto crit_check_ret;
352         
353         /* Check finder info attributes */
354         if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.attrs != 0)
355                 if (adp || (adp = adl_lkup(uname, &sbuf))) {
356                         finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
357                         if ((finfo->attrs & c2.finfo.attrs) != c1.finfo.attrs)
358                                 goto crit_check_ret;
359                 } else goto crit_check_ret;
360
361         /* Check label */
362         if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.label != 0)
363                 if (adp || (adp = adl_lkup(uname, &sbuf))) {
364                         finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
365                         if ((finfo->label & c2.finfo.label) != c1.finfo.label)
366                                 goto crit_check_ret;
367                 } else goto crit_check_ret;
368         
369         /* FIXME: Attributes check ! */
370         
371         /* All criteria are met. */
372         r |= 1;
373 crit_check_ret:
374         if (adp != NULL)
375                 ad_close(adp, ADFLAGS_HF);
376         return r;
377 }  
378
379
380 /* Adds an item to resultset. */
381 static int rslt_add(struct vol *vol, struct stat *statbuf, char *fname, short cidx, int isdir, char **rbuf)
382 {
383         char *p = *rbuf;
384         int l = fname != NULL ? strlen(fname) : 0;
385         u_int32_t did;
386         char p0;
387
388         p0 = p[0] = cidx != -1 ? l + 7 : l + 5;
389         if (p0 & 1) p[0]++;
390         p[1] = isdir ? 128 : 0;
391         p += 2;
392         if (cidx != -1) {
393                 if (dstack[cidx].dir == NULL && resolve_dir(vol, cidx) == 0)
394                         return 0;
395                 did = dstack[cidx].dir->d_did;
396                 memcpy(p, &did, sizeof(did));
397                 p += sizeof(did);
398         }
399
400         /* Fill offset of returned file name */
401         if (fname != NULL) {
402                 *p++ = 0;
403                 *p++ = (int)(p - *rbuf) - 1;
404                 p[0] = l;
405                 strcpy(p+1, fname);
406                 p += l + 1;
407         }
408
409         if (p0 & 1)
410                 *p++ = 0;
411
412         *rbuf = p;
413         /* *rbuf[0] = (int)(p-*rbuf); */
414         return 1;
415 } /* rslt_add */
416
417 #define VETO_STR \
418         "./../.AppleDouble/.AppleDB/Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/.AppleDesktop/.Parent/"
419
420 /* This function performs search. It is called directly from afp_catsearch 
421  * vol - volume we are searching on ...
422  * dir - directory we are starting from ...
423  * c1, c2 - search criteria
424  * rmatches - maximum number of matches we can return
425  * pos - position we've stopped recently
426  * rbuf - output buffer
427  * rbuflen - output buffer length
428 */
429 static int catsearch(struct vol *vol, struct dir *dir,  
430                      int rmatches, int *pos, char *rbuf, u_int32_t *nrecs, int *rsize)
431 {
432         int cidx, r, i;
433         char *fname = NULL;
434         struct dirent *entry;
435         struct stat statbuf;
436         int result = AFP_OK;
437         int ccr;
438         char *orig_dir = NULL;
439         int orig_dir_len = 128;
440         char *path = vol->v_path;
441         char *rrbuf = rbuf;
442
443         if (*pos != 0 && *pos != cur_pos) 
444                 return AFPERR_CATCHNG;
445
446         /* FIXME: Category "offspring count ! */
447
448         /* So we are beginning... */
449         /* We need to initialize all mandatory structures/variables and change working directory appropriate... */
450         if (*pos == 0) {
451                 clearstack();
452                 if (dirpos != NULL) {
453                         closedir(dirpos);
454                         dirpos = NULL;
455                 } /* if (dirpos != NULL) */
456                 
457                 if (addstack("", dir, -1) == -1) {
458                         result = AFPERR_MISC;
459                         goto catsearch_end;
460                 }
461                 dstack[0].path = strdup(path);
462                 /* FIXME: Sometimes DID is given by klient ! (correct this one above !) */
463         }
464
465         /* Save current path */
466         orig_dir = (char*)malloc(orig_dir_len);
467         while (getcwd(orig_dir, orig_dir_len-1)==NULL) {
468                 if (errno != ERANGE) {
469                         result = AFPERR_MISC;
470                         goto catsearch_end;
471                 }
472                 orig_dir_len += 128; 
473                 orig_dir = realloc(orig_dir, orig_dir_len);
474         } /* while() */
475         
476         while ((cidx = reducestack()) != -1) {
477                 if (dirpos == NULL)
478                         dirpos = opendir(dstack[cidx].path);    
479                 if (dirpos == NULL) {
480                         switch (errno) {
481                         case EACCES:
482                                 dstack[cidx].checked = 1;
483                                 continue;
484                         case EMFILE:
485                         case ENFILE:
486                         case ENOENT:
487                                 result = AFPERR_NFILE;
488                                 break;
489                         case ENOMEM:
490                         case ENOTDIR:
491                         default:
492                                 result = AFPERR_MISC;
493                         } /* switch (errno) */
494                         goto catsearch_end;
495                 }
496                 chdir(dstack[cidx].path);
497                 while ((entry=readdir(dirpos)) != NULL) {
498                         (*pos)++;
499                         if (veto_file(VETO_STR, entry->d_name))
500                                 continue;
501                         if (stat(entry->d_name, &statbuf) != 0) {
502                                 switch (errno) {
503                                 case EACCES:
504                                 case ELOOP:
505                                 case ENOENT:
506                                         continue;
507                                 case ENOTDIR:
508                                 case EFAULT:
509                                 case ENOMEM:
510                                 case ENAMETOOLONG:
511                                 default:
512                                         result = AFPERR_MISC;
513                                         goto catsearch_end;
514                                 } /* switch (errno) */
515                         } /* if (stat(entry->d_name, &statbuf) != 0) */
516                         fname = utompath(vol, entry->d_name);
517                         for (i = 0; fname[i] != 0; i++)
518                                 fname[i] = tolower(fname[i]);
519                         if (strlen(fname) > MACFILELEN) 
520                                 continue;
521                         ccr = crit_check(vol, entry->d_name, fname, cidx);
522                         /* bit 0 means that criteria has ben met */
523                         if (ccr & 1) {
524                                 r = rslt_add(vol, &statbuf, 
525                                              (c1.fbitmap&(1<<FILPBIT_LNAME))|(c1.dbitmap&(1<<DIRPBIT_LNAME)) ? 
526                                                  utompath(vol, entry->d_name) : NULL,   
527                                              (c1.fbitmap&(1<<FILPBIT_PDID))|(c1.dbitmap&(1<<DIRPBIT_PDID)) ? 
528                                                  cidx : -1, 
529                                              S_ISDIR(statbuf.st_mode), &rrbuf); 
530                                 if (r == 0) {
531                                         result = AFPERR_MISC;
532                                         goto catsearch_end;
533                                 } 
534                                 *nrecs += r;
535                                 /* Number of matches limit */
536                                 if (--rmatches == 0) 
537                                         goto catsearch_pause; /* FIXME: timelimit checks ! */
538                                 /* Block size limit */
539                                 if (rrbuf - rbuf >= 448)
540                                         goto catsearch_pause;
541
542                         } 
543                         /* bit 1 means that we have to descend into this directory. */
544                         if (ccr & 2) {
545                                 if (S_ISDIR(statbuf.st_mode))
546                                         if (addstack(entry->d_name, NULL, cidx) == -1) {
547                                                 result = AFPERR_MISC;
548                                                 goto catsearch_end;
549                                         } /* if (addstack... */
550                         }
551                 } /* while ((entry=readdir(dirpos)) != NULL) */
552                 closedir(dirpos);dirpos = NULL;
553                 dstack[cidx].checked = 1;
554         } /* while (current_idx = reducestack()) != -1) */
555
556         /* We have finished traversing our tree. Return EOF here. */
557         result = AFPERR_EOF;
558         goto catsearch_end;
559
560 catsearch_pause:
561         cur_pos = *pos; 
562         save_cidx = cidx;
563
564 catsearch_end: /* Exiting catsearch: error condition */
565         *rsize = rrbuf - rbuf;
566         if (orig_dir != NULL) {
567                 chdir(orig_dir);
568                 free(orig_dir);
569         }
570         return result;
571 } /* catsearch() */
572
573
574 int afp_catsearch(AFPObj *obj, char *ibuf, int ibuflen,
575                   char *rbuf, int *rbuflen)
576 {
577     struct vol *vol;
578     u_int16_t   vid;
579     u_int32_t   rmatches, reserved;
580     u_int32_t   catpos[4];
581     u_int32_t   pdid = 0;
582     char        *lname = NULL;
583     struct dir *dir;
584     int ret, rsize, i = 0;
585     u_int32_t nrecs = 0;
586     static int nrr = 1;
587     char *spec1, *spec2, *bspec1, *bspec2;
588
589     memset(&c1, 0, sizeof(c1));
590     memset(&c2, 0, sizeof(c2));
591
592     ibuf += 2;
593     memcpy(&vid, ibuf, sizeof(vid));
594     ibuf += sizeof(vid);
595
596     *rbuflen = 0;
597     if ((vol = getvolbyvid(vid)) == NULL)
598         return AFPERR_PARAM;
599
600     memcpy(&rmatches, ibuf, sizeof(rmatches));
601     rmatches = ntohl(rmatches);
602     ibuf += sizeof(rmatches); 
603
604     /* FIXME: (rl) should we check if reserved == 0 ? */
605     ibuf += sizeof(reserved);
606
607     memcpy(catpos, ibuf, sizeof(catpos));
608     ibuf += sizeof(catpos);
609
610     memcpy(&c1.fbitmap, ibuf, sizeof(c1.fbitmap));
611     c1.fbitmap = c2.fbitmap = ntohs(c1.fbitmap);
612     ibuf += sizeof(c1.fbitmap);
613
614     memcpy(&c1.dbitmap, ibuf, sizeof(c1.dbitmap));
615     c1.dbitmap = c2.dbitmap = ntohs(c1.dbitmap);
616     ibuf += sizeof(c1.dbitmap);
617
618     memcpy(&c1.rbitmap, ibuf, sizeof(c1.rbitmap));
619     c1.rbitmap = c2.rbitmap = ntohl(c1.rbitmap);
620     ibuf += sizeof(c1.rbitmap);
621
622     if (! (c1.fbitmap || c1.dbitmap)) {
623             *rbuflen = 0;
624             return AFPERR_BITMAP;
625     }
626
627     /* Parse file specifications */
628     spec1 = ibuf;
629     spec2 = ibuf + ibuf[0] + 2;
630
631     spec1 += 2; bspec1 = spec1;
632     spec2 += 2; bspec2 = spec2;
633
634     /* File attribute bits... */
635     if (c1.rbitmap & (1 << FILPBIT_ATTR)) {
636             memcpy(&c1.attr, ibuf, sizeof(c1.attr));
637             spec1 += sizeof(c1.attr);
638             c1.attr = ntohs(c1.attr);
639             memcpy(&c2.attr, ibuf, sizeof(c2.attr));
640             spec2 += sizeof(c1.attr);
641             c2.attr = ntohs(c2.attr);
642     }
643
644     /* Parent DID */
645     if (c1.rbitmap & (1 << FILPBIT_PDID)) {
646             memcpy(&c1.pdid, spec1, sizeof(pdid));
647             spec1 += sizeof(c1.pdid);
648             memcpy(&c2.pdid, spec2, sizeof(pdid));
649             spec2 += sizeof(c2.pdid);
650     } /* FIXME: PDID - do we demarshall this argument ? */
651
652     /* Creation date */
653     if (c1.rbitmap & (1 << FILPBIT_CDATE)) {
654             memcpy(&c1.cdate, spec1, sizeof(c1.cdate));
655             spec1 += sizeof(c1.cdate);
656             c1.cdate = AD_DATE_TO_UNIX(c1.cdate);
657             memcpy(&c2.cdate, spec2, sizeof(c2.cdate));
658             spec2 += sizeof(c1.cdate);
659             ibuf += sizeof(c1.cdate);;
660             c2.cdate = AD_DATE_TO_UNIX(c2.cdate);
661     }
662
663     /* Modification date */
664     if (c1.rbitmap & (1 << FILPBIT_MDATE)) {
665             memcpy(&c1.mdate, spec1, sizeof(c1.mdate));
666             c1.mdate = AD_DATE_TO_UNIX(c1.mdate);
667             spec1 += sizeof(c1.mdate);
668             memcpy(&c2.mdate, spec2, sizeof(c2.mdate));
669             c2.mdate = AD_DATE_TO_UNIX(c2.mdate);
670             spec2 += sizeof(c1.mdate);
671     }
672     
673     /* Backup date */
674     if (c1.rbitmap & (1 << FILPBIT_BDATE)) {
675             memcpy(&c1.bdate, spec1, sizeof(c1.bdate));
676             spec1 += sizeof(c1.bdate);
677             c1.bdate = AD_DATE_TO_UNIX(c1.bdate);
678             memcpy(&c2.bdate, spec2, sizeof(c2.bdate));
679             spec2 += sizeof(c2.bdate);
680             c1.bdate = AD_DATE_TO_UNIX(c2.bdate);
681     }
682
683     /* Finder info */
684     if (c1.rbitmap * (1 << FILPBIT_FINFO)) {
685             memcpy(&c1.finfo, spec1, sizeof(c1.finfo));
686             spec1 += sizeof(c1.finfo);
687             memcpy(&c2.finfo, spec2, sizeof(c2.finfo));
688             spec2 += sizeof(c2.finfo);
689     } /* Finder info */
690
691     if ((c1.rbitmap & (1 << DIRPBIT_OFFCNT)) != 0) {
692         /* Offspring count - only directories */
693         if (c1.fbitmap == 0) {
694             memcpy(&c1.offcnt, spec1, sizeof(c1.offcnt));
695             spec1 += sizeof(c1.offcnt);
696             c1.offcnt = ntohs(c1.offcnt);
697             memcpy(&c2.offcnt, spec2, sizeof(c2.offcnt));
698             spec2 += sizeof(c2.offcnt);
699             c2.offcnt = ntohs(c2.offcnt);
700         }
701         else if (c1.dbitmap == 0) {
702                 /* ressource fork length */
703         }
704         else {
705                 /* error */
706         }
707     } /* Offspring count/ressource fork length */
708
709     /* Long name */
710     if (c1.rbitmap & (1 << FILPBIT_LNAME)) {
711         /* Get the long filename */     
712         memcpy(c1.lname, bspec1 + spec1[1] + 1, (bspec1 + spec1[1])[0]);
713         c1.lname[(bspec1 + spec1[1])[0]]= 0;
714         for (i = 0; c1.lname[i] != 0; i++)
715                 c1.lname[i] = tolower(c1.lname[i]);
716         /* FIXME: do we need it ? It's always null ! */
717         memcpy(c2.lname, bspec2 + spec2[1] + 1, (bspec2 + spec2[1])[0]);
718         c2.lname[(bspec2 + spec2[1])[0]]= 0;
719         for (i = 0; c2.lname[i] != 0; i++)
720                 c2.lname[i] = tolower(c2.lname[i]);
721     }
722
723
724     /* Call search */
725     *rbuflen = 24;
726     ret = catsearch(vol, vol->v_dir, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize);
727     memcpy(rbuf, catpos, sizeof(catpos));
728     rbuf += sizeof(catpos);
729     c1.fbitmap = htons(c1.fbitmap);
730     memcpy(rbuf, &c1.fbitmap, sizeof(c1.fbitmap));
731     rbuf += sizeof(c1.fbitmap);
732     c1.dbitmap = htons(c1.dbitmap);
733     memcpy(rbuf, &c1.dbitmap, sizeof(c1.dbitmap));
734     rbuf += sizeof(c1.dbitmap);
735     nrecs = htonl(nrecs);
736     memcpy(rbuf, &nrecs, sizeof(nrecs));
737     rbuf += sizeof(nrecs);
738     *rbuflen += rsize;
739
740     return ret;
741 } /* afp_catsearch */
742
743 /* FIXME: we need a clean separation between afp stubs and 'real' implementation */
744 /* (so, all buffer packing/unpacking should be done in stub, everything else 
745    should be done in other functions) */