From: Frank Lahm Date: Tue, 23 Nov 2010 15:49:06 +0000 (+0100) Subject: afp_catseaching the new database X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=56b180541894127ea4a2ac37471da7f74a0e3a9e;hp=71ec4b597b051519868286079eb4a27bbb1e0315;p=netatalk.git afp_catseaching the new database --- diff --git a/etc/afpd/catsearch.c b/etc/afpd/catsearch.c index 70c93f15..e96621e8 100644 --- a/etc/afpd/catsearch.c +++ b/etc/afpd/catsearch.c @@ -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 */ @@ -18,6 +19,10 @@ * * Initial version written by Rafal Lewczuk * + * 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 @@ -30,26 +35,15 @@ #include #include #include - -#if STDC_HEADERS #include -#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 #include #include #include #include -#ifdef CNID_DB #include -#endif /* CNID_DB */ - +#include #include #include @@ -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); diff --git a/etc/cnid_dbd/dbd_resolve.c b/etc/cnid_dbd/dbd_resolve.c index 6008d152..17a42de0 100644 --- a/etc/cnid_dbd/dbd_resolve.c +++ b/etc/cnid_dbd/dbd_resolve.c @@ -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); diff --git a/include/atalk/cnid.h b/include/atalk/cnid.h index 385f646d..d7df70e1 100644 --- a/include/atalk/cnid.h +++ b/include/atalk/cnid.h @@ -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; diff --git a/libatalk/cnid/dbd/cnid_dbd.c b/libatalk/cnid/dbd/cnid_dbd.c index 22ac6d3b..990248e4 100644 --- a/libatalk/cnid/dbd/cnid_dbd.c +++ b/libatalk/cnid/dbd/cnid_dbd.c @@ -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; diff --git a/libatalk/cnid/dbd/cnid_dbd.h b/libatalk/cnid/dbd/cnid_dbd.h index f25e3618..1f645908 100644 --- a/libatalk/cnid/dbd/cnid_dbd.h +++ b/libatalk/cnid/dbd/cnid_dbd.h @@ -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);