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