]> arthur.barton.de Git - netatalk.git/commitdiff
afp_catseaching the new database
authorFrank Lahm <franklahm@googlemail.com>
Tue, 23 Nov 2010 15:49:06 +0000 (16:49 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Tue, 23 Nov 2010 15:49:06 +0000 (16:49 +0100)
etc/afpd/catsearch.c
etc/cnid_dbd/dbd_resolve.c
include/atalk/cnid.h
libatalk/cnid/dbd/cnid_dbd.c
libatalk/cnid/dbd/cnid_dbd.h

index 70c93f15207a1ff7d48e2fdeb93fd91ba8a89947..e96621e84cefbea461df9d27b971c267cf734673 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>
 
@@ -485,18 +479,29 @@ 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. */
@@ -670,6 +675,143 @@ 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 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_db(struct vol *vol,
+                        struct dir *dir,  
+                        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;    /* Saved position index (ID) - used to remember "position" across FPCatSearch calls */
+    int num_matches, ccr ,r;
+       int result = AFP_OK;
+    struct path path;
+       char *rrbuf = rbuf;
+        
+       if (*pos != 0 && *pos != cur_pos) {
+               result = AFPERR_CATCHNG;
+               goto catsearch_end;
+       }
+
+    if (cur_pos == 0 || *pos == 0) {
+        if ((num_matches = cnid_find(vol->v_cdb,
+                                     c1.utf8name,
+                                     strlen(c1.utf8name),
+                                     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;
+
+        /* We need the parent CNID for files and must determine the type (file or dir) */
+        if ((name = cnid_resolve(vol->v_cdb, &did, resolvebuf, 12 + MAXPATHLEN + 1)) == NULL) {
+            result = AFPERR_NFILE;
+                       goto catsearch_end;
+        }
+
+        if ((dir = dirlookup(vol, did)) == NULL) {
+            LOG(log_error, logtype_afpd,"catsearch_db: missing DID: %u", ntohl(did));
+            result = AFPERR_NFILE;
+                       goto catsearch_end;
+        }
+        if (movecwd(vol, dir) < 0 ) {
+            LOG(log_error, logtype_afpd,"catsearch_db: movecwd: %s", dir->d_fullpath);
+            result = AFPERR_NFILE;
+                       goto catsearch_end;
+        }        
+
+        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:
+            case ENOENT:
+                goto next;
+            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) {
+                LOG(log_error, logtype_afpd,"catsearch_db: missing DID: %u", ntohl(cnid));
+                result = AFPERR_NFILE;
+                goto catsearch_end;
+            }
+        }
+        path.d_dir = dir;
+
+        LOG(log_error, 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)) {
+            /* 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;
+       return result;
+}
+
 /* -------------------------- */
 static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
                   char *rbuf, size_t *rbuflen, int ext)
@@ -861,7 +1003,7 @@ static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
                        namelen = 255;
 
                memcpy (c1.utf8name, spec1+2, namelen);
-               c1.utf8name[(namelen+1)] =0;
+               c1.utf8name[namelen] = 0;
 
                /* convert charset */
                flags = CONV_PRECOMPOSE;
@@ -872,7 +1014,13 @@ 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))
+        /* we've got a name and it's a dbd volume, so search CNID database */
+        ret = catsearch_db(vol, vol->v_root, 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);
 
index 6008d152dc10e1d6f550fe915ade078f7094c0cb..17a42de0ff1a5f362885edd4826fd9bbbc6e0521 100644 (file)
@@ -50,8 +50,8 @@ int dbd_resolve(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply
 
     memcpy(&rply->did, (char *) data.data + CNID_DID_OFS, sizeof(cnid_t));
 
-    rply->namelen = data.size - CNID_NAME_OFS;
-    rply->name = (char *)data.data + CNID_NAME_OFS;
+    rply->namelen = data.size;
+    rply->name = (char *)data.data;
 
     LOG(log_debug, logtype_cnid, "dbd_resolve: Resolving CNID %u to did %u name %s",
         ntohl(rqst->cnid), ntohl(rply->did), rply->name);
index 385f646d96d7f2c687e595cd03006d7e1bdb9f03..d7df70e1d164ddd82c5c61f44f9e07996500607a 100644 (file)
@@ -67,7 +67,7 @@ struct _cnid_db {
     int    (*cnid_getstamp)    (struct _cnid_db *cdb, void *buffer, const size_t len);
     cnid_t (*cnid_rebuild_add) (struct _cnid_db *, const struct stat *, const cnid_t,
                                 char *, const size_t, cnid_t);
-    int    (*cnid_find)        (struct _cnid_db *cdb, const char *name, size_t namelen,
+    int    (*cnid_find)        (struct _cnid_db *cdb, char *name, size_t namelen,
                                 void *buffer, size_t buflen);
 };
 typedef struct _cnid_db cnid_db;
index 22ac6d3b146adb839f79302122395363e4c8a2e6..990248e45e439a22bc4de87377ae8fbe7e1e95f7 100644 (file)
@@ -680,11 +680,9 @@ char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t le
     rqst.op = CNID_DBD_OP_RESOLVE;
     rqst.cnid = *id;
 
-    /* This mimicks the behaviour of the "regular" cnid_resolve. So far,
-       nobody uses the content of buffer. It only provides space for the
-       name in the caller. */
-    rply.name = (char *)buffer + CNID_HEADER_LEN;
-    rply.namelen = len - CNID_HEADER_LEN;
+    /* Pass buffer to transmit so it can stuff the reply data there */
+    rply.name = (char *)buffer;
+    rply.namelen = len;
 
     if (transmit(db, &rqst, &rply) < 0) {
         errno = CNID_ERR_DB;
@@ -695,7 +693,7 @@ char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t le
     switch (rply.result) {
     case CNID_DBD_RES_OK:
         *id = rply.did;
-        name = rply.name;
+        name = rply.name + CNID_NAME_OFS;
         LOG(log_debug, logtype_cnid, "cnid_dbd_resolve: resolved did: %u, name: '%s'", ntohl(*id), name);
         break;
     case CNID_DBD_RES_NOTFOUND:
@@ -793,7 +791,7 @@ cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t
 }
 
 /* ---------------------- */
-int cnid_dbd_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen)
+int cnid_dbd_find(struct _cnid_db *cdb, char *name, size_t namelen, void *buffer, size_t buflen)
 {
     CNID_private *db;
     struct cnid_dbd_rqst rqst;
index f25e36180a76d177e94ef6aa6ed3c7f7a0cdf493..1f645908358b442633beae7e730e9789be690975 100644 (file)
@@ -26,7 +26,7 @@ extern char  *cnid_dbd_resolve    (struct _cnid_db *, cnid_t *, void *, size_t )
 extern int    cnid_dbd_getstamp   (struct _cnid_db *, void *, const size_t ); 
 extern cnid_t cnid_dbd_lookup     (struct _cnid_db *, const struct stat *, const cnid_t,
                                    char *, const size_t);
-extern int    cnid_dbd_find       (struct _cnid_db *cdb, const char *name, size_t namelen,
+extern int    cnid_dbd_find       (struct _cnid_db *cdb, char *name, size_t namelen,
                                    void *buffer, size_t buflen);
 extern int    cnid_dbd_update     (struct _cnid_db *, const cnid_t, const struct stat *,
                                    const cnid_t, char *, size_t);