]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/catsearch.c
Merge from branch-2-1
[netatalk.git] / etc / afpd / catsearch.c
index 1197ecd9eca6d574136876348771fae212233977..70c93f15207a1ff7d48e2fdeb93fd91ba8a89947 100644 (file)
 #ifdef CNID_DB
 #include <atalk/cnid.h>
 #endif /* CNID_DB */
+
+#include <atalk/util.h>
+#include <atalk/bstradd.h>
+
 #include "desktop.h"
 #include "directory.h"
+#include "dircache.h"
 #include "file.h"
 #include "volume.h"
 #include "globals.h"
@@ -117,8 +122,6 @@ struct dsitem {
  
 
 #define DS_BSIZE 128
-static u_int32_t cur_pos = 0;    /* Saved position index (ID) - used to remember "position" across FPCatSearch calls */
-static DIR *dirpos = NULL; /* UNIX structure describing currently opened directory. */
 static int save_cidx = -1; /* Saved index of currently scanned directory. */
 
 static struct dsitem *dstack = NULL; /* Directory stack data... */
@@ -144,6 +147,7 @@ static int addstack(char *uname, struct dir *dir, int pidx)
        /* Put new element. Allocate and copy lname and path. */
        ds = dstack + dsidx++;
        ds->dir = dir;
+    dir->d_flags |= DIRF_CACHELOCK;
        ds->pidx = pidx;
        ds->checked = 0;
        if (pidx >= 0) {
@@ -176,6 +180,7 @@ static int reducestack(void)
        while (dsidx > 0) {
                if (dstack[dsidx-1].checked) {
                        dsidx--;
+            dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
                        free(dstack[dsidx].path);
                } else
                        return dsidx - 1;
@@ -189,6 +194,7 @@ static void clearstack(void)
        save_cidx = -1;
        while (dsidx > 0) {
                dsidx--;
+        dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
                free(dstack[dsidx].path);
        }
 } 
@@ -215,7 +221,7 @@ static struct adouble *adl_lkup(struct vol *vol, struct path *path, struct adoub
                adp = &ad;
        } 
 
-    if ( ad_metadata( path->u_name, ((isdir)?ADFLAGS_DIR:0), adp) < 0 ) {
+    if ( ad_metadata( path->u_name, ((isdir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
         adp = NULL; /* FIXME without resource fork adl_lkup will be call again */
     }
     
@@ -237,13 +243,13 @@ static struct finderinfo *unpack_buffer(struct finderinfo *finfo, char *buffer)
 
 /* -------------------- */
 static struct finderinfo *
-unpack_finderinfo(struct vol *vol, struct path *path, struct adouble **adp, struct finderinfo *finfo)
+unpack_finderinfo(struct vol *vol, struct path *path, struct adouble **adp, struct finderinfo *finfo, int islnk)
 {
        packed_finder  buf;
        void           *ptr;
        
     *adp = adl_lkup(vol, path, *adp);
-       ptr = get_finderinfo(vol, path->u_name, *adp, &buf);
+       ptr = get_finderinfo(vol, path->u_name, *adp, &buf,islnk);
        return unpack_buffer(finfo, ptr);
 }
 
@@ -265,6 +271,8 @@ static int crit_check(struct vol *vol, struct path *path) {
        u_int32_t ac_date, ab_date;
        static char convbuf[514]; /* for convert_charset dest_len parameter +2 */
        size_t len;
+    int islnk;
+    islnk=S_ISLNK(path->st.st_mode);
 
        if (S_ISDIR(path->st.st_mode)) {
                if (!c1.dbitmap)
@@ -379,7 +387,7 @@ static int crit_check(struct vol *vol, struct path *path) {
 
         /* Check file type ID */
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.f_type != 0) {
-           finfo = unpack_finderinfo(vol, path, &adp, &finderinfo);
+           finfo = unpack_finderinfo(vol, path, &adp, &finderinfo,islnk);
                if (finfo->f_type != c1.finfo.f_type)
                        goto crit_check_ret;
        }
@@ -387,7 +395,7 @@ static int crit_check(struct vol *vol, struct path *path) {
        /* Check creator ID */
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.creator != 0) {
                if (!finfo) {
-                       finfo = unpack_finderinfo(vol, path, &adp, &finderinfo);
+                       finfo = unpack_finderinfo(vol, path, &adp, &finderinfo,islnk);
                }
                if (finfo->creator != c1.finfo.creator)
                        goto crit_check_ret;
@@ -396,7 +404,7 @@ static int crit_check(struct vol *vol, struct path *path) {
        /* Check finder info attributes */
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.attrs != 0) {
                if (!finfo) {
-                       finfo = unpack_finderinfo(vol, path, &adp, &finderinfo);
+                       finfo = unpack_finderinfo(vol, path, &adp, &finderinfo,islnk);
                }
 
                if ((finfo->attrs & c2.finfo.attrs) != c1.finfo.attrs)
@@ -406,7 +414,7 @@ static int crit_check(struct vol *vol, struct path *path) {
        /* Check label */
        if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.label != 0) {
                if (!finfo) {
-                       finfo = unpack_finderinfo(vol, path, &adp, &finderinfo);
+                       finfo = unpack_finderinfo(vol, path, &adp, &finderinfo,islnk);
                }
                if ((finfo->label & c2.finfo.label) != c1.finfo.label)
                        goto crit_check_ret;
@@ -490,18 +498,19 @@ static int rslt_add ( struct vol *vol, struct path *path, char **buf, int ext)
 static int catsearch(struct vol *vol, struct dir *dir,  
                     int rmatches, u_int32_t *pos, char *rbuf, u_int32_t *nrecs, int *rsize, int ext)
 {
+    static u_int32_t cur_pos;    /* Saved position index (ID) - used to remember "position" across FPCatSearch calls */
+    static DIR *dirpos;                 /* UNIX structure describing currently opened directory. */
        int cidx, r;
        struct dirent *entry;
        int result = AFP_OK;
        int ccr;
     struct path path;
-       char *orig_dir = NULL;
-       int orig_dir_len = 128;
        char *vpath = vol->v_path;
        char *rrbuf = rbuf;
     time_t start_time;
     int num_rounds = NUM_ROUNDS;
-    int cached;
+    int cwd = -1;
+    int error;
         
        if (*pos != 0 && *pos != cur_pos) {
                result = AFPERR_CATCHNG;
@@ -510,8 +519,6 @@ static int catsearch(struct vol *vol, struct dir *dir,
 
        /* 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) {
@@ -529,23 +536,24 @@ static int catsearch(struct vol *vol, struct dir *dir,
        }
 
        /* Save current path */
-       orig_dir = (char*)malloc(orig_dir_len);
-       while (getcwd(orig_dir, orig_dir_len-1)==NULL) {
-               if (errno != ERANGE) {
-                       result = AFPERR_MISC;
-                       goto catsearch_end;
-               }
-               orig_dir_len += 128; 
-               orig_dir = realloc(orig_dir, orig_dir_len);
-       } /* while() */
+    if ((cwd = open(".", O_RDONLY)) < 0) {
+        result = AFPERR_MISC;
+        goto catsearch_end;
+    }
        
+       /* So we are beginning... */
+    start_time = time(NULL);
+
        while ((cidx = reducestack()) != -1) {
-               cached = 1;
-               if (dirpos == NULL) {
+               error = lchdir(dstack[cidx].path);
+
+               if (!error && dirpos == NULL)
+                       dirpos = opendir(".");
+
+               if (dirpos == NULL)
                        dirpos = opendir(dstack[cidx].path);
-                       cached = (dstack[cidx].dir->d_child != NULL);
-               }
-               if (dirpos == NULL) {
+
+               if (error || dirpos == NULL) {
                        switch (errno) {
                        case EACCES:
                                dstack[cidx].checked = 1;
@@ -562,10 +570,7 @@ static int catsearch(struct vol *vol, struct dir *dir,
                        } /* switch (errno) */
                        goto catsearch_end;
                }
-               /* FIXME error in chdir, what do we do? */
-               chdir(dstack[cidx].path);
                
-
                while ((entry=readdir(dirpos)) != NULL) {
                        (*pos)++;
 
@@ -594,18 +599,16 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                   ie if in the same loop the parent dir wasn't in the cache
                                   ALL dirsearch_byname will fail.
                                */
-                               if (cached)
-                       path.d_dir = dirsearch_byname(vol, dstack[cidx].dir, path.u_name);
-               else
-                       path.d_dir = NULL;
-               if (!path.d_dir) {
+                int unlen = strlen(path.u_name);
+                path.d_dir = dircache_search_by_name(vol, dstack[cidx].dir, path.u_name, unlen, path.st.st_ctime);
+               if (path.d_dir == NULL) {
                        /* path.m_name is set by adddir */
-                   if (NULL == (path.d_dir = adddir( vol, dstack[cidx].dir, &path) ) ) {
+                   if (NULL == (path.d_dir = dir_add( vol, dstack[cidx].dir, &path, unlen) ) ) {
                                                result = AFPERR_MISC;
                                                goto catsearch_end;
                                        }
                 }
-                path.m_name = path.d_dir->d_m_name; 
+                path.m_name = cfrombstr(path.d_dir->d_m_name);
                        
                                if (addstack(path.u_name, path.d_dir, cidx) == -1) {
                                        result = AFPERR_MISC;
@@ -658,10 +661,12 @@ catsearch_pause:
 
 catsearch_end: /* Exiting catsearch: error condition */
        *rsize = rrbuf - rbuf;
-       if (orig_dir != NULL) {
-               chdir(orig_dir);
-               free(orig_dir);
-       }
+    if (cwd != -1) {
+        if ((fchdir(cwd)) != 0) {
+            LOG(log_debug, logtype_afpd, "error chdiring back: %s", strerror(errno));        
+        }
+        close(cwd);
+    }
        return result;
 } /* catsearch() */
 
@@ -867,7 +872,7 @@ static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
     
     /* Call search */
     *rbuflen = 24;
-    ret = catsearch(vol, vol->v_dir, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
+    ret = catsearch(vol, vol->v_root, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
     memcpy(rbuf, catpos, sizeof(catpos));
     rbuf += sizeof(catpos);