]> arthur.barton.de Git - netatalk.git/blobdiff - etc/afpd/catsearch.c
First working IPC reconnect
[netatalk.git] / etc / afpd / catsearch.c
index 3aa043497b37c40e17702ef51b3248cb97914eaa..a488501e6b67e3c101660b844aa218bb460a1da5 100644 (file)
@@ -1,6 +1,7 @@
 /* 
  * Netatalk 2002 (c)
  * Copyright (C) 1990, 1993 Regents of The University of Michigan
+ * Copyright (C) 2010 Frank Lahm
  * All Rights Reserved. See COPYRIGHT
  */
 
  *
  * Initial version written by Rafal Lewczuk <rlewczuk@pronet.pl>
  *
+ * Starting with Netatalk 2.2 searching by name criteria utilizes the
+ * CNID database in conjunction with an enhanced cnid_dbd. This requires
+ * the use of cnidscheme:dbd for the searched volume, the new functionality
+ * is not built into cnidscheme:cdb.
  */
 
 #ifdef HAVE_CONFIG_H
 #include <ctype.h>
 #include <string.h>
 #include <time.h>
-
-#if STDC_HEADERS
 #include <string.h>
-#else
-#ifndef HAVE_MEMCPY
-#define memcpy(d,s,n) bcopy ((s), (d), (n))
-#define memmove(d,s,n) bcopy ((s), (d), (n))
-#endif /* ! HAVE_MEMCPY */
-#endif
-
 #include <sys/file.h>
 #include <netinet/in.h>
 
 #include <atalk/afp.h>
 #include <atalk/adouble.h>
 #include <atalk/logger.h>
-#ifdef CNID_DB
 #include <atalk/cnid.h>
-#endif /* CNID_DB */
-
+#include <atalk/cnid_dbd_private.h>
 #include <atalk/util.h>
 #include <atalk/bstradd.h>
+#include <atalk/unicode.h>
+#include <atalk/globals.h>
 
 #include "desktop.h"
 #include "directory.h"
 #include "dircache.h"
 #include "file.h"
 #include "volume.h"
-#include "globals.h"
 #include "filedir.h"
 #include "fork.h"
 
@@ -113,7 +108,8 @@ struct scrit {
  *
  */
 struct dsitem {
-       struct dir *dir; /* Structure describing this directory */
+//     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;
@@ -146,8 +142,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->did = dir->d_did;
        ds->pidx = pidx;
        ds->checked = 0;
        if (pidx >= 0) {
@@ -180,7 +175,6 @@ 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;
@@ -194,7 +188,6 @@ static void clearstack(void)
        save_cidx = -1;
        while (dsidx > 0) {
                dsidx--;
-        dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
                free(dstack[dsidx].path);
        }
 } 
@@ -485,21 +478,33 @@ static int rslt_add ( struct vol *vol, struct path *path, char **buf, int ext)
 #define VETO_STR \
         "./../.AppleDouble/.AppleDB/Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/.AppleDesktop/.Parent/"
 
-/* This function performs search. It is called directly from afp_catsearch 
- * vol - volume we are searching on ...
- * dir - directory we are starting from ...
- * c1, c2 - search criteria
- * rmatches - maximum number of matches we can return
- * pos - position we've stopped recently
- * rbuf - output buffer
- * rbuflen - output buffer length
+/*!
+ * This function performs a filesystem search
+ *
+ * Uses globals c1, c2, the search criteria
+ *
+ * @param vol       (r)  volume we are searching on ...
+ * @param dir       (rw) directory we are starting from ...
+ * @param rmatches  (r)  maximum number of matches we can return
+ * @param pos       (r)  position we've stopped recently
+ * @param rbuf      (w)  output buffer
+ * @param nrecs     (w)  number of matches
+ * @param rsize     (w)  length of data written to output buffer
+ * @param ext       (r)  extended search flag
  */
 #define NUM_ROUNDS 200
-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 int catsearch(struct vol *vol,
+                     struct dir *dir,  
+                     int rmatches,
+                     uint32_t *pos,
+                     char *rbuf,
+                     uint32_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. */
+    struct dir *curdir;          /* struct dir of current directory */
        int cidx, r;
        struct dirent *entry;
        int result = AFP_OK;
@@ -570,8 +575,13 @@ static int catsearch(struct vol *vol, struct dir *dir,
                        } /* switch (errno) */
                        goto catsearch_end;
                }
+
+        if ((curdir = dirlookup_bypath(vol, dstack[cidx].path)) == NULL) {
+            result = AFPERR_MISC;
+            goto catsearch_end;
+        }
                
-               while ((entry=readdir(dirpos)) != NULL) {
+               while ((entry = readdir(dirpos)) != NULL) {
                        (*pos)++;
 
                        if (!check_dirent(vol, entry->d_name))
@@ -600,10 +610,16 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                   ALL dirsearch_byname will fail.
                                */
                 int unlen = strlen(path.u_name);
-                path.d_dir = dircache_search_by_name(vol, dstack[cidx].dir, path.u_name, unlen);
+                path.d_dir = dircache_search_by_name(vol,
+                                                     curdir,
+                                                     path.u_name,
+                                                     unlen);
                if (path.d_dir == NULL) {
                        /* path.m_name is set by adddir */
-                   if (NULL == (path.d_dir = dir_add( vol, dstack[cidx].dir, &path, unlen) ) ) {
+                   if ((path.d_dir = dir_add(vol,
+                                              curdir,
+                                              &path,
+                                              unlen)) == NULL) {
                                                result = AFPERR_MISC;
                                                goto catsearch_end;
                                        }
@@ -614,11 +630,10 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                        result = AFPERR_MISC;
                                        goto catsearch_end;
                                } 
+            } else {
+               path.d_dir = curdir;
             }
-            else {
-               /* yes it sucks for directory d_dir is the directory, for file it's the parent directory*/
-               path.d_dir = dstack[cidx].dir;
-            }
+
                        ccr = crit_check(vol, &path);
 
                        /* bit 0 means that criteria has been met */
@@ -670,6 +685,156 @@ catsearch_end: /* Exiting catsearch: error condition */
        return result;
 } /* catsearch() */
 
+/*!
+ * This function performs a CNID db search
+ *
+ * Uses globals c1, c2, the search criteria
+ *
+ * @param vol       (r)  volume we are searching on ...
+ * @param dir       (rw) directory we are starting from ...
+ * @param uname     (r)  UNIX name of object to search
+ * @param rmatches  (r)  maximum number of matches we can return
+ * @param pos       (r)  position we've stopped recently
+ * @param rbuf      (w)  output buffer
+ * @param nrecs     (w)  number of matches
+ * @param rsize     (w)  length of data written to output buffer
+ * @param ext       (r)  extended search flag
+ */
+static int catsearch_db(struct vol *vol,
+                        struct dir *dir,  
+                        const char *uname,
+                        int rmatches,
+                        uint32_t *pos,
+                        char *rbuf,
+                        uint32_t *nrecs,
+                        int *rsize,
+                        int ext)
+{
+    static char resbuf[DBD_MAX_SRCH_RSLTS * sizeof(cnid_t)];
+    static uint32_t cur_pos;
+    static int num_matches;
+    int ccr ,r;
+       int result = AFP_OK;
+    struct path path;
+       char *rrbuf = rbuf;
+    char buffer[MAXPATHLEN +2];
+    uint16_t flags = CONV_TOLOWER;
+
+    LOG(log_debug, logtype_afpd, "catsearch_db(req pos: %u): {pos: %u, name: %s}",
+        *pos, cur_pos, uname);
+        
+       if (*pos != 0 && *pos != cur_pos) {
+               result = AFPERR_CATCHNG;
+               goto catsearch_end;
+       }
+
+    if (cur_pos == 0 || *pos == 0) {
+        if (convert_charset(vol->v_volcharset,
+                            vol->v_volcharset,
+                            vol->v_maccharset,
+                            uname,
+                            strlen(uname),
+                            buffer,
+                            MAXPATHLEN,
+                            &flags) == (size_t)-1) {
+            LOG(log_error, logtype_afpd, "catsearch_db: conversion error");
+            result = AFPERR_MISC;
+            goto catsearch_end;
+        }
+
+        LOG(log_debug, logtype_afpd, "catsearch_db: %s", buffer);
+
+        if ((num_matches = cnid_find(vol->v_cdb,
+                                     buffer,
+                                     strlen(uname),
+                                     resbuf,
+                                     sizeof(resbuf))) == -1) {
+            result = AFPERR_MISC;
+            goto catsearch_end;
+        }
+    }
+       
+       while (cur_pos < num_matches) {
+        char *name;
+        cnid_t cnid, did;
+        char resolvebuf[12 + MAXPATHLEN + 1];
+        struct dir *dir;
+
+        /* Next CNID to process from buffer */
+        memcpy(&cnid, resbuf + cur_pos * sizeof(cnid_t), sizeof(cnid_t));
+        did = cnid;
+
+        if ((name = cnid_resolve(vol->v_cdb, &did, resolvebuf, 12 + MAXPATHLEN + 1)) == NULL)
+            goto next;
+        LOG(log_debug, logtype_afpd, "catsearch_db: {pos: %u, name:%s, cnid: %u}",
+            cur_pos, name, ntohl(cnid));
+        if ((dir = dirlookup(vol, did)) == NULL)
+            goto next;
+        if (movecwd(vol, dir) < 0 )
+            goto next;
+
+        memset(&path, 0, sizeof(path));
+        path.u_name = name;
+        path.m_name = utompath(vol, name, cnid, utf8_encoding());
+
+        if (of_stat(&path) != 0) {
+            switch (errno) {
+            case EACCES:
+            case ELOOP:
+                goto next;
+            case ENOENT:
+                
+            default:
+                result = AFPERR_MISC;
+                goto catsearch_end;
+            } 
+        }
+        /* For files path.d_dir is the parent dir, for dirs its the dir itself */
+        if (S_ISDIR(path.st.st_mode))
+            if ((dir = dirlookup(vol, cnid)) == NULL)
+                goto next;
+        path.d_dir = dir;
+
+        LOG(log_maxdebug, logtype_afpd,"catsearch_db: dir: %s, cwd: %s, name: %s", 
+            cfrombstr(dir->d_fullpath), getcwdpath(), path.u_name);
+
+        /* At last we can check the search criteria */
+        ccr = crit_check(vol, &path);
+        if ((ccr & 1)) {
+            LOG(log_debug, logtype_afpd,"catsearch_db: match: %s/%s",
+                getcwdpath(), path.u_name);
+            /* bit 1 means that criteria has been met */
+            r = rslt_add(vol, &path, &rrbuf, ext);
+            if (r == 0) {
+                result = AFPERR_MISC;
+                goto catsearch_end;
+            } 
+            *nrecs += r;
+            /* Number of matches limit */
+            if (--rmatches == 0) 
+                goto catsearch_pause;
+            /* Block size limit */
+            if (rrbuf - rbuf >= 448)
+                goto catsearch_pause;
+        }
+    next:
+        cur_pos++;
+    } /* while */
+
+       /* finished */
+       result = AFPERR_EOF;
+    cur_pos = 0;
+       goto catsearch_end;
+
+catsearch_pause:
+    *pos = cur_pos;
+
+catsearch_end: /* Exiting catsearch: error condition */
+       *rsize = rrbuf - rbuf;
+    LOG(log_debug, logtype_afpd, "catsearch_db(req pos: %u): {pos: %u}", *pos, cur_pos);
+       return result;
+}
+
 /* -------------------------- */
 static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
                   char *rbuf, size_t *rbuflen, int ext)
@@ -686,7 +851,8 @@ static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
     size_t     len;
     u_int16_t  namelen;
     u_int16_t  flags;
-    char       tmppath[256];
+    char           tmppath[256];
+    char        *uname;
 
     *rbuflen = 0;
 
@@ -857,11 +1023,13 @@ static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
                /* length */
                memcpy(&namelen, spec1, sizeof(namelen));
                namelen = ntohs (namelen);
-               if (namelen > 255)  /* Safeguard */
-                       namelen = 255;
+               if (namelen > UTF8FILELEN_EARLY)  /* Safeguard */
+                       namelen = UTF8FILELEN_EARLY;
 
                memcpy (c1.utf8name, spec1+2, namelen);
-               c1.utf8name[(namelen+1)] =0;
+               c1.utf8name[namelen] = 0;
+        if ((uname = mtoupath(vol, c1.utf8name, 0, utf8_encoding())) == NULL)
+            return AFPERR_PARAM;
 
                /* convert charset */
                flags = CONV_PRECOMPOSE;
@@ -872,7 +1040,15 @@ static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
     
     /* Call search */
     *rbuflen = 24;
-    ret = catsearch(vol, vol->v_root, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
+    if ((c1.rbitmap & (1 << FILPBIT_PDINFO))
+        && (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 */
+        ret = catsearch_db(vol, vol->v_root, uname, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
+    else
+        /* perform a slow filesystem tree search */
+        ret = catsearch(vol, vol->v_root, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
+
     memcpy(rbuf, catpos, sizeof(catpos));
     rbuf += sizeof(catpos);