/*
* 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>
#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. */
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)
namelen = 255;
memcpy (c1.utf8name, spec1+2, namelen);
- c1.utf8name[(namelen+1)] =0;
+ c1.utf8name[namelen] = 0;
/* convert charset */
flags = CONV_PRECOMPOSE;
/* 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);