/*! * 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; }
/* * build mac. path (backwards) by traversing the directory tree * * The old way: dir and path refer to an app, path is a mac format * pathname. makemacpath() builds something that looks like a cname, * but uses upaths instead of mac format paths. * * The new way: dir and path refer to an app, path is a mac format * pathname. makemacpath() builds a cname. (zero is a path separator * and it's not \0 terminated). * * See afp_getappl() for the backward compatiblity code. */ static char * makemacpath(const struct vol *vol, char *mpath, int mpathlen, struct dir *dir, char *path) { char *p; p = mpath + mpathlen; p -= strlen( path ); memcpy( p, path, strlen( path )); while ( dir->d_did != DIRDID_ROOT ) { p -= blength(dir->d_m_name) + 1; if (p < mpath) { /* FIXME: pathname too long */ return NULL; } memcpy(p, cfrombstr(dir->d_m_name), blength(dir->d_m_name) + 1); if ((dir = dirlookup(vol, dir->d_pdid)) == NULL) return NULL; } return( p ); #if 0 char buffer[12 + MAXPATHLEN + 1]; int buflen = 12 + MAXPATHLEN + 1; char *ret = mpath; char *path = name; char *uname = NULL; struct bstrList *pathlist = NULL; cnid_t cnid = dir->d_pdid; /* Create list for path elements, request 16 list elements for now*/ if ((pathlist = bstListCreateMin(16)) == NULL) { LOG(log_error, logtype_afpd, "makemacpath: OOM: %s", strerror(errno)); return NULL; } while ( cnid != DIRDID_ROOT ) { /* construct path, copy already found uname to path element list*/ if ((bstrListPush(pathlist, bfromcstr(path))) != BSTR_OK) { afp_errno = AFPERR_MISC; ret = NULL; goto exit; } /* next part */ if ((uname = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL ) { afp_errno = AFPERR_NOOBJ; ret = NULL; goto exit; } if ((path = utompath(vol, uname, cnid, utf8_encoding())) == NULL) { afp_errno = AFPERR_MISC; ret = NULL; goto exit; } } exit: if (pathlist) bstrListDestroy(pathlist); return(ret); #endif }
/* ------------------------------------------------------- */ static char * private_demangle(const struct vol *vol, char *mfilename, cnid_t did, cnid_t *osx) { char *t; char *u_name; uint32_t id, file_id; static char buffer[12 + MAXPATHLEN + 1]; int len = 12 + MAXPATHLEN + 1; struct dir *dir; size_t prefix; id = file_id = 0; t = strchr(mfilename, MANGLE_CHAR); if (t == NULL) { return mfilename; } prefix = t - mfilename; /* FIXME * is prefix == 0 a valid mangled filename ? */ /* may be a mangled filename */ t++; if (*t == '0') { /* can't start with a 0 */ return mfilename; } while(isuxdigit(*t)) { id = (id *16) + hextoint(*t); t++; } if ((*t != 0 && *t != '.') || strlen(t) > MAX_EXT_LENGTH || id < 17) { return mfilename; } file_id = id = htonl(id); if (osx) { *osx = id; } /* is it a dir?, there's a conflict with pre OSX 'trash #2' */ if ((dir = dirlookup(vol, id))) { if (dir->d_pdid != did) { /* not in the same folder, there's a race with outdate cache * but we have to live with it, hopefully client will recover */ return mfilename; } if (!osx) { /* it's not from cname so mfilename and dir must be the same */ if (strcmp(cfrombstr(dir->d_m_name), mfilename) == 0) { return cfrombstr(dir->d_u_name); } } else { return demangle_checks(vol, cfrombstr(dir->d_u_name), mfilename, prefix, t); } } else if (NULL != (u_name = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) { if (id != did) { return mfilename; } if (!osx) { /* convert back to mac name and check it's the same */ t = utompath(vol, u_name, file_id, utf8_encoding(vol->v_obj)); if (!strcmp(t, mfilename)) { return u_name; } } else { return demangle_checks (vol, u_name, mfilename, prefix, t); } } return mfilename; }