]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/catsearch.c
options need strdup, remove a syslog call
[netatalk.git] / etc / afpd / catsearch.c
index 6b9ef02d48bda296d7d1e8dec19bf77deeb2374f..207061e0cd2a653ddbdc928da1282d2e991edbb7 100644 (file)
 #include <stdlib.h>
 #include <dirent.h>
 #include <errno.h>
-#include <syslog.h>
 #include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
 
 #if STDC_HEADERS
 #include <string.h>
@@ -48,6 +50,7 @@
 #include <netatalk/endian.h>
 #include <atalk/afp.h>
 #include <atalk/adouble.h>
+#include <atalk/logger.h>
 #ifdef CNID_DB
 #include <atalk/cnid.h>
 #endif /* CNID_DB */
@@ -59,7 +62,6 @@
 #include "filedir.h"
 #include "fork.h"
 
-#ifdef WITH_CATSEARCH
 
 struct finderinfo {
        u_int32_t f_type;
@@ -96,7 +98,8 @@ struct scrit {
        u_int32_t pdid;             /* Parent DID */
         u_int16_t offcnt;           /* Offspring count */
        struct finderinfo finfo;    /* Finder info */
-       char lname[32];             /* Long name */
+       char lname[64];             /* Long name */ 
+       char utf8name[512];         /* UTF8 name */
 };
 
 /*
@@ -108,11 +111,12 @@ struct scrit {
  *
  */
 struct dsitem {
-       char *lname;     /* Long name */
+       char *m_name;    /* Mac name */
+       char *u_name;    /* unix name (== strrchr('/', path)) */
        struct dir *dir; /* Structure describing this directory */
        int pidx;        /* Parent's dsitem structure index. */
        int checked;     /* Have we checked this directory ? */
-       char *path;      /* UNIX path to this directory */
+       char *path;      /* absolute UNIX path to this directory */
 };
  
 
@@ -128,9 +132,10 @@ static int dsidx = 0;           /* First free item index... */
 static struct scrit c1, c2;          /* search criteria */
 
 /* Puts new item onto directory stack. */
-static int addstack(char *lname, struct dir *dir, int pidx)
+static int addstack(char *uname, char *mname, struct dir *dir, int pidx)
 {
        struct dsitem *ds;
+       int           l;
 
        /* check if we have some space on stack... */
        if (dsidx >= dssize) {
@@ -142,14 +147,18 @@ static int addstack(char *lname, struct dir *dir, int pidx)
 
        /* Put new element. Allocate and copy lname and path. */
        ds = dstack + dsidx++;
-       ds->lname = strdup(lname);
+       if (!(ds->m_name = strdup(mname)))
+               return -1;
        ds->dir = dir;
        ds->pidx = pidx;
        if (pidx >= 0) {
-               ds->path = malloc(strlen(dstack[pidx].path) + strlen(ds->lname) + 2);
+               l = strlen(dstack[pidx].path);
+               if (!(ds->path = malloc(l + strlen(uname) + 2) ))
+                       return -1;
                strcpy(ds->path, dstack[pidx].path);
                strcat(ds->path, "/");
-               strcat(ds->path, ds->lname);
+               strcat(ds->path, uname);
+               ds->u_name = ds->path +l +1;
        }
 
        ds->checked = 0;
@@ -170,12 +179,12 @@ static int reducestack()
        while (dsidx > 0) {
                if (dstack[dsidx-1].checked) {
                        dsidx--;
-                       free(dstack[dsidx].lname);
+                       free(dstack[dsidx].m_name);
                        free(dstack[dsidx].path);
                        /* Check if we need to free (or release) dir structures */
                } else
                        return dsidx - 1;
-       } // while
+       } 
        return -1;
 } /* reducestack() */
 
@@ -185,7 +194,7 @@ static void clearstack()
        save_cidx = -1;
        while (dsidx > 0) {
                dsidx--;
-               free(dstack[dsidx].lname);
+               free(dstack[dsidx].m_name);
                free(dstack[dsidx].path);
                /* Check if we need to free (or release) dir structures */
        }
@@ -194,9 +203,8 @@ static void clearstack()
 /* Fills in dir field of dstack[cidx]. Must fill parent dirs' fields if needed... */
 static int resolve_dir(struct vol *vol, int cidx)
 {
-       struct dir *dir, *curdir;
-       struct stat statbuf;
-
+       struct dir *dir, *cdir;
+       
        if (dstack[cidx].dir != NULL)
                return 1;
 
@@ -206,44 +214,51 @@ static int resolve_dir(struct vol *vol, int cidx)
        if (dstack[dstack[cidx].pidx].dir == NULL && resolve_dir(vol, dstack[cidx].pidx) == 0)
               return 0;
 
-       curdir = dstack[dstack[cidx].pidx].dir;
-       dir = curdir->d_child;
+       cdir = dstack[dstack[cidx].pidx].dir;
+       dir = cdir->d_child;
        while (dir) {
-               if (strcmp(dir->d_name, dstack[cidx].lname) == 0)
+               if (strcmp(dir->d_m_name, dstack[cidx].m_name) == 0)
                        break;
-               dir = (dir == curdir->d_child->d_prev) ? NULL : dir->d_next;
+               dir = (dir == cdir->d_child->d_prev) ? NULL : dir->d_next;
        } /* while */
 
-       if (!dir)
-               if (stat(dstack[cidx].path, &statbuf)==-1) {
-                       syslog(LOG_DEBUG, "resolve_dir: stat %s: %s", dstack[cidx].path, strerror(errno));
+       if (!dir) {
+               struct path path;
+
+               path.u_name = dstack[cidx].path;   
+               if (of_stat(&path)==-1) {
+                       LOG(log_debug, logtype_afpd, "resolve_dir: stat %s: %s", dstack[cidx].path, strerror(errno));
                        return 0;
                }
-
-       if (!dir && ((dir = adddir(vol, curdir, dstack[cidx].lname, strlen(dstack[cidx].lname),
-                                               dstack[cidx].path, strlen(dstack[cidx].path), &statbuf)) == NULL))
+               path.m_name = dstack[cidx].m_name;
+               path.u_name = dstack[cidx].u_name;   
+               /* adddir works with a filename not absolute pathname */
+               if ((dir = adddir(vol, cdir, &path)) == NULL)
                        return 0;
+       }
        dstack[cidx].dir = dir;
 
        return 1;
 } /* resolve_dir */
 
-/* Looks up for an opened adouble structure, opens resource fork of selected file. */
-static struct adouble *adl_lkup(char *upath, struct stat *sb)
+/* Looks up for an opened adouble structure, opens resource fork of selected file. 
+ * FIXME What about noadouble?
+*/
+static struct adouble *adl_lkup(struct vol *vol, struct path *path)
 {
        static struct adouble ad;
        struct adouble *adp;
        struct ofork *of;
-       int isdir = S_ISDIR(sb->st_mode);
+       int isdir = S_ISDIR(path->st.st_mode);
 
-       if (!isdir && (of = of_findname(upath, sb ))) {
+       if (!isdir && (of = of_findname(path))) {
                adp = of->of_ad;
        } else {
-               memset(&ad, 0, sizeof(ad));
+               ad_init(&ad, vol->v_adouble);
                adp = &ad;
        } 
 
-       if ( ad_open( upath, ADFLAGS_HF | (isdir)?ADFLAGS_DIR:0, O_RDONLY, 0, adp) < 0 ) {
+       if ( ad_open( path->u_name, ADFLAGS_HF | ((isdir)?ADFLAGS_DIR:0), O_RDONLY, 0, adp) < 0 ) {
                return NULL;
        } 
        return adp;     
@@ -257,18 +272,16 @@ static struct adouble *adl_lkup(char *upath, struct stat *sb)
  * fname - our fname (translated to UNIX)
  * cidx - index in directory stack
  */
-static int crit_check(struct vol *vol, char *uname, char *fname, int cidx) {
+static int crit_check(struct vol *vol, struct path *path, int cidx) {
        int r = 0;
-       struct stat sbuf;
-       u_int16_t attr;
-       struct finderinfo *finfo = NULL;
+       u_int16_t attr, flags = CONV_PRECOMPOSE;
+       struct finderinfo *finfo = NULL, finderinfo;
        struct adouble *adp = NULL;
        time_t c_date, b_date;
+       static char convbuf[512];
+       size_t len;
 
-       if (stat(uname, &sbuf) < 0)
-               return 0;
-       
-       if (S_ISDIR(sbuf.st_mode)) {
+       if (S_ISDIR(path->st.st_mode)) {
                r = 2;
                if (!c1.dbitmap)
                        return r;
@@ -279,17 +292,40 @@ static int crit_check(struct vol *vol, char *uname, char *fname, int cidx) {
        /* Kind of optimization: 
         * -- first check things we've already have - filename
         * -- last check things we get from ad_open()
+        * FIXME strmcp strstr (icase)
         */
 
        /* Check for filename */
        if (c1.rbitmap & (1<<DIRPBIT_LNAME)) { 
+#ifdef DEBUG
+               LOG(log_debug, logtype_afpd, "Crit check: comparing %s/%s to %s", path->m_name, path->u_name, c1.lname);
+#endif
+               if ( (size_t)(-1) == (len = convert_string(vol->v_maccharset, CH_UCS2, path->m_name, strlen(path->m_name), convbuf, 512)) )
+                       goto crit_check_ret;
+               convbuf[len] = 0; 
                if (c1.rbitmap & (1<<CATPBIT_PARTIAL)) {
-                       if (strstr(fname, c1.lname) == NULL)
+                       if (strcasestr_w( (ucs2_t*) convbuf, (ucs2_t*) c1.lname) == NULL)
                                goto crit_check_ret;
                } else
-                       if (strcmp(fname, c1.lname) != 0)
+                       if (strcasecmp_w((ucs2_t*) convbuf, (ucs2_t*) c1.lname) != 0)
                                goto crit_check_ret;
        } /* if (c1.rbitmap & ... */
+       
+       if ((c1.rbitmap & (1<<FILPBIT_PDINFO))) { 
+#ifdef DEBUG
+               LOG(log_debug, logtype_afpd, "Crit check: comparing %s to %s", path->m_name, c1.utf8name);
+#endif
+               if ( (size_t)(-1) == (len = convert_charset( CH_UTF8_MAC, CH_UCS2, CH_UTF8, path->m_name, strlen(path->m_name), convbuf, 512, &flags)) )
+                       goto crit_check_ret;
+               convbuf[len] = 0; 
+               if (c1.rbitmap & (1<<CATPBIT_PARTIAL)) {
+                       if (strcasestr_w((ucs2_t *) convbuf, (ucs2_t*)c1.utf8name) == NULL)
+                               goto crit_check_ret;
+               } else
+                       if (strcasecmp_w((ucs2_t *)convbuf, (ucs2_t*)c1.utf8name) != 0)
+                               goto crit_check_ret;
+       } /* if (c1.rbitmap & ... */
+
 
 
        /* FIXME */
@@ -302,72 +338,84 @@ static int crit_check(struct vol *vol, char *uname, char *fname, int cidx) {
 
        /* Check for modification date FIXME: should we look at adouble structure ? */
        if ((c1.rbitmap & (1<<DIRPBIT_MDATE))) 
-               if (sbuf.st_mtime < c1.mdate || sbuf.st_mtime > c2.mdate)
+               if (path->st.st_mtime < c1.mdate || path->st.st_mtime > c2.mdate)
                        goto crit_check_ret;
 
        /* Check for creation date... */
        if (c1.rbitmap & (1<<DIRPBIT_CDATE)) {
-               if (adp || (adp = adl_lkup(uname, &sbuf))) {
+               if (adp || (adp = adl_lkup(vol, path))) {
                        if (ad_getdate(adp, AD_DATE_CREATE, (u_int32_t*)&c_date) >= 0)
                                c_date = AD_DATE_TO_UNIX(c_date);
-                       else c_date = sbuf.st_mtime;
-               } else c_date = sbuf.st_mtime;
+                       else c_date = path->st.st_mtime;
+               } else c_date = path->st.st_mtime;
                if (c_date < c1.cdate || c_date > c2.cdate)
                        goto crit_check_ret;
        }
 
        /* Check for backup date... */
        if (c1.rbitmap & (1<<DIRPBIT_BDATE)) {
-               if (adp || (adp == adl_lkup(uname, &sbuf))) {
+               if (adp || (adp == adl_lkup(vol, path))) {
                        if (ad_getdate(adp, AD_DATE_BACKUP, (u_int32_t*)&b_date) >= 0)
                                b_date = AD_DATE_TO_UNIX(b_date);
-                       else b_date = sbuf.st_mtime;
-               } else b_date = sbuf.st_mtime;
+                       else b_date = path->st.st_mtime;
+               } else b_date = path->st.st_mtime;
                if (b_date < c1.bdate || b_date > c2.bdate)
                        goto crit_check_ret;
        }
                                
        /* Check attributes */
-       if ((c1.rbitmap & (1<<DIRPBIT_ATTR)) && c2.attr != 0)
-               if (adp || (adp = adl_lkup(uname, &sbuf))) {
+       if ((c1.rbitmap & (1<<DIRPBIT_ATTR)) && c2.attr != 0) {
+               if (adp || (adp = adl_lkup(vol, path))) {
                        ad_getattr(adp, &attr);
                        if ((attr & c2.attr) != c1.attr)
                                goto crit_check_ret;
                } else goto crit_check_ret;
-               
+       }               
 
         /* Check file type ID */
-       if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.f_type != 0)
-               if (adp || (adp = adl_lkup(uname, &sbuf))) {
-                       finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
-                       if (finfo->f_type != c1.finfo.f_type)
-                               goto crit_check_ret;
-               } else goto crit_check_ret;
-
-       /* Check creator ID */
-       if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.creator != 0)
-               if (adp || (adp = adl_lkup(uname, &sbuf))) {
-                       finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
-                       if (finfo->creator != c1.finfo.creator)
-                               goto crit_check_ret;
-               } else goto crit_check_ret;
+       if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.f_type != 0) {
+               if (!adp)
+                       adp = adl_lkup(vol, path);
+               finfo = get_finderinfo(path->m_name, adp, &finderinfo);
+               if (finfo->f_type != c1.finfo.f_type)
+                       goto crit_check_ret;
+       }
        
+       /* Check creator ID */
+       if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.creator != 0) {
+               if (!finfo) {
+                       if (!adp)
+                               adp = adl_lkup(vol, path);
+                       finfo = get_finderinfo(path->m_name, adp, &finderinfo);
+               }
+               if (finfo->creator != c1.finfo.creator)
+                       goto crit_check_ret;
+       }
+               
        /* Check finder info attributes */
-       if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.attrs != 0)
-               if (adp || (adp = adl_lkup(uname, &sbuf))) {
+       if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.attrs != 0) {
+               u_int8_t attrs = 0;
+
+               if (adp || (adp = adl_lkup(vol, path))) {
                        finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
-                       if ((finfo->attrs & c2.finfo.attrs) != c1.finfo.attrs)
-                               goto crit_check_ret;
-               } else goto crit_check_ret;
+                       attrs = finfo->attrs;
+               }
+               else if (*path->u_name == '.') {
+                       attrs = htons(FINDERINFO_INVISIBLE);
+               }
 
+               if ((attrs & c2.finfo.attrs) != c1.finfo.attrs)
+                       goto crit_check_ret;
+       }
+       
        /* Check label */
-       if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.label != 0)
-               if (adp || (adp = adl_lkup(uname, &sbuf))) {
+       if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.label != 0) {
+               if (adp || (adp = adl_lkup(vol, path))) {
                        finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
                        if ((finfo->label & c2.finfo.label) != c1.finfo.label)
                                goto crit_check_ret;
                } else goto crit_check_ret;
-       
+       }       
        /* FIXME: Attributes check ! */
        
        /* All criteria are met. */
@@ -380,7 +428,7 @@ crit_check_ret:
 
 
 /* Adds an item to resultset. */
-static int rslt_add(struct vol *vol, struct stat *statbuf, char *fname, short cidx, int isdir, char **rbuf)
+static int rslt_add(struct vol *vol, char *fname, short cidx, int isdir, char **rbuf)
 {
        char *p = *rbuf;
        int l = fname != NULL ? strlen(fname) : 0;
@@ -402,7 +450,8 @@ static int rslt_add(struct vol *vol, struct stat *statbuf, char *fname, short ci
        /* Fill offset of returned file name */
        if (fname != NULL) {
                *p++ = 0;
-               *p++ = (int)(p - *rbuf) - 1;
+               *p = (int)(p - *rbuf) - 1;
+               p++;
                p[0] = l;
                strcpy(p+1, fname);
                p += l + 1;
@@ -416,6 +465,57 @@ static int rslt_add(struct vol *vol, struct stat *statbuf, char *fname, short ci
        return 1;
 } /* rslt_add */
 
+static int rslt_add_ext ( struct vol *vol, struct path *path, char **buf, short cidx)
+{
+
+       char            *p = *buf;
+       int             ret, tbuf =0;
+       u_int16_t       resultsize;
+       int             isdir = S_ISDIR(path->st.st_mode); 
+
+       if (dstack[cidx].dir == NULL && resolve_dir(vol, cidx) == 0)
+               return 0;
+
+       p += sizeof(resultsize); /* Skip resultsize */
+       *p++ = isdir ? FILDIRBIT_ISDIR : FILDIRBIT_ISFILE;    /* IsDir ? */
+       *p++ = 0;                  /* Pad */
+       
+       if ( isdir )
+       {
+               struct dir* dir = NULL;
+
+               dir = dirsearch_byname(dstack[cidx].dir, path->u_name);
+               if (!dir) {
+                       if ((dir = adddir( vol, dstack[cidx].dir, path)) == NULL) {
+                               return 0;
+                       }
+               }
+               ret = getdirparams(vol, c1.dbitmap, path, dir, p , &tbuf ); 
+       }
+       else
+       {
+               ret = getfilparams ( vol, c1.fbitmap, path, dstack[cidx].dir, p, &tbuf);
+       }
+
+       if ( ret != AFP_OK )
+               return 0;
+
+       /* Make sure entry length is even */
+       if (tbuf & 1) {
+          *p++ = 0;
+          tbuf++;
+       }
+
+       resultsize = htons(tbuf);
+       memcpy ( *buf, &resultsize, sizeof(resultsize) );
+       
+       *buf += tbuf + 4;
+
+       return 1;
+} /* rslr_add_ext */
+       
+       
+
 #define VETO_STR \
         "./../.AppleDouble/.AppleDB/Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/.AppleDesktop/.Parent/"
 
@@ -427,41 +527,46 @@ static int rslt_add(struct vol *vol, struct stat *statbuf, char *fname, short ci
  * pos - position we've stopped recently
  * rbuf - output buffer
  * rbuflen - output buffer length
-*/
+ */
+#define NUM_ROUNDS 100
 static int catsearch(struct vol *vol, struct dir *dir,  
-                    int rmatches, int *pos, char *rbuf, u_int32_t *nrecs, int *rsize)
+                    int rmatches, int *pos, char *rbuf, u_int32_t *nrecs, int *rsize, int ext)
 {
-       int cidx, r, i;
+       int cidx, r;
        char *fname = NULL;
        struct dirent *entry;
-       struct stat statbuf;
        int result = AFP_OK;
        int ccr;
+        struct path path;
        char *orig_dir = NULL;
        int orig_dir_len = 128;
-       char *path = vol->v_path;
+       char *vpath = vol->v_path;
        char *rrbuf = rbuf;
-
+        time_t start_time;
+        int num_rounds = NUM_ROUNDS;
+        
        if (*pos != 0 && *pos != cur_pos) 
                return AFPERR_CATCHNG;
 
        /* FIXME: Category "offspring count ! */
 
        /* So we are beginning... */
+        start_time = time(NULL);
+
        /* We need to initialize all mandatory structures/variables and change working directory appropriate... */
        if (*pos == 0) {
                clearstack();
                if (dirpos != NULL) {
                        closedir(dirpos);
                        dirpos = NULL;
-               } /* if (dirpos != NULL) */
+               } 
                
-               if (addstack("", dir, -1) == -1) {
+               if (addstack("","", dir, -1) == -1) {
                        result = AFPERR_MISC;
                        goto catsearch_end;
                }
-               dstack[0].path = strdup(path);
-               /* FIXME: Sometimes DID is given by klient ! (correct this one above !) */
+               dstack[0].path = strdup(vpath);
+               /* FIXME: Sometimes DID is given by client ! (correct this one above !) */
        }
 
        /* Save current path */
@@ -498,9 +603,20 @@ static int catsearch(struct vol *vol, struct dir *dir,
                chdir(dstack[cidx].path);
                while ((entry=readdir(dirpos)) != NULL) {
                        (*pos)++;
-                       if (veto_file(VETO_STR, entry->d_name))
-                               continue;
-                       if (stat(entry->d_name, &statbuf) != 0) {
+
+                       if (!(fname = path.m_name = check_dirent(vol, entry->d_name)))
+                          continue;
+
+                       if (NULL == (fname = path.m_name = utompath(vol, entry->d_name, 0, utf8_encoding())))
+                          continue;
+
+                      /* now check against too big a file */
+                       if (strlen(path.m_name) > vol->max_filename)
+                          continue;
+
+
+                       path.u_name = entry->d_name;
+                       if (of_stat(&path) != 0) {
                                switch (errno) {
                                case EACCES:
                                case ELOOP:
@@ -514,21 +630,35 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                        result = AFPERR_MISC;
                                        goto catsearch_end;
                                } /* switch (errno) */
-                       } /* if (stat(entry->d_name, &statbuf) != 0) */
-                       fname = utompath(vol, entry->d_name);
+                       } /* if (stat(entry->d_name, &path.st) != 0) */
+#if 0
                        for (i = 0; fname[i] != 0; i++)
                                fname[i] = tolower(fname[i]);
-                       if (strlen(fname) > MACFILELEN) 
-                               continue;
-                       ccr = crit_check(vol, entry->d_name, fname, cidx);
-                       /* bit 0 means that criteria has ben met */
+#endif
+                       ccr = crit_check(vol, &path, cidx);
+                       /* bit 1 means that we have to descend into this directory. */
+                       if ((ccr & 2) && S_ISDIR(path.st.st_mode)) {
+                               if (addstack(entry->d_name, fname, NULL, cidx) == -1) {
+                                       result = AFPERR_MISC;
+                                       goto catsearch_end;
+                               } 
+                       }
+
+                       /* bit 0 means that criteria has been met */
                        if (ccr & 1) {
-                               r = rslt_add(vol, &statbuf, 
-                                            (c1.fbitmap&(1<<FILPBIT_LNAME))|(c1.dbitmap&(1<<DIRPBIT_LNAME)) ? 
-                                                utompath(vol, entry->d_name) : NULL,   
-                                            (c1.fbitmap&(1<<FILPBIT_PDID))|(c1.dbitmap&(1<<DIRPBIT_PDID)) ? 
-                                                cidx : -1, 
-                                            S_ISDIR(statbuf.st_mode), &rrbuf); 
+                               if ( ext ) { 
+                                       r = rslt_add_ext ( vol, &path, &rrbuf, cidx);
+                               }
+                               else
+                               {
+                                       r = rslt_add(vol,  
+                                                    (c1.fbitmap&(1<<FILPBIT_LNAME))|(c1.dbitmap&(1<<DIRPBIT_LNAME)) ? 
+                                                        fname : NULL,  
+                                                    (c1.fbitmap&(1<<FILPBIT_PDID))|(c1.dbitmap&(1<<DIRPBIT_PDID)) ? 
+                                                        cidx : -1, 
+                                                    S_ISDIR(path.st.st_mode), &rrbuf); 
+                               }
+                               
                                if (r == 0) {
                                        result = AFPERR_MISC;
                                        goto catsearch_end;
@@ -536,22 +666,22 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                *nrecs += r;
                                /* Number of matches limit */
                                if (--rmatches == 0) 
-                                       goto catsearch_pause; /* FIXME: timelimit checks ! */
+                                       goto catsearch_pause;
                                /* Block size limit */
                                if (rrbuf - rbuf >= 448)
                                        goto catsearch_pause;
-
-                       } 
-                       /* bit 1 means that we have to descend into this directory. */
-                       if (ccr & 2) {
-                               if (S_ISDIR(statbuf.st_mode))
-                                       if (addstack(entry->d_name, NULL, cidx) == -1) {
-                                               result = AFPERR_MISC;
-                                               goto catsearch_end;
-                                       } /* if (addstack... */
+                       }
+                        /* MacOS 9 doesn't like servers executing commands longer than few seconds */
+                       if (--num_rounds <= 0) {
+                           if (start_time != time(NULL)) {
+                               result=AFP_OK;
+                               goto catsearch_pause;
+                           }
+                           num_rounds = NUM_ROUNDS;
                        }
                } /* while ((entry=readdir(dirpos)) != NULL) */
-               closedir(dirpos);dirpos = NULL;
+               closedir(dirpos);
+               dirpos = NULL;
                dstack[cidx].checked = 1;
        } /* while (current_idx = reducestack()) != -1) */
 
@@ -572,21 +702,22 @@ catsearch_end: /* Exiting catsearch: error condition */
        return result;
 } /* catsearch() */
 
-
-int afp_catsearch(AFPObj *obj, char *ibuf, int ibuflen,
-                  char *rbuf, int *rbuflen)
+int catsearch_afp(AFPObj *obj, char *ibuf, int ibuflen,
+                  char *rbuf, int *rbuflen, int ext)
 {
     struct vol *vol;
     u_int16_t   vid;
+    u_int16_t   spec_len;
     u_int32_t   rmatches, reserved;
     u_int32_t  catpos[4];
     u_int32_t   pdid = 0;
-    char        *lname = NULL;
-    struct dir *dir;
-    int ret, rsize, i = 0;
+    int ret, rsize;
     u_int32_t nrecs = 0;
-    static int nrr = 1;
-    char *spec1, *spec2, *bspec1, *bspec2;
+    unsigned char *spec1, *spec2, *bspec1, *bspec2;
+    size_t     len;
+    u_int16_t  namelen;
+    u_int16_t  flags;
+    char       tmppath[256];
 
     memset(&c1, 0, sizeof(c1));
     memset(&c2, 0, sizeof(c2));
@@ -596,9 +727,10 @@ int afp_catsearch(AFPObj *obj, char *ibuf, int ibuflen,
     ibuf += sizeof(vid);
 
     *rbuflen = 0;
-    if ((vol = getvolbyvid(vid)) == NULL)
+    if ((vol = getvolbyvid(vid)) == NULL) {
         return AFPERR_PARAM;
-
+    }
+    
     memcpy(&rmatches, ibuf, sizeof(rmatches));
     rmatches = ntohl(rmatches);
     ibuf += sizeof(rmatches); 
@@ -622,25 +754,32 @@ int afp_catsearch(AFPObj *obj, char *ibuf, int ibuflen,
     ibuf += sizeof(c1.rbitmap);
 
     if (! (c1.fbitmap || c1.dbitmap)) {
-           *rbuflen = 0;
            return AFPERR_BITMAP;
     }
 
+    if ( ext) {
+        memcpy(&spec_len, ibuf, sizeof(spec_len));
+        spec_len = ntohs(spec_len);
+    }
+    else {
+        spec_len = *(unsigned char*)ibuf;
+    }
+
     /* Parse file specifications */
     spec1 = ibuf;
-    spec2 = ibuf + ibuf[0] + 2;
+    spec2 = ibuf + spec_len + 2;
 
-    spec1 += 2; bspec1 = spec1;
-    spec2 += 2; bspec2 = spec2;
+    spec1 += 2; 
+    spec2 += 2; 
 
+    bspec1 = spec1;
+    bspec2 = spec2;
     /* File attribute bits... */
     if (c1.rbitmap & (1 << FILPBIT_ATTR)) {
-           memcpy(&c1.attr, ibuf, sizeof(c1.attr));
+           memcpy(&c1.attr, spec1, sizeof(c1.attr));
            spec1 += sizeof(c1.attr);
-           c1.attr = ntohs(c1.attr);
-           memcpy(&c2.attr, ibuf, sizeof(c2.attr));
+           memcpy(&c2.attr, spec2, sizeof(c2.attr));
            spec2 += sizeof(c1.attr);
-           c2.attr = ntohs(c2.attr);
     }
 
     /* Parent DID */
@@ -683,7 +822,7 @@ int afp_catsearch(AFPObj *obj, char *ibuf, int ibuflen,
     }
 
     /* Finder info */
-    if (c1.rbitmap * (1 << FILPBIT_FINFO)) {
+    if (c1.rbitmap & (1 << FILPBIT_FINFO)) {
            memcpy(&c1.finfo, spec1, sizeof(c1.finfo));
            spec1 += sizeof(c1.finfo);
            memcpy(&c2.finfo, spec2, sizeof(c2.finfo));
@@ -704,47 +843,87 @@ int afp_catsearch(AFPObj *obj, char *ibuf, int ibuflen,
                /* ressource fork length */
        }
        else {
-               /* error */
+           return AFPERR_BITMAP;  /* error */
        }
     } /* Offspring count/ressource fork length */
 
     /* Long name */
     if (c1.rbitmap & (1 << FILPBIT_LNAME)) {
         /* Get the long filename */    
-       memcpy(c1.lname, bspec1 + spec1[1] + 1, (bspec1 + spec1[1])[0]);
-       c1.lname[(bspec1 + spec1[1])[0]]= 0;
-       for (i = 0; c1.lname[i] != 0; i++)
-               c1.lname[i] = tolower(c1.lname[i]);
+       memcpy(tmppath, bspec1 + spec1[1] + 1, (bspec1 + spec1[1])[0]);
+       tmppath[(bspec1 + spec1[1])[0]]= 0;
+       len = convert_string ( vol->v_maccharset, CH_UCS2, tmppath, strlen(tmppath), c1.lname, 64);
+        if (len == (size_t)(-1))
+            return AFPERR_PARAM;
+       c1.lname[len] = 0;
+
+#if 0  
        /* FIXME: do we need it ? It's always null ! */
        memcpy(c2.lname, bspec2 + spec2[1] + 1, (bspec2 + spec2[1])[0]);
        c2.lname[(bspec2 + spec2[1])[0]]= 0;
-       for (i = 0; c2.lname[i] != 0; i++)
-               c2.lname[i] = tolower(c2.lname[i]);
+#endif
     }
-
-
+        /* UTF8 Name */
+    if (c1.rbitmap & (1 << FILPBIT_PDINFO)) {
+
+       /* offset */
+       memcpy(&namelen, spec1, sizeof(namelen));
+       namelen = ntohs (namelen);
+
+       spec1 = bspec1+namelen+4; /* Skip Unicode Hint */
+
+       /* length */
+       memcpy(&namelen, spec1, sizeof(namelen));
+       namelen = ntohs (namelen);
+       if (namelen > 255)  /* Safeguard */
+               namelen = 255;
+
+       memcpy (c1.utf8name, spec1+2, namelen);
+       c1.utf8name[(namelen+1)] =0;
+
+       /* convert charset */
+       flags = CONV_PRECOMPOSE;
+       len = convert_charset(CH_UTF8_MAC, CH_UCS2, CH_UTF8, c1.utf8name, namelen, c1.utf8name, 512, &flags);
+        if (len == (size_t)(-1))
+            return AFPERR_PARAM;
+       c1.utf8name[len]=0;
+    }
+    
     /* Call search */
     *rbuflen = 24;
-    ret = catsearch(vol, vol->v_dir, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize);
+    ret = catsearch(vol, vol->v_dir, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
     memcpy(rbuf, catpos, sizeof(catpos));
     rbuf += sizeof(catpos);
+
     c1.fbitmap = htons(c1.fbitmap);
     memcpy(rbuf, &c1.fbitmap, sizeof(c1.fbitmap));
     rbuf += sizeof(c1.fbitmap);
+
     c1.dbitmap = htons(c1.dbitmap);
     memcpy(rbuf, &c1.dbitmap, sizeof(c1.dbitmap));
     rbuf += sizeof(c1.dbitmap);
+
     nrecs = htonl(nrecs);
     memcpy(rbuf, &nrecs, sizeof(nrecs));
     rbuf += sizeof(nrecs);
     *rbuflen += rsize;
 
     return ret;
-} /* afp_catsearch */
+} /* catsearch_afp */
+
+int afp_catsearch (AFPObj *obj, char *ibuf, int ibuflen,
+                  char *rbuf, int *rbuflen)
+{
+       return catsearch_afp( obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
+
+
+int afp_catsearch_ext (AFPObj *obj, char *ibuf, int ibuflen,
+                  char *rbuf, int *rbuflen)
+{
+       return catsearch_afp( obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
 
 /* FIXME: we need a clean separation between afp stubs and 'real' implementation */
 /* (so, all buffer packing/unpacking should be done in stub, everything else 
    should be done in other functions) */
-
-#endif
-/* WITH_CATSEARCH */