]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/catsearch.c
Configurable symlink behaviour
[netatalk.git] / etc / afpd / catsearch.c
index a488501e6b67e3c101660b844aa218bb460a1da5..f1f55ef96d7a3ed2cea6823d317f1abcb014d180 100644 (file)
@@ -29,6 +29,9 @@
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -108,57 +111,50 @@ struct scrit {
  *
  */
 struct dsitem {
-//     struct dir *dir; /* Structure describing this directory */
-//  cnid_t did;      /* CNID of this directory           */
-       int pidx;        /* Parent's dsitem structure index. */
-       int checked;     /* Have we checked this directory ? */
-       int path_len;
-       char *path;      /* absolute UNIX path to this directory */
+    cnid_t ds_did;         /* CNID of this directory           */
+    int    ds_checked;     /* Have we checked this directory ? */
 };
  
 
 #define DS_BSIZE 128
 static int save_cidx = -1; /* Saved index of currently scanned directory. */
-
 static struct dsitem *dstack = NULL; /* Directory stack data... */
 static int dssize = 0;              /* Directory stack (allocated) size... */
 static int dsidx = 0;               /* First free item index... */
-
 static struct scrit c1, c2;          /* search criteria */
 
+/* Clears directory stack. */
+static void clearstack(void) 
+{
+       save_cidx = -1;
+       while (dsidx > 0) {
+               dsidx--;
+       }
+}
+
 /* Puts new item onto directory stack. */
 static int addstack(char *uname, struct dir *dir, int pidx)
 {
        struct dsitem *ds;
        size_t         l, u;
+    struct dsitem *tmpds = NULL;
 
        /* check if we have some space on stack... */
        if (dsidx >= dssize) {
                dssize += DS_BSIZE;
-               dstack = realloc(dstack, dssize * sizeof(struct dsitem));       
-               if (dstack == NULL)
+               tmpds = realloc(dstack, dssize * sizeof(struct dsitem));        
+               if (tmpds == NULL) {
+            clearstack();
+            free(dstack);
                        return -1;
+        }
+        dstack = tmpds;
        }
 
        /* Put new element. Allocate and copy lname and path. */
        ds = dstack + dsidx++;
-//     ds->did = dir->d_did;
-       ds->pidx = pidx;
-       ds->checked = 0;
-       if (pidx >= 0) {
-           l = dstack[pidx].path_len;
-           u = strlen(uname) +1;
-           if (!(ds->path = malloc(l + u + 1) ))
-                       return -1;
-               memcpy(ds->path, dstack[pidx].path, l);
-               ds->path[l] = '/';
-               memcpy(&ds->path[l+1], uname, u);
-               ds->path_len = l +u;
-       }
-       else {
-           ds->path = strdup(uname);
-               ds->path_len = strlen(uname);
-       }
+       ds->ds_did = dir->d_did;
+       ds->ds_checked = 0;
        return 0;
 }
 
@@ -173,25 +169,15 @@ static int reducestack(void)
        }
 
        while (dsidx > 0) {
-               if (dstack[dsidx-1].checked) {
+               if (dstack[dsidx-1].ds_checked) {
                        dsidx--;
-                       free(dstack[dsidx].path);
+//                     free(dstack[dsidx].path);
                } else
                        return dsidx - 1;
        } 
        return -1;
 } 
 
-/* Clears directory stack. */
-static void clearstack(void) 
-{
-       save_cidx = -1;
-       while (dsidx > 0) {
-               dsidx--;
-               free(dstack[dsidx].path);
-       }
-} 
-
 /* Looks up for an opened adouble structure, opens resource fork of selected file. 
  * FIXME What about noadouble?
 */
@@ -207,7 +193,7 @@ static struct adouble *adl_lkup(struct vol *vol, struct path *path, struct adoub
            
        isdir  = S_ISDIR(path->st.st_mode);
 
-       if (!isdir && (of = of_findname(path))) {
+       if (!isdir && (of = of_findname(vol, path))) {
                adp = of->of_ad;
        } else {
                ad_init(&ad, vol->v_adouble, vol->v_ad_options);
@@ -504,7 +490,7 @@ static int catsearch(struct vol *vol,
 {
     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. */
-    struct dir *curdir;          /* struct dir of current directory */
+    struct dir *currentdir;      /* struct dir of current directory */
        int cidx, r;
        struct dirent *entry;
        int result = AFP_OK;
@@ -516,7 +502,8 @@ static int catsearch(struct vol *vol,
     int num_rounds = NUM_ROUNDS;
     int cwd = -1;
     int error;
-        
+    int unlen;
+
        if (*pos != 0 && *pos != cur_pos) {
                result = AFPERR_CATCHNG;
                goto catsearch_end;
@@ -550,18 +537,24 @@ static int catsearch(struct vol *vol,
     start_time = time(NULL);
 
        while ((cidx = reducestack()) != -1) {
-               error = lchdir(dstack[cidx].path);
+        if ((currentdir = dirlookup(vol, dstack[cidx].ds_did)) == NULL) {
+            result = AFPERR_MISC;
+            goto catsearch_end;
+        }
+        LOG(log_debug, logtype_afpd, "catsearch: current struct dir: \"%s\"", cfrombstr(currentdir->d_fullpath));
+
+               error = movecwd(vol, currentdir);
 
                if (!error && dirpos == NULL)
                        dirpos = opendir(".");
 
                if (dirpos == NULL)
-                       dirpos = opendir(dstack[cidx].path);
+                       dirpos = opendir(bdata(currentdir->d_fullpath));
 
                if (error || dirpos == NULL) {
                        switch (errno) {
                        case EACCES:
-                               dstack[cidx].checked = 1;
+                               dstack[cidx].ds_checked = 1;
                                continue;
                        case EMFILE:
                        case ENFILE:
@@ -576,10 +569,6 @@ static int catsearch(struct vol *vol,
                        goto catsearch_end;
                }
 
-        if ((curdir = dirlookup_bypath(vol, dstack[cidx].path)) == NULL) {
-            result = AFPERR_MISC;
-            goto catsearch_end;
-        }
                
                while ((entry = readdir(dirpos)) != NULL) {
                        (*pos)++;
@@ -587,9 +576,12 @@ static int catsearch(struct vol *vol,
                        if (!check_dirent(vol, entry->d_name))
                           continue;
 
+            LOG(log_debug, logtype_afpd, "catsearch(\"%s\"): dirent: \"%s\"",
+                cfrombstr(currentdir->d_fullpath), entry->d_name);
+
                        memset(&path, 0, sizeof(path));
                        path.u_name = entry->d_name;
-                       if (of_stat(&path) != 0) {
+                       if (of_stat(vol, &path) != 0) {
                                switch (errno) {
                                case EACCES:
                                case ELOOP:
@@ -604,20 +596,21 @@ static int catsearch(struct vol *vol,
                                        goto catsearch_end;
                                } 
                        }
-                       if (S_ISDIR(path.st.st_mode)) {
+            switch (S_IFMT & path.st.st_mode) {
+            case S_IFDIR:
                                /* here we can short cut 
                                   ie if in the same loop the parent dir wasn't in the cache
                                   ALL dirsearch_byname will fail.
                                */
-                int unlen = strlen(path.u_name);
+                unlen = strlen(path.u_name);
                 path.d_dir = dircache_search_by_name(vol,
-                                                     curdir,
+                                                     currentdir,
                                                      path.u_name,
                                                      unlen);
                if (path.d_dir == NULL) {
                        /* path.m_name is set by adddir */
                    if ((path.d_dir = dir_add(vol,
-                                              curdir,
+                                              currentdir,
                                               &path,
                                               unlen)) == NULL) {
                                                result = AFPERR_MISC;
@@ -630,8 +623,12 @@ static int catsearch(struct vol *vol,
                                        result = AFPERR_MISC;
                                        goto catsearch_end;
                                } 
-            } else {
-               path.d_dir = curdir;
+                break;
+            case S_IFREG:
+               path.d_dir = currentdir;
+                break;
+            default:
+                continue;
             }
 
                        ccr = crit_check(vol, &path);
@@ -663,7 +660,7 @@ static int catsearch(struct vol *vol,
                } /* while ((entry=readdir(dirpos)) != NULL) */
                closedir(dirpos);
                dirpos = NULL;
-               dstack[cidx].checked = 1;
+               dstack[cidx].ds_checked = 1;
        } /* while (current_idx = reducestack()) != -1) */
 
        /* We have finished traversing our tree. Return EOF here. */
@@ -777,7 +774,7 @@ static int catsearch_db(struct vol *vol,
         path.u_name = name;
         path.m_name = utompath(vol, name, cnid, utf8_encoding());
 
-        if (of_stat(&path) != 0) {
+        if (of_stat(vol, &path) != 0) {
             switch (errno) {
             case EACCES:
             case ELOOP:
@@ -1041,6 +1038,7 @@ static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
     /* Call search */
     *rbuflen = 24;
     if ((c1.rbitmap & (1 << FILPBIT_PDINFO))
+        && !(c1.rbitmap & (1<<CATPBIT_PARTIAL))
         && (strcmp(vol->v_cnidscheme, "dbd") == 0)
         && (vol->v_flags & AFPVOL_SEARCHDB))
         /* we've got a name and it's a dbd volume, so search CNID database */