#include <stdio.h>
#include <stdlib.h>
-#include <dirent.h>
#include <errno.h>
-#include <syslog.h>
-#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
#if STDC_HEADERS
#include <string.h>
#endif /* ! HAVE_MEMCPY */
#endif
-#include <sys/types.h>
-#include <sys/stat.h>
#include <sys/file.h>
#include <netinet/in.h>
-#include <netatalk/endian.h>
#include <atalk/afp.h>
#include <atalk/adouble.h>
+#include <atalk/logger.h>
#ifdef CNID_DB
#include <atalk/cnid.h>
-#endif /* DID_MTAB */
+#endif /* CNID_DB */
+
+#include <atalk/util.h>
+#include <atalk/bstradd.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"
-#ifdef DID_MTAB
-#include "parse-mtab.h"
-#endif /* DID_MTAB */
-
-#ifdef WITH_CATSEARCH
struct finderinfo {
u_int32_t f_type;
u_int32_t creator;
- u_int8_t attrs; /* File attributes (8 bits)*/
- u_int8_t label; /* Label (8 bits)*/
+ u_int16_t attrs; /* File attributes (high 8 bits)*/
+ u_int16_t label; /* Label (low 8 bits )*/
char reserved[22]; /* Unknown (at least for now...) */
};
+typedef char packed_finder[ADEDLEN_FINDERI];
+
/* Known attributes:
* 0x04 - has a custom icon
* 0x20 - name/icon is locked
time_t mdate; /* Last modification date */
time_t bdate; /* Last backup date */
u_int32_t pdid; /* Parent DID */
- u_int16_t offcnt; /* Offspring count */
+ u_int16_t offcnt; /* Offspring count */
struct finderinfo finfo; /* Finder info */
- char lname[32]; /* Long name */
+ char lname[64]; /* Long name */
+ char utf8name[514]; /* UTF8 or UCS2 name */ /* for convert_charset dest_len parameter +2 */
};
/*
*
*/
struct dsitem {
- char *lname; /* Long name */
struct dir *dir; /* Structure describing this directory */
int pidx; /* Parent's dsitem structure index. */
int checked; /* Have we checked this directory ? */
- char *path; /* UNIX path to this directory */
+ int path_len;
+ char *path; /* absolute UNIX path to this directory */
};
#define DS_BSIZE 128
-static int cur_pos = 0; /* Saved position index (ID) - used to remember "position" across FPCatSearch calls */
-static DIR *dirpos = NULL; /* UNIX structure describing currently opened directory. */
static int save_cidx = -1; /* Saved index of currently scanned directory. */
static struct dsitem *dstack = NULL; /* Directory stack data... */
static struct scrit c1, c2; /* search criteria */
/* Puts new item onto directory stack. */
-static int addstack(char *lname, struct dir *dir, int pidx)
+static int addstack(char *uname, struct dir *dir, int pidx)
{
struct dsitem *ds;
+ size_t l, u;
/* check if we have some space on stack... */
if (dsidx >= dssize) {
/* Put new element. Allocate and copy lname and path. */
ds = dstack + dsidx++;
- ds->lname = strdup(lname);
ds->dir = dir;
+ dir->d_flags |= DIRF_CACHELOCK;
ds->pidx = pidx;
+ ds->checked = 0;
if (pidx >= 0) {
- ds->path = malloc(strlen(dstack[pidx].path) + strlen(ds->lname) + 2);
- strcpy(ds->path, dstack[pidx].path);
- strcat(ds->path, "/");
- strcat(ds->path, ds->lname);
+ 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->checked = 0;
-
return 0;
}
/* Removes checked items from top of directory stack. Returns index of the first unchecked elements or -1. */
-static int reducestack()
+static int reducestack(void)
{
int r;
if (save_cidx != -1) {
while (dsidx > 0) {
if (dstack[dsidx-1].checked) {
dsidx--;
- free(dstack[dsidx].lname);
+ dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
free(dstack[dsidx].path);
- /* Check if we need to free (or release) dir structures */
} else
return dsidx - 1;
- } // while
+ }
return -1;
-} /* reducestack() */
+}
/* Clears directory stack. */
-static void clearstack()
+static void clearstack(void)
{
save_cidx = -1;
while (dsidx > 0) {
dsidx--;
- free(dstack[dsidx].lname);
+ dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
free(dstack[dsidx].path);
- /* Check if we need to free (or release) dir structures */
}
-} /* clearstack() */
+}
-/* Fills in dir field of dstack[cidx]. Must fill parent dirs' fields if needed... */
-static int resolve_dir(struct vol *vol, int cidx)
-{
- struct dir *dir, *curdir;
- struct stat statbuf;
-
- if (dstack[cidx].dir != NULL)
- return 1;
-
- if (dstack[cidx].pidx < 0)
- return 0;
-
- if (dstack[dstack[cidx].pidx].dir == NULL && resolve_dir(vol, dstack[cidx].pidx) == 0)
- return 0;
-
- curdir = dstack[dstack[cidx].pidx].dir;
- dir = curdir->d_child;
- while (dir) {
- if (strcmp(dir->d_name, dstack[cidx].lname) == 0)
- break;
- dir = (dir == curdir->d_child->d_prev) ? NULL : dir->d_next;
- } /* while */
-
- if (!dir)
- if (stat(dstack[cidx].path, &statbuf)==-1) {
- syslog(LOG_DEBUG, "resolve_dir: stat %s: %s", dstack[cidx].path, strerror(errno));
- return 0;
- }
-
- if (!dir && ((dir = adddir(vol, curdir, dstack[cidx].lname, strlen(dstack[cidx].lname),
- dstack[cidx].path, strlen(dstack[cidx].path), &statbuf)) == NULL))
- return 0;
- dstack[cidx].dir = dir;
-
- return 1;
-} /* resolve_dir */
-
-/* Looks up for an opened adouble structure, opens resource fork of selected file. */
-static struct adouble *adl_lkup(struct vol *vol, char *upath, int cidx)
+/* Looks up for an opened adouble structure, opens resource fork of selected file.
+ * FIXME What about noadouble?
+*/
+static struct adouble *adl_lkup(struct vol *vol, struct path *path, struct adouble *adp)
{
static struct adouble ad;
- struct adouble *adp;
- char *mpath = utompath(vol, upath);
+
struct ofork *of;
-
-/*
- //if (dstack[cidx].dir == NULL && !resolve_dir(vol, cidx))
- // return NULL;
-
- //if ((of = of_findname(vol, dstack[cidx].dir, mpath))) {
- // adp = of->of_ad;
- //} else {
- */
- memset(&ad, 0, sizeof(ad));
+ int isdir;
+
+ if (adp)
+ return adp;
+
+ isdir = S_ISDIR(path->st.st_mode);
+
+ if (!isdir && (of = of_findname(path))) {
+ adp = of->of_ad;
+ } else {
+ ad_init(&ad, vol->v_adouble, vol->v_ad_options);
adp = &ad;
- /* } */
+ }
- if ( ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, adp) < 0 ) {
- return NULL;
- }
+ if ( ad_metadata( path->u_name, ((isdir) ? ADFLAGS_DIR : 0), adp) < 0 ) {
+ adp = NULL; /* FIXME without resource fork adl_lkup will be call again */
+ }
+
return adp;
}
+/* -------------------- */
+static struct finderinfo *unpack_buffer(struct finderinfo *finfo, char *buffer)
+{
+ memcpy(&finfo->f_type, buffer +FINDERINFO_FRTYPEOFF, sizeof(finfo->f_type));
+ memcpy(&finfo->creator, buffer +FINDERINFO_FRCREATOFF, sizeof(finfo->creator));
+ memcpy(&finfo->attrs, buffer +FINDERINFO_FRFLAGOFF, sizeof(finfo->attrs));
+ memcpy(&finfo->label, buffer +FINDERINFO_FRFLAGOFF, sizeof(finfo->label));
+ finfo->attrs &= 0xff00; /* high 8 bits */
+ finfo->label &= 0xff; /* low 8 bits */
+
+ return finfo;
+}
+
+/* -------------------- */
+static struct finderinfo *
+unpack_finderinfo(struct vol *vol, struct path *path, struct adouble **adp, struct finderinfo *finfo, int islnk)
+{
+ packed_finder buf;
+ void *ptr;
+
+ *adp = adl_lkup(vol, path, *adp);
+ ptr = get_finderinfo(vol, path->u_name, *adp, &buf,islnk);
+ return unpack_buffer(finfo, ptr);
+}
+
+/* -------------------- */
#define CATPBIT_PARTIAL 31
/* Criteria checker. This function returns a 2-bit value. */
/* bit 0 means if checked file meets given criteria. */
* fname - our fname (translated to UNIX)
* cidx - index in directory stack
*/
-static int crit_check(struct vol *vol, char *uname, char *fname, int cidx) {
- int r = 0;
- struct stat sbuf;
- u_int16_t attr;
- struct finderinfo *finfo = NULL;
+static int crit_check(struct vol *vol, struct path *path) {
+ int result = 0;
+ u_int16_t attr, flags = CONV_PRECOMPOSE;
+ struct finderinfo *finfo = NULL, finderinfo;
struct adouble *adp = NULL;
time_t c_date, b_date;
+ u_int32_t ac_date, ab_date;
+ static char convbuf[514]; /* for convert_charset dest_len parameter +2 */
+ size_t len;
+ int islnk;
+ islnk=S_ISLNK(path->st.st_mode);
+
+ if (S_ISDIR(path->st.st_mode)) {
+ if (!c1.dbitmap)
+ return 0;
+ }
+ else {
+ if (!c1.fbitmap)
+ return 0;
- if (stat(uname, &sbuf) < 0)
- return 0;
-
- if (S_ISDIR(sbuf.st_mode))
- r = 2;
-
+ /* compute the Mac name
+ * first try without id (it's slow to find it)
+ * An other option would be to call get_id in utompath but
+ * we need to pass parent dir
+ */
+ if (!(path->m_name = utompath(vol, path->u_name, 0 , utf8_encoding()) )) {
+ /*retry with the right id */
+
+ cnid_t id;
+
+ adp = adl_lkup(vol, path, adp);
+ id = get_id(vol, adp, &path->st, path->d_dir->d_did, path->u_name, strlen(path->u_name));
+ if (!id) {
+ /* FIXME */
+ return 0;
+ }
+ /* save the id for getfilparm */
+ path->id = id;
+ if (!(path->m_name = utompath(vol, path->u_name, id , utf8_encoding()))) {
+ return 0;
+ }
+ }
+ }
+
/* Kind of optimization:
* -- first check things we've already have - filename
* -- last check things we get from ad_open()
+ * FIXME strmcp strstr (icase)
*/
/* Check for filename */
- if (c1.rbitmap & (1<<DIRPBIT_LNAME)) {
+ if ((c1.rbitmap & (1<<DIRPBIT_LNAME))) {
+ if ( (size_t)(-1) == (len = convert_string(vol->v_maccharset, CH_UCS2, path->m_name, -1, convbuf, 512)) )
+ goto crit_check_ret;
+
+ if ((c1.rbitmap & (1<<CATPBIT_PARTIAL))) {
+ if (strcasestr_w( (ucs2_t*) convbuf, (ucs2_t*) c1.lname) == NULL)
+ goto crit_check_ret;
+ } else
+ if (strcasecmp_w((ucs2_t*) convbuf, (ucs2_t*) c1.lname) != 0)
+ goto crit_check_ret;
+ }
+
+ if ((c1.rbitmap & (1<<FILPBIT_PDINFO))) {
+ if ( (size_t)(-1) == (len = convert_charset( CH_UTF8_MAC, CH_UCS2, CH_UTF8, path->m_name, strlen(path->m_name), convbuf, 512, &flags))) {
+ goto crit_check_ret;
+ }
+
if (c1.rbitmap & (1<<CATPBIT_PARTIAL)) {
- if (strstr(fname, c1.lname) == NULL)
+ if (strcasestr_w((ucs2_t *) convbuf, (ucs2_t*)c1.utf8name) == NULL)
goto crit_check_ret;
} else
- if (strcmp(fname, c1.lname) != 0)
+ if (strcasecmp_w((ucs2_t *)convbuf, (ucs2_t*)c1.utf8name) != 0)
goto crit_check_ret;
- } /* if (c1.rbitmap & ... */
+ }
/* FIXME */
if ((unsigned)c2.bdate > 0x7fffffff)
c2.bdate = 0x7fffffff;
- /* Check for modification date FIXME: should we look at adouble structure ? */
- if ((c1.rbitmap & (1<<DIRPBIT_MDATE)))
- if (sbuf.st_mtime < c1.mdate || sbuf.st_mtime > c2.mdate)
+ /* Check for modification date */
+ if ((c1.rbitmap & (1<<DIRPBIT_MDATE))) {
+ if (path->st.st_mtime < c1.mdate || path->st.st_mtime > c2.mdate)
goto crit_check_ret;
-
+ }
+
/* Check for creation date... */
- if (c1.rbitmap & (1<<DIRPBIT_CDATE)) {
- if (adp || (adp = adl_lkup(vol, uname, cidx))) {
- if (ad_getdate(adp, AD_DATE_CREATE, (u_int32_t*)&c_date) >= 0)
- c_date = AD_DATE_TO_UNIX(c_date);
- else c_date = sbuf.st_mtime;
- } else c_date = sbuf.st_mtime;
+ if ((c1.rbitmap & (1<<DIRPBIT_CDATE))) {
+ c_date = path->st.st_mtime;
+ adp = adl_lkup(vol, path, adp);
+ if (adp && ad_getdate(adp, AD_DATE_CREATE, &ac_date) >= 0)
+ c_date = AD_DATE_TO_UNIX(ac_date);
+
if (c_date < c1.cdate || c_date > c2.cdate)
goto crit_check_ret;
}
/* Check for backup date... */
- if (c1.rbitmap & (1<<DIRPBIT_BDATE)) {
- if (adp || (adp == adl_lkup(vol, uname, cidx))) {
- if (ad_getdate(adp, AD_DATE_BACKUP, (u_int32_t*)&b_date) >= 0)
- b_date = AD_DATE_TO_UNIX(b_date);
- else b_date = sbuf.st_mtime;
- } else b_date = sbuf.st_mtime;
+ if ((c1.rbitmap & (1<<DIRPBIT_BDATE))) {
+ b_date = path->st.st_mtime;
+ adp = adl_lkup(vol, path, adp);
+ if (adp && ad_getdate(adp, AD_DATE_BACKUP, &ab_date) >= 0)
+ b_date = AD_DATE_TO_UNIX(ab_date);
+
if (b_date < c1.bdate || b_date > c2.bdate)
goto crit_check_ret;
}
/* Check attributes */
- if ((c1.rbitmap & (1<<DIRPBIT_ATTR)) && c2.attr != 0)
- if (adp || (adp = adl_lkup(vol, uname, cidx))) {
+ if ((c1.rbitmap & (1<<DIRPBIT_ATTR)) && c2.attr != 0) {
+ if ((adp = adl_lkup(vol, path, adp))) {
ad_getattr(adp, &attr);
if ((attr & c2.attr) != c1.attr)
goto crit_check_ret;
- } else goto crit_check_ret;
-
+ } else
+ goto crit_check_ret;
+ }
/* Check file type ID */
- if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.f_type != 0)
- if (adp || (adp = adl_lkup(vol, uname, cidx))) {
- finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
- if (finfo->f_type != c1.finfo.f_type)
- goto crit_check_ret;
- } else goto crit_check_ret;
-
- /* Check creator ID */
- if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.creator != 0)
- if (adp || (adp = adl_lkup(vol, uname, cidx))) {
- finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
- if (finfo->creator != c1.finfo.creator)
- goto crit_check_ret;
- } else goto crit_check_ret;
+ if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.f_type != 0) {
+ finfo = unpack_finderinfo(vol, path, &adp, &finderinfo,islnk);
+ if (finfo->f_type != c1.finfo.f_type)
+ goto crit_check_ret;
+ }
+ /* Check creator ID */
+ if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.creator != 0) {
+ if (!finfo) {
+ finfo = unpack_finderinfo(vol, path, &adp, &finderinfo,islnk);
+ }
+ if (finfo->creator != c1.finfo.creator)
+ goto crit_check_ret;
+ }
+
/* Check finder info attributes */
- if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.attrs != 0)
- if (adp || (adp = adl_lkup(vol, uname, cidx))) {
- finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
- if ((finfo->attrs & c2.finfo.attrs) != c1.finfo.attrs)
- goto crit_check_ret;
- } else goto crit_check_ret;
+ if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.attrs != 0) {
+ if (!finfo) {
+ finfo = unpack_finderinfo(vol, path, &adp, &finderinfo,islnk);
+ }
- /* Check label */
- if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.label != 0)
- if (adp || (adp = adl_lkup(vol, uname, cidx))) {
- finfo = (struct finderinfo*)ad_entry(adp, ADEID_FINDERI);
- if ((finfo->label & c2.finfo.label) != c1.finfo.label)
- goto crit_check_ret;
- } else goto crit_check_ret;
+ if ((finfo->attrs & c2.finfo.attrs) != c1.finfo.attrs)
+ goto crit_check_ret;
+ }
+ /* Check label */
+ if ((c1.rbitmap & (1<<DIRPBIT_FINFO)) && c2.finfo.label != 0) {
+ if (!finfo) {
+ finfo = unpack_finderinfo(vol, path, &adp, &finderinfo,islnk);
+ }
+ if ((finfo->label & c2.finfo.label) != c1.finfo.label)
+ goto crit_check_ret;
+ }
/* FIXME: Attributes check ! */
/* All criteria are met. */
- r |= 1;
+ result |= 1;
crit_check_ret:
if (adp != NULL)
- ad_close(adp, ADFLAGS_HF);
- return r;
+ ad_close_metadata(adp);
+ return result;
}
-
-/* Adds an item to resultset. */
-static int rslt_add(struct vol *vol, struct stat *statbuf, char *fname, short cidx, int isdir, char **rbuf)
+/* ------------------------------ */
+static int rslt_add ( struct vol *vol, struct path *path, char **buf, int ext)
{
- char *p = *rbuf;
- int l = fname != NULL ? strlen(fname) : 0;
- u_int32_t did;
- char p0;
-
- p0 = p[0] = cidx != -1 ? l + 7 : l + 5;
- if (p0 & 1) p[0]++;
- p[1] = isdir ? 128 : 0;
- p += 2;
- if (cidx != -1) {
- if (dstack[cidx].dir == NULL && resolve_dir(vol, cidx) == 0)
- return 0;
- did = dstack[cidx].dir->d_did;
- memcpy(p, &did, sizeof(did));
- p += sizeof(did);
+
+ char *p = *buf;
+ int ret;
+ size_t tbuf =0;
+ u_int16_t resultsize;
+ int isdir = S_ISDIR(path->st.st_mode);
+
+ /* Skip resultsize */
+ if (ext) {
+ p += sizeof(resultsize);
}
+ else {
+ p++;
+ }
+ *p++ = isdir ? FILDIRBIT_ISDIR : FILDIRBIT_ISFILE; /* IsDir ? */
- /* Fill offset of returned file name */
- if (fname != NULL) {
- *p++ = 0;
- *p++ = (int)(p - *rbuf) + 1;
- p[0] = l;
- strcpy(p+1, fname);
- p += l + 1;
+ if (ext) {
+ *p++ = 0; /* Pad */
+ }
+
+ if ( isdir ) {
+ ret = getdirparams(vol, c1.dbitmap, path, path->d_dir, p , &tbuf );
+ }
+ else {
+ /* FIXME slow if we need the file ID, we already know it, done ? */
+ ret = getfilparams ( vol, c1.fbitmap, path, path->d_dir, p, &tbuf);
}
- if (p0 & 1)
- *p++ = 0;
+ if ( ret != AFP_OK )
+ return 0;
- *rbuf = p;
- /* *rbuf[0] = (int)(p-*rbuf); */
- return 1;
-} /* rslt_add */
+ /* Make sure entry length is even */
+ if ((tbuf & 1)) {
+ *p++ = 0;
+ tbuf++;
+ }
+
+ if (ext) {
+ resultsize = htons(tbuf);
+ memcpy ( *buf, &resultsize, sizeof(resultsize) );
+ *buf += tbuf + 4;
+ }
+ else {
+ **buf = tbuf;
+ *buf += tbuf + 2;
+ }
+ return 1;
+}
+
#define VETO_STR \
"./../.AppleDouble/.AppleDB/Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/.AppleDesktop/.Parent/"
* pos - position we've stopped recently
* rbuf - output buffer
* rbuflen - output buffer length
-*/
+ */
+#define NUM_ROUNDS 200
static int catsearch(struct vol *vol, struct dir *dir,
- int rmatches, int *pos, char *rbuf, u_int32_t *nrecs, int *rsize)
+ int rmatches, u_int32_t *pos, char *rbuf, u_int32_t *nrecs, int *rsize, int ext)
{
- int cidx, r, i;
- char *fname = NULL;
+ 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. */
+ int cidx, r;
struct dirent *entry;
- struct stat statbuf;
int result = AFP_OK;
int ccr;
- char *orig_dir = NULL;
- int orig_dir_len = 128;
- char *path = vol->v_path;
+ struct path path;
+ char *vpath = vol->v_path;
char *rrbuf = rbuf;
-
- if (*pos != 0 && *pos != cur_pos)
- return AFPERR_CATCHNG;
+ time_t start_time;
+ int num_rounds = NUM_ROUNDS;
+ int cwd = -1;
+ int error;
+
+ if (*pos != 0 && *pos != cur_pos) {
+ result = AFPERR_CATCHNG;
+ goto catsearch_end;
+ }
/* FIXME: Category "offspring count ! */
- /* So we are beginning... */
+
/* We need to initialize all mandatory structures/variables and change working directory appropriate... */
if (*pos == 0) {
clearstack();
if (dirpos != NULL) {
closedir(dirpos);
dirpos = NULL;
- } /* if (dirpos != NULL) */
+ }
- if (addstack("", dir, -1) == -1) {
+ if (addstack(vpath, dir, -1) == -1) {
result = AFPERR_MISC;
goto catsearch_end;
}
- dstack[0].path = strdup(path);
- /* FIXME: Sometimes DID is given by klient ! (correct this one above !) */
+ /* FIXME: Sometimes DID is given by client ! (correct this one above !) */
}
/* Save current path */
- orig_dir = (char*)malloc(orig_dir_len);
- while (getcwd(orig_dir, orig_dir_len-1)==NULL) {
- if (errno != ERANGE) {
- result = AFPERR_MISC;
- goto catsearch_end;
- }
- orig_dir_len += 128;
- orig_dir = realloc(orig_dir, orig_dir_len);
- } /* while() */
+ if ((cwd = open(".", O_RDONLY)) < 0) {
+ result = AFPERR_MISC;
+ goto catsearch_end;
+ }
+ /* So we are beginning... */
+ start_time = time(NULL);
+
while ((cidx = reducestack()) != -1) {
+ error = lchdir(dstack[cidx].path);
+
+ if (!error && dirpos == NULL)
+ dirpos = opendir(".");
+
if (dirpos == NULL)
- dirpos = opendir(dstack[cidx].path);
- if (dirpos == NULL) {
+ dirpos = opendir(dstack[cidx].path);
+
+ if (error || dirpos == NULL) {
switch (errno) {
case EACCES:
dstack[cidx].checked = 1;
} /* switch (errno) */
goto catsearch_end;
}
- chdir(dstack[cidx].path);
+
while ((entry=readdir(dirpos)) != NULL) {
(*pos)++;
- if (veto_file(VETO_STR, entry->d_name))
- continue;
- if (stat(entry->d_name, &statbuf) != 0) {
+
+ if (!check_dirent(vol, entry->d_name))
+ continue;
+
+ memset(&path, 0, sizeof(path));
+ path.u_name = entry->d_name;
+ if (of_stat(&path) != 0) {
switch (errno) {
case EACCES:
case ELOOP:
default:
result = AFPERR_MISC;
goto catsearch_end;
- } /* switch (errno) */
- } /* if (stat(entry->d_name, &statbuf) != 0) */
- fname = utompath(vol, entry->d_name);
- for (i = 0; fname[i] != 0; i++)
- fname[i] = tolower(fname[i]);
- if (strlen(fname) > MACFILELEN)
- continue;
- ccr = crit_check(vol, entry->d_name, fname, cidx);
- /* bit 0 means that criteria has ben met */
- if (ccr & 1) {
- r = rslt_add(vol, &statbuf,
- (c1.fbitmap&(1<<FILPBIT_LNAME))|(c1.dbitmap&(1<<DIRPBIT_LNAME)) ?
- utompath(vol, entry->d_name) : NULL,
- (c1.fbitmap&(1<<FILPBIT_PDID))|(c1.dbitmap&(1<<DIRPBIT_PDID)) ?
- cidx : -1,
- S_ISDIR(statbuf.st_mode), &rrbuf);
+ }
+ }
+ if (S_ISDIR(path.st.st_mode)) {
+ /* 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, path.st.st_ctime);
+ 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) ) ) {
+ result = AFPERR_MISC;
+ goto catsearch_end;
+ }
+ }
+ 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;
+ }
+ }
+ 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 */
+ if ((ccr & 1)) {
+ 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; /* FIXME: timelimit checks ! */
+ goto catsearch_pause;
/* Block size limit */
if (rrbuf - rbuf >= 448)
goto catsearch_pause;
-
- }
- /* bit 1 means that we have to descend into this directory. */
- if (ccr & 2) {
- if (S_ISDIR(statbuf.st_mode))
- if (addstack(entry->d_name, NULL, cidx) == -1) {
- result = AFPERR_MISC;
- goto catsearch_end;
- } /* if (addstack... */
+ }
+ /* MacOS 9 doesn't like servers executing commands longer than few seconds */
+ if (--num_rounds <= 0) {
+ if (start_time != time(NULL)) {
+ result=AFP_OK;
+ goto catsearch_pause;
+ }
+ num_rounds = NUM_ROUNDS;
}
} /* while ((entry=readdir(dirpos)) != NULL) */
- closedir(dirpos);dirpos = NULL;
+ closedir(dirpos);
+ dirpos = NULL;
dstack[cidx].checked = 1;
} /* while (current_idx = reducestack()) != -1) */
catsearch_end: /* Exiting catsearch: error condition */
*rsize = rrbuf - rbuf;
- if (orig_dir != NULL) {
- chdir(orig_dir);
- free(orig_dir);
- }
+ if (cwd != -1) {
+ if ((fchdir(cwd)) != 0) {
+ LOG(log_debug, logtype_afpd, "error chdiring back: %s", strerror(errno));
+ }
+ close(cwd);
+ }
return result;
} /* catsearch() */
-
-int afp_catsearch(AFPObj *obj, char *ibuf, int ibuflen,
- char *rbuf, int *rbuflen)
+/* -------------------------- */
+static int catsearch_afp(AFPObj *obj _U_, char *ibuf, size_t ibuflen,
+ char *rbuf, size_t *rbuflen, int ext)
{
struct vol *vol;
u_int16_t vid;
+ u_int16_t spec_len;
u_int32_t rmatches, reserved;
u_int32_t catpos[4];
u_int32_t pdid = 0;
- char *lname = NULL;
- struct dir *dir;
- int ret, rsize, i = 0;
+ int ret, rsize;
u_int32_t nrecs = 0;
- static int nrr = 1;
- char *spec1, *spec2, *bspec1, *bspec2;
+ unsigned char *spec1, *spec2, *bspec1, *bspec2;
+ size_t len;
+ u_int16_t namelen;
+ u_int16_t flags;
+ char tmppath[256];
+
+ *rbuflen = 0;
+
+ /* min header size */
+ if (ibuflen < 32) {
+ return AFPERR_PARAM;
+ }
memset(&c1, 0, sizeof(c1));
memset(&c2, 0, sizeof(c2));
memcpy(&vid, ibuf, sizeof(vid));
ibuf += sizeof(vid);
- *rbuflen = 0;
- if ((vol = getvolbyvid(vid)) == NULL)
+ if ((vol = getvolbyvid(vid)) == NULL) {
return AFPERR_PARAM;
-
+ }
+
memcpy(&rmatches, ibuf, sizeof(rmatches));
rmatches = ntohl(rmatches);
ibuf += sizeof(rmatches);
ibuf += sizeof(c1.fbitmap);
memcpy(&c1.dbitmap, ibuf, sizeof(c1.dbitmap));
- c1.dbitmap = c2.dbitmap = ntohl(c1.dbitmap);
+ c1.dbitmap = c2.dbitmap = ntohs(c1.dbitmap);
ibuf += sizeof(c1.dbitmap);
memcpy(&c1.rbitmap, ibuf, sizeof(c1.rbitmap));
ibuf += sizeof(c1.rbitmap);
if (! (c1.fbitmap || c1.dbitmap)) {
- *rbuflen = 0;
return AFPERR_BITMAP;
}
+ if ( ext) {
+ memcpy(&spec_len, ibuf, sizeof(spec_len));
+ spec_len = ntohs(spec_len);
+ }
+ else {
+ /* with catsearch only name and parent id are allowed */
+ c1.fbitmap &= (1<<FILPBIT_LNAME) | (1<<FILPBIT_PDID);
+ c1.dbitmap &= (1<<DIRPBIT_LNAME) | (1<<DIRPBIT_PDID);
+ spec_len = *(unsigned char*)ibuf;
+ }
+
/* Parse file specifications */
- spec1 = ibuf;
- spec2 = ibuf + ibuf[0] + 2;
+ spec1 = (unsigned char*)ibuf;
+ spec2 = (unsigned char*)ibuf + spec_len + 2;
- spec1 += 2; bspec1 = spec1;
- spec2 += 2; bspec2 = spec2;
+ spec1 += 2;
+ spec2 += 2;
+ bspec1 = spec1;
+ bspec2 = spec2;
/* File attribute bits... */
if (c1.rbitmap & (1 << FILPBIT_ATTR)) {
- memcpy(&c1.attr, ibuf, sizeof(c1.attr));
+ memcpy(&c1.attr, spec1, sizeof(c1.attr));
spec1 += sizeof(c1.attr);
- c1.attr = ntohs(c1.attr);
- memcpy(&c2.attr, ibuf, sizeof(c2.attr));
+ memcpy(&c2.attr, spec2, sizeof(c2.attr));
spec2 += sizeof(c1.attr);
- c2.attr = ntohs(c2.attr);
}
/* Parent DID */
}
/* Finder info */
- if (c1.rbitmap * (1 << FILPBIT_FINFO)) {
- memcpy(&c1.finfo, spec1, sizeof(c1.finfo));
- spec1 += sizeof(c1.finfo);
- memcpy(&c2.finfo, spec2, sizeof(c2.finfo));
- spec2 += sizeof(c2.finfo);
+ if (c1.rbitmap & (1 << FILPBIT_FINFO)) {
+ packed_finder buf;
+
+ memcpy(buf, spec1, sizeof(buf));
+ unpack_buffer(&c1.finfo, buf);
+ spec1 += sizeof(buf);
+
+ memcpy(buf, spec2, sizeof(buf));
+ unpack_buffer(&c2.finfo, buf);
+ spec2 += sizeof(buf);
} /* Finder info */
- /* Offspring count - only directories */
- if (c1.dbitmap != 0 && (c1.rbitmap & (1 << DIRPBIT_OFFCNT)) != 0) {
- memcpy(&c1.offcnt, spec1, sizeof(c1.offcnt));
- spec1 += sizeof(c1.offcnt);
- c1.offcnt = ntohs(c1.offcnt);
- memcpy(&c2.offcnt, spec2, sizeof(c2.offcnt));
- spec2 += sizeof(c2.offcnt);
- c2.offcnt = ntohs(c2.offcnt);
- } /* Offspring count */
+ if ((c1.rbitmap & (1 << DIRPBIT_OFFCNT)) != 0) {
+ /* Offspring count - only directories */
+ if (c1.fbitmap == 0) {
+ memcpy(&c1.offcnt, spec1, sizeof(c1.offcnt));
+ spec1 += sizeof(c1.offcnt);
+ c1.offcnt = ntohs(c1.offcnt);
+ memcpy(&c2.offcnt, spec2, sizeof(c2.offcnt));
+ spec2 += sizeof(c2.offcnt);
+ c2.offcnt = ntohs(c2.offcnt);
+ }
+ else if (c1.dbitmap == 0) {
+ /* ressource fork length */
+ }
+ else {
+ return AFPERR_BITMAP; /* error */
+ }
+ } /* Offspring count/ressource fork length */
/* Long name */
if (c1.rbitmap & (1 << FILPBIT_LNAME)) {
/* Get the long filename */
- memcpy(c1.lname, bspec1 + spec1[1] + 1, (bspec1 + spec1[1])[0]);
- c1.lname[(bspec1 + spec1[1])[0]]= 0;
- for (i = 0; c1.lname[i] != 0; i++)
- c1.lname[i] = tolower(c1.lname[i]);
- /* FIXME: do we need it ? It's always null ! */
- memcpy(c2.lname, bspec2 + spec2[1] + 1, (bspec2 + spec2[1])[0]);
- c2.lname[(bspec2 + spec2[1])[0]]= 0;
- for (i = 0; c2.lname[i] != 0; i++)
- c2.lname[i] = tolower(c2.lname[i]);
+ memcpy(tmppath, bspec1 + spec1[1] + 1, (bspec1 + spec1[1])[0]);
+ tmppath[(bspec1 + spec1[1])[0]]= 0;
+ len = convert_string ( vol->v_maccharset, CH_UCS2, tmppath, -1, c1.lname, sizeof(c1.lname));
+ if (len == (size_t)(-1))
+ return AFPERR_PARAM;
+
+#if 0
+ /* FIXME: do we need it ? It's always null ! */
+ memcpy(c2.lname, bspec2 + spec2[1] + 1, (bspec2 + spec2[1])[0]);
+ c2.lname[(bspec2 + spec2[1])[0]]= 0;
+#endif
}
+ /* UTF8 Name */
+ if (c1.rbitmap & (1 << FILPBIT_PDINFO)) {
+
+ /* offset */
+ memcpy(&namelen, spec1, sizeof(namelen));
+ namelen = ntohs (namelen);
+
+ spec1 = bspec1+namelen+4; /* Skip Unicode Hint */
+ /* length */
+ memcpy(&namelen, spec1, sizeof(namelen));
+ namelen = ntohs (namelen);
+ if (namelen > 255) /* Safeguard */
+ namelen = 255;
+ memcpy (c1.utf8name, spec1+2, namelen);
+ c1.utf8name[(namelen+1)] =0;
+
+ /* convert charset */
+ flags = CONV_PRECOMPOSE;
+ len = convert_charset(CH_UTF8_MAC, CH_UCS2, CH_UTF8, c1.utf8name, namelen, c1.utf8name, 512, &flags);
+ if (len == (size_t)(-1))
+ return AFPERR_PARAM;
+ }
+
/* Call search */
*rbuflen = 24;
- ret = catsearch(vol, vol->v_dir, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize);
+ ret = catsearch(vol, vol->v_root, rmatches, &catpos[0], rbuf+24, &nrecs, &rsize, ext);
memcpy(rbuf, catpos, sizeof(catpos));
rbuf += sizeof(catpos);
+
c1.fbitmap = htons(c1.fbitmap);
memcpy(rbuf, &c1.fbitmap, sizeof(c1.fbitmap));
rbuf += sizeof(c1.fbitmap);
+
c1.dbitmap = htons(c1.dbitmap);
memcpy(rbuf, &c1.dbitmap, sizeof(c1.dbitmap));
- rbuf += sizeof(c2.dbitmap);
+ rbuf += sizeof(c1.dbitmap);
+
nrecs = htonl(nrecs);
memcpy(rbuf, &nrecs, sizeof(nrecs));
rbuf += sizeof(nrecs);
*rbuflen += rsize;
return ret;
-} /* afp_catsearch */
+} /* catsearch_afp */
+
+/* -------------------------- */
+int afp_catsearch (AFPObj *obj, char *ibuf, size_t ibuflen,
+ char *rbuf, size_t *rbuflen)
+{
+ return catsearch_afp( obj, ibuf, ibuflen, rbuf, rbuflen, 0);
+}
+
+
+int afp_catsearch_ext (AFPObj *obj, char *ibuf, size_t ibuflen,
+ char *rbuf, size_t *rbuflen)
+{
+ return catsearch_afp( obj, ibuf, ibuflen, rbuf, rbuflen, 1);
+}
/* FIXME: we need a clean separation between afp stubs and 'real' implementation */
/* (so, all buffer packing/unpacking should be done in stub, everything else
should be done in other functions) */
-
-#endif
-/* WITH_CATSEARCH */