return(m);
}
-/*!
- * Build path relativ to volume root
- *
- * path might be:
- * (a) relative:
- * "dir/subdir" with cwd: "/afp_volume/topdir"
- * (b) absolute:
- * "/afp_volume/dir/subdir"
- *
- * @param path (r) path relative to cwd() or absolute
- * @param volpath (r) volume path that path is a subdir of (has been computed in volinfo funcs)
- *
- * @returns relative path in new bstring, caller must bdestroy it
- */
-static bstring rel_path_in_vol(const char *path, const char *volpath)
-{
- EC_INIT;
- int cwd = -1;
- bstring fpath = NULL;
- char *dname = NULL;
- struct stat st;
-
- if (path == NULL || volpath == NULL)
- return NULL;
-
- EC_NEG1_LOG(cwd = open(".", O_RDONLY));
-
- EC_ZERO_LOGSTR(lstat(path, &st), "lstat(%s): %s", path, strerror(errno));
- switch (S_IFMT & st.st_mode) {
-
- case S_IFREG:
- case S_IFLNK:
- EC_NULL_LOG(dname = strdup(path));
- EC_ZERO_LOGSTR(chdir(dirname(dname)), "chdir(%s): %s", dirname, strerror(errno));
- free(dname);
- dname = NULL;
- EC_NULL(fpath = bfromcstr(getcwdpath()));
- BSTRING_STRIP_SLASH(fpath);
- EC_ZERO(bcatcstr(fpath, "/"));
- EC_NULL_LOG(dname = strdup(path));
- EC_ZERO(bcatcstr(fpath, basename(dname)));
- break;
-
- case S_IFDIR:
- EC_ZERO_LOGSTR(chdir(path), "chdir(%s): %s", path, strerror(errno));
- EC_NULL(fpath = bfromcstr(getcwdpath()));
- break;
-
- default:
- SLOG("special: %s", path);
- EC_FAIL;
- }
-
- BSTRING_STRIP_SLASH(fpath);
-
- /*
- * Now we have eg:
- * fpath: /Volume/netatalk/dir/bla
- * volpath: /Volume/netatalk/
- * we want: "dir/bla"
- */
- EC_ZERO(bdelete(fpath, 0, strlen(volpath)));
-
-EC_CLEANUP:
- if (dname) free(dname);
- if (cwd != -1) {
- fchdir(cwd);
- close(cwd);
- }
- if (ret != 0)
- return NULL;
- return fpath;
-}
/*!
* Convert dot encoding of basename _in place_
*
*/
struct dsitem {
- struct dir *dir; /* Structure describing this directory */
+// struct dir *dir; /* Structure describing this directory */
+// cnid_t did; /* CNID of this directory */
int pidx; /* Parent's dsitem structure index. */
int checked; /* Have we checked this directory ? */
int path_len;
/* Put new element. Allocate and copy lname and path. */
ds = dstack + dsidx++;
- ds->dir = dir;
- dir->d_flags |= DIRF_CACHELOCK;
+// ds->did = dir->d_did;
ds->pidx = pidx;
ds->checked = 0;
if (pidx >= 0) {
while (dsidx > 0) {
if (dstack[dsidx-1].checked) {
dsidx--;
- dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
free(dstack[dsidx].path);
} else
return dsidx - 1;
save_cidx = -1;
while (dsidx > 0) {
dsidx--;
- dstack[dsidx].dir->d_flags &= ~DIRF_CACHELOCK;
free(dstack[dsidx].path);
}
}
{
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 *curdir; /* struct dir of current directory */
int cidx, r;
struct dirent *entry;
int result = AFP_OK;
} /* switch (errno) */
goto catsearch_end;
}
+
+ if ((curdir = dirlookup_bypath(vol, dstack[cidx].path)) == NULL) {
+ result = AFPERR_MISC;
+ goto catsearch_end;
+ }
- while ((entry=readdir(dirpos)) != NULL) {
+ while ((entry = readdir(dirpos)) != NULL) {
(*pos)++;
if (!check_dirent(vol, entry->d_name))
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);
+ path.d_dir = dircache_search_by_name(vol,
+ curdir,
+ 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) ) ) {
+ if ((path.d_dir = dir_add(vol,
+ curdir,
+ &path,
+ unlen)) == NULL) {
result = AFPERR_MISC;
goto catsearch_end;
}
result = AFPERR_MISC;
goto catsearch_end;
}
+ } else {
+ path.d_dir = curdir;
}
- 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 */
* We have/need two indexes:
* - a DID/name index on the main dircache, another hashtable
* - a queue index on the dircache, for evicting the oldest entries
- * The cache supports locking of struct dir elements through the DIRF_CACHELOCK flag. A dir
- * locked this way wont ever be removed from the cache, so be careful.
*
* Debugging
* =========
* The default is to remove the 256 oldest entries from the cache.
* 1. Get the oldest entry
* 2. If it's in use ie open forks reference it or it's curdir requeue it,
- * or it's locked (from catsearch) dont remove it
+ * dont remove it
* 3. Remove the dir from the main cache and the didname index
* 4. Free the struct dir structure and all its members
*/
}
queue_count--;
- if (curdir == dir
- || (dir->d_flags & DIRF_CACHELOCK)) { /* 2 */
+ if (curdir == dir) { /* 2 */
if ((dir->qidx_node = enqueue(index_queue, dir)) == NULL) {
dircache_dump();
AFP_PANIC("dircache_evict");
{
hnode_t *hn;
- AFP_ASSERT(dir);
- AFP_ASSERT((flags & ~(QUEUE_INDEX | DIDNAME_INDEX | DIRCACHE)) == 0);
-
- if (dir->d_flags & DIRF_CACHELOCK)
- return;
+ AFP_ASSERT(dir);
+ AFP_ASSERT((flags & ~(QUEUE_INDEX | DIDNAME_INDEX | DIRCACHE)) == 0);
if (flags & QUEUE_INDEX) {
/* remove it from the queue index */
i = 1;
while ((hn = hash_scan_next(&hs))) {
dir = hnode_get(hn);
- fprintf(dump, "%05u: %3u %6u %6u %s%s %s\n",
+ fprintf(dump, "%05u: %3u %6u %6u %s %s\n",
i++,
ntohs(dir->d_vid),
ntohl(dir->d_pdid),
ntohl(dir->d_did),
dir->d_fullpath ? "d" : "f",
- (dir->d_flags & DIRF_CACHELOCK) ? "l" : "-",
cfrombstr(dir->d_u_name));
}
i = 1;
while ((hn = hash_scan_next(&hs))) {
dir = hnode_get(hn);
- fprintf(dump, "%05u: %3u %6u %6u %s%s %s\n",
+ fprintf(dump, "%05u: %3u %6u %6u %s %s\n",
i++,
ntohs(dir->d_vid),
ntohl(dir->d_pdid),
ntohl(dir->d_did),
dir->d_fullpath ? "d" : "f",
- (dir->d_flags & DIRF_CACHELOCK) ? "l" : "-",
cfrombstr(dir->d_u_name));
}
if (n == index_queue)
break;
dir = (struct dir *)n->data;
- fprintf(dump, "%05u: %3u %6u %6u %s%s %s\n",
+ fprintf(dump, "%05u: %3u %6u %6u %s %s\n",
i,
ntohs(dir->d_vid),
ntohl(dir->d_pdid),
ntohl(dir->d_did),
dir->d_fullpath ? "d" : "f",
- (dir->d_flags & DIRF_CACHELOCK) ? "l" : "-",
cfrombstr(dir->d_u_name));
n = n->next;
}
#include <atalk/unix.h>
#include <atalk/bstrlib.h>
#include <atalk/bstradd.h>
+#include <atalk/errchk.h>
#include "directory.h"
#include "dircache.h"
return param;
}
+/*!
+ * Resolve struct dir for an absolute path
+ *
+ * Given a path like "/Volumes/volume/dir/subdir" in a volume "/Volumes/volume" return
+ * a pointer to struct dir of "subdir".
+ * 1. Remove volue path from absolute path
+ * 2. start path
+ * 3. loop through all elements of the remaining path from 1.
+ * 4. we only allow dirs
+ * 5. search dircache
+ * 6. if not found in the dircache query the CNID database for the DID
+ * 7. and use dirlookup to resolve the DID to a it's struct dir *
+ *
+ * @param vol (r) volume the path is in, must be known
+ * @param path (r) absoule path
+ *
+ * @returns pointer to struct dir or NULL on error
+ */
+struct dir *dirlookup_bypath(const struct vol *vol, const char *path)
+{
+ EC_INIT;
+
+ struct dir *dir = NULL;
+ cnid_t cnid, did;
+ bstring rpath = NULL;
+ bstring statpath = NULL;
+ struct bstrList *l = NULL;
+ struct stat st;
+
+ cnid = htonl(2);
+ dir = vol->v_root;
+
+ EC_NULL(rpath = rel_path_in_vol(path, vol->v_path)); /* 1. */
+ EC_NULL(statpath = bfromcstr(vol->v_path)); /* 2. */
+
+ l = bsplit(rpath, '/');
+ for (int i = 0; i < l->qty ; i++) { /* 3. */
+ did = cnid;
+ EC_ZERO(bconcat(statpath, l->entry[i]));
+ EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st),
+ "lstat(rpath: %s, elem: %s): %s: %s",
+ cfrombstr(rpath), cfrombstr(l->entry[i]),
+ cfrombstr(statpath), strerror(errno));
+
+ if (!(S_ISDIR(st.st_mode))) /* 4. */
+ EC_FAIL;
+
+ if ((dir = dircache_search_by_name(vol, /* 5. */
+ dir,
+ cfrombstr(l->entry[i]),
+ blength(l->entry[i]),
+ st.st_ctime)) == NULL) {
+ if ((cnid = cnid_add(vol->v_cdb, /* 6. */
+ &st,
+ did,
+ cfrombstr(l->entry[i]),
+ blength(l->entry[i]),
+ 0)) == CNID_INVALID) {
+ EC_FAIL;
+ }
+
+ if ((dir = dirlookup(vol, cnid)) == NULL) /* 7. */
+ EC_FAIL;
+ }
+
+ EC_ZERO(bcatcstr(statpath, "/"));
+ }
+
+EC_CLEANUP:
+ bdestroy(rpath);
+ bstrListDestroy(l);
+ bdestroy(statpath);
+ if (ret != 0)
+ return NULL;
+
+ return dir;
+}
+
/*!
* @brief Resolve a DID
*
* @param did (r) DID to resolve
*
* @returns pointer to struct dir
- *
- * @note FIXME: OSX calls it with bogus id, ie file ID not folder ID,
- * and we are really bad in this case.
*/
struct dir *dirlookup(const struct vol *vol, cnid_t did)
{
/* Get it from the database */
cnid = did;
- if ( (upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL
- || (upath = strdup(upath)) == NULL) { /* 3 */
+ if ((upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL) {
+ afp_errno = AFPERR_NOOBJ;
+ err = 1;
+ goto exit;
+ }
+ if ((upath = strdup(upath)) == NULL) { /* 3 */
afp_errno = AFPERR_NOOBJ;
err = 1;
goto exit;
* - DIRDID_ROOT is hit
* - a cached entry is found
*/
+ LOG(log_debug, logtype_afpd, "dirlookup(did: %u) {recursion for did: %u}", ntohl(pdid));
if ((pdir = dirlookup(vol, pdid)) == NULL) {
err = 1;
goto exit;
/* Get macname from unixname */
if (path->m_name == NULL) {
if ((path->m_name = utompath(vol, path->u_name, id, utf8_encoding())) == NULL) {
+ LOG(log_error, logtype_afpd, "dir_add(\"%s\"): can't assign macname", path->u_name);
err = 2;
goto exit;
}
if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT)
return 0;
- if (dir->d_flags & DIRF_CACHELOCK) { /* 1 */
- LOG(log_warning, logtype_afpd, "dir_remove(did:%u,'%s'): dir is locked",
- ntohl(dir->d_did), cfrombstr(dir->d_u_name));
- return 0;
- }
-
LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}",
ntohl(dir->d_did), cfrombstr(dir->d_u_name));
LOG(log_maxdebug, logtype_afpd, "movecwd: from: curdir:\"%s\", cwd:\"%s\"",
cfrombstr(curdir->d_fullpath), getcwdpath());
- if ( dir == curdir)
- return( 0 );
if (dir->d_did == DIRDID_ROOT_PARENT) {
curdir = &rootParent;
return 0;
#define DIRF_OFFCNT (1<<4) /* offsprings count is valid */
#define DIRF_CNID (1<<5) /* renumerate id */
-#define DIRF_CACHELOCK (1<<6) /* lock in cache, don't remove in dircache_eviction, for catsearch */
#define AFPDIR_READ (1<<0)
const char *new_mname, const char *new_uname, bstring pdir_fullpath);
extern int dir_remove(const struct vol *vol, struct dir *dir);
extern struct dir *dirlookup (const struct vol *, cnid_t);
+extern struct dir *dirlookup_bypath(const struct vol *vol, const char *path);
+
extern int movecwd (const struct vol *, struct dir *);
extern struct path *cname (struct vol *, struct dir *, char **);
#endif /* HAVE_UNISTD_H */
#include <poll.h>
#include <netatalk/at.h>
+
#include <atalk/unicode.h>
+#include <atalk/bstrlib.h>
/* exit error codes */
#define EXITERR_CLNT 1 /* client related error */
extern int lchdir(const char *dir);
extern void randombytes(void *buf, int n);
#endif /* _ATALK_UTIL_H */
+
+/******************************************************************
+ * cnid.c
+ *****************************************************************/
+
+extern bstring rel_path_in_vol(const char *path, const char *volpath);
libutil_la_SOURCES = \
atalk_addr.c \
bprint.c \
+ cnid.c \
fault.c \
getiface.c \
locking.c \
--- /dev/null
+/*
+ * Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <libgen.h>
+
+#include <atalk/util.h>
+#include <atalk/cnid.h>
+#include <atalk/volinfo.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
+#include <atalk/logger.h>
+#include <atalk/errchk.h>
+#include <atalk/unicode.h>
+
+/*!
+ * Build path relativ to volume root
+ *
+ * path might be:
+ * (a) relative:
+ * "dir/subdir" with cwd: "/afp_volume/topdir"
+ * (b) absolute:
+ * "/afp_volume/dir/subdir"
+ *
+ * @param path (r) path relative to cwd() or absolute
+ * @param volpath (r) volume path that path is a subdir of (has been computed in volinfo funcs)
+ *
+ * @returns relative path in new bstring, caller must bdestroy it
+ */
+bstring rel_path_in_vol(const char *path, const char *volpath)
+{
+ EC_INIT;
+ int cwd = -1;
+ bstring fpath = NULL;
+ char *dname = NULL;
+ struct stat st;
+
+ if (path == NULL || volpath == NULL)
+ return NULL;
+
+ EC_NEG1_LOG(cwd = open(".", O_RDONLY));
+
+ EC_ZERO_LOGSTR(lstat(path, &st), "lstat(%s): %s", path, strerror(errno));
+
+ if (path[0] == '/') {
+ EC_NULL(fpath = bfromcstr(path));
+ } else {
+ switch (S_IFMT & st.st_mode) {
+ case S_IFREG:
+ case S_IFLNK:
+ EC_NULL_LOG(dname = strdup(path));
+ EC_ZERO_LOGSTR(chdir(dirname(dname)), "chdir(%s): %s", dirname, strerror(errno));
+ free(dname);
+ dname = NULL;
+ EC_NULL(fpath = bfromcstr(getcwdpath()));
+ BSTRING_STRIP_SLASH(fpath);
+ EC_ZERO(bcatcstr(fpath, "/"));
+ EC_NULL_LOG(dname = strdup(path));
+ EC_ZERO(bcatcstr(fpath, basename(dname)));
+ break;
+
+ case S_IFDIR:
+ EC_ZERO_LOGSTR(chdir(path), "chdir(%s): %s", path, strerror(errno));
+ EC_NULL(fpath = bfromcstr(getcwdpath()));
+ break;
+
+ default:
+ EC_FAIL;
+ }
+ }
+
+ BSTRING_STRIP_SLASH(fpath);
+
+ /*
+ * Now we have eg:
+ * fpath: /Volume/netatalk/dir/bla
+ * volpath: /Volume/netatalk/
+ * we want: "dir/bla"
+ */
+ EC_ZERO(bdelete(fpath, 0, strlen(volpath)));
+
+EC_CLEANUP:
+ if (dname) free(dname);
+ if (cwd != -1) {
+ fchdir(cwd);
+ close(cwd);
+ }
+ if (ret != 0)
+ return NULL;
+ return fpath;
+}