X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fcatsearch.c;h=f1f55ef96d7a3ed2cea6823d317f1abcb014d180;hb=b362b6f7b22b6e4e9e74760989f389149677917b;hp=b266348ca0ca6a15073c1dfb003b70d90a426901;hpb=70e8818ea52f3ff5bca42e6c3cbf5765f959f322;p=netatalk.git diff --git a/etc/afpd/catsearch.c b/etc/afpd/catsearch.c index b266348c..f1f55ef9 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,47 +19,44 @@ * * 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 #include "config.h" #endif /* HAVE_CONFIG_H */ +#include +#include +#include #include #include #include #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 +#include +#include #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,57 +111,50 @@ struct scrit { * */ struct dsitem { - struct dir *dir; /* Structure describing 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->dir = dir; - dir->d_flags |= DIRF_CACHELOCK; - 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; } @@ -178,27 +169,15 @@ static int reducestack(void) } while (dsidx > 0) { - if (dstack[dsidx-1].checked) { + if (dstack[dsidx-1].ds_checked) { dsidx--; - dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK; - 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--; - dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK; - free(dstack[dsidx].path); - } -} - /* Looks up for an opened adouble structure, opens resource fork of selected file. * FIXME What about noadouble? */ @@ -214,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); @@ -485,21 +464,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 *currentdir; /* struct dir of current directory */ int cidx, r; struct dirent *entry; int result = AFP_OK; @@ -511,7 +502,8 @@ static int catsearch(struct vol *vol, struct dir *dir, int num_rounds = NUM_ROUNDS; int cwd = -1; int error; - + int unlen; + if (*pos != 0 && *pos != cur_pos) { result = AFPERR_CATCHNG; goto catsearch_end; @@ -545,18 +537,24 @@ static int catsearch(struct vol *vol, struct dir *dir, 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: @@ -570,16 +568,20 @@ static int catsearch(struct vol *vol, struct dir *dir, } /* switch (errno) */ goto catsearch_end; } + - while ((entry=readdir(dirpos)) != NULL) { + while ((entry = readdir(dirpos)) != NULL) { (*pos)++; 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: @@ -594,31 +596,41 @@ static int catsearch(struct vol *vol, struct dir *dir, 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); - path.d_dir = dircache_search_by_name(vol, dstack[cidx].dir, path.u_name, unlen); + unlen = strlen(path.u_name); + path.d_dir = dircache_search_by_name(vol, + currentdir, + 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, + currentdir, + &path, + unlen)) == NULL) { result = AFPERR_MISC; goto catsearch_end; } } - path.m_name = cfrombstring(path.d_dir->d_m_name); + path.m_name = cfrombstr(path.d_dir->d_m_name); if (addstack(path.u_name, path.d_dir, cidx) == -1) { result = AFPERR_MISC; goto catsearch_end; } + break; + case S_IFREG: + path.d_dir = currentdir; + break; + default: + continue; } - 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 */ @@ -648,7 +660,7 @@ static int catsearch(struct vol *vol, struct dir *dir, } /* 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. */ @@ -670,6 +682,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(vol, &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 +848,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 +1020,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 +1037,16 @@ 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)) + && !(c1.rbitmap & (1<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);