/*
- * $Id: afp_options.c,v 1.51.4.1 2010-02-04 14:34:31 franklahm Exp $
+ * $Id: afp_options.c,v 1.51.4.2 2010-02-05 10:27:58 franklahm Exp $
*
* Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu)
* Copyright (c) 1990,1993 Regents of The University of Michigan.
#include "globals.h"
#include "status.h"
#include "auth.h"
+#include "dircache.h"
#include <atalk/compat.h>
/* don't advertize slp by default */
options->flags |= OPTION_NOSLP;
#endif
- options->dircachesize = 8192;
+ options->dircachesize = DEFAULT_MAX_DIRCACHE_SIZE;
}
/* parse an afpd.conf line. i'm doing it this way because it's
#ifdef CNID_DB
#include <atalk/cnid.h>
#endif /* CNID_DB */
+#include <atalk/bstradd.h>
+
#include "desktop.h"
#include "directory.h"
#include "dircache.h"
/* 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) {
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);
}
}
char *rrbuf = rbuf;
time_t start_time;
int num_rounds = NUM_ROUNDS;
- int cached;
int cwd = -1;
if (*pos != 0 && *pos != cur_pos) {
}
while ((cidx = reducestack()) != -1) {
- cached = 1;
if (dirpos == NULL) {
dirpos = opendir(dstack[cidx].path);
-// FIXME dircache rewrite
-// cached = (dstack[cidx].dir->d_child != NULL);
}
if (dirpos == NULL) {
switch (errno) {
} /* switch (errno) */
goto catsearch_end;
}
- /* FIXME error in chdir, what do we do? */
- chdir(dstack[cidx].path);
+
+ if (chdir(dstack[cidx].path) != 0) {
+ result = AFPERR_NFILE;
+ goto catsearch_end;
+ }
while ((entry=readdir(dirpos)) != NULL) {
ALL dirsearch_byname will fail.
*/
int unlen = strlen(path.u_name);
- if (cached)
- path.d_dir = dircache_search_by_name(vol, dstack[cidx].dir, path.u_name, unlen);
- else
- path.d_dir = NULL;
- if (!path.d_dir) {
+ path.d_dir = dircache_search_by_name(vol, dstack[cidx].dir, 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) ) ) {
result = AFPERR_MISC;
goto catsearch_end;
}
}
- path.m_name = (char *)path.d_dir->d_m_name->data;
+ path.m_name = cfrombstring(path.d_dir->d_m_name);
if (addstack(path.u_name, path.d_dir, cidx) == -1) {
result = AFPERR_MISC;
/*
- $Id: dircache.c,v 1.1.2.3 2010-02-04 14:34:31 franklahm Exp $
+ $Id: dircache.c,v 1.1.2.4 2010-02-05 10:27:58 franklahm Exp $
Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
This program is free software; you can redistribute it and/or modify
* 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.
*/
/********************************************************
/*****************************
* THE dircache */
-/* Maximum size of the dircache hashtable */
-#define DEFAULT_MAX_DIRCACHE_SIZE 8192 /* FIXME: make it a afpd.conf option */
-#define MAX_POSSIBLE_DIRCACHE_SIZE 131072
-
static hash_t *dircache; /* The actual cache */
static unsigned int dircache_maxsize; /* cache maximum size */
*
* 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, dont remove it
+ * 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
* 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_ofork) { /* 2 */
+ if (curdir == dir
+ || dir->d_ofork
+ || (dir->d_flags & DIRF_CACHELOCK)) { /* 2 */
if ((dir->qidx_node = enqueue(index_queue, dir)) == NULL) {
dircache_dump();
exit(EXITERR_SYS);
assert(dir);
assert((flags & ~(QUEUE_INDEX | DIDNAME_INDEX | DIRCACHE)) == 0);
+ if (dir->d_flags & DIRF_CACHELOCK)
+ return;
+
if (flags & QUEUE_INDEX) {
/* remove it from the queue index */
dequeue(dir->qidx_node->prev); /* this effectively deletes the dequeued node */
}
/*!
-
- FIXME: TO DO !!!
-
* @brief Dump dircache to /tmp/dircache.PID
-
*/
void dircache_dump(void)
{
if (n == index_queue)
break;
dir = (struct dir *)n->data;
- fprintf(dump, "%05u: vid:%u, pdid:%u, did:%u, path:%s\n",
- i, ntohs(dir->d_vid), ntohl(dir->d_pdid), ntohl(dir->d_did), cfrombstring(dir->d_fullpath));
+ fprintf(dump, "%05u: vid:%u, pdid:%6u, did:%6u, path:%s, locked:%s\n",
+ i, ntohs(dir->d_vid), ntohl(dir->d_pdid), ntohl(dir->d_did), cfrombstring(dir->d_fullpath),
+ (dir->d_flags & DIRF_CACHELOCK) ? "yes" : "no");
n = n->next;
}
/*
- $Id: dircache.h,v 1.1.2.2 2010-02-04 14:34:31 franklahm Exp $
+ $Id: dircache.h,v 1.1.2.3 2010-02-05 10:27:58 franklahm Exp $
Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
This program is free software; you can redistribute it and/or modify
#include <atalk/volume.h>
#include <atalk/directory.h>
+/* Maximum size of the dircache hashtable */
+#define DEFAULT_MAX_DIRCACHE_SIZE 8192
+#define MAX_POSSIBLE_DIRCACHE_SIZE 131072
+
/* flags for dircache_remove */
#define DIRCACHE (1 << 0)
#define DIDNAME_INDEX (1 << 1)
/*
- * $Id: directory.c,v 1.131.2.9 2010-02-04 14:34:31 franklahm Exp $
+ * $Id: directory.c,v 1.131.2.10 2010-02-05 10:27:58 franklahm Exp $
*
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
/*
* FIXMEs, loose ends after the dircache rewrite:
- * o dircache aging, place dirlookup'ed dirs on front of queue ??
* o merge dircache_search_by_name and dir_add ??
* o case-insensitivity is gone from cname
- * o catsearch doesn't work, see FIXMEs in catsearch.c
- * o curdir per volume caching is gone
* o directory offspring count calculation probably broken
* o doesn't work with CNID backend last and the like,
* CNID backend must support persistent CNIDs.
*
* The final movecwd in cname failed, possibly with EPERM or ENOENT. We:
* 1. move cwd into parent dir (we're often already there, but not always)
+ * 2. set struct path to the dirname
+ * 3. in case of
+ * AFPERR_ACCESS: the dir is there, we just cant chdir into it
+ * AFPERR_NOOBJ: the dir was there when we stated it in cname, so we have a race
+ * 4. indicate there's no dir for this path
+ * 5. remove the dir
*/
static struct path *path_from_dir(struct vol *vol, struct dir *dir, struct path *ret)
{
- /*
- * it's tricky: movecwd failed some of dir path are not there anymore.
- * FIXME: Is it true with other errors?
- */
if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT)
return NULL;
switch (afp_errno) {
case AFPERR_ACCESS:
- if (movecwd( vol, dirlookup(vol, dir->d_pdid)) < 0 )
+ if (movecwd( vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */
return NULL;
- memcpy(ret->m_name, cfrombstring(dir->d_m_name), blength(dir->d_m_name) + 1);
+ memcpy(ret->m_name, cfrombstring(dir->d_m_name), blength(dir->d_m_name) + 1); /* 3 */
if (dir->d_m_name == dir->d_u_name) {
ret->u_name = ret->m_name;
} else {
}
ret->d_dir = dir;
-#if 0
- ret->st_valid = 1;
- ret->st_errno = EACCES;
-#endif
- LOG(log_debug, logtype_afpd, "cname(AFPERR_ACCESS:'%s') {path-from-dir: curdir:'%s', path:'%s'}",
+ LOG(log_debug, logtype_afpd, "cname('%s') {path-from-dir: AFPERR_ACCESS. curdir:'%s', path:'%s'}",
cfrombstring(dir->d_fullpath),
cfrombstring(curdir->d_fullpath),
ret->u_name);
return ret;
case AFPERR_NOOBJ:
- if (movecwd(vol, dirlookup(vol, dir->d_pdid)) < 0 )
+ if (movecwd(vol, dirlookup(vol, dir->d_pdid)) < 0 ) /* 1 */
return NULL;
memcpy(ret->m_name, cfrombstring(dir->d_m_name), blength(dir->d_m_name) + 1);
memcpy(ret->u_name, cfrombstring(dir->d_u_name), blength(dir->d_u_name) + 1);
}
-#if 0
- ret->st_valid = 1;
- ret->st_errno = ENOENT;
-#endif
- ret->d_dir = NULL;
- dir_remove(vol, dir);
+ ret->d_dir = NULL; /* 4 */
+ dir_remove(vol, dir); /* 5 */
return ret;
default:
}
/*!
+
+ FIXME: open forks ??!!!
+
* @brief Remove a dir from a cache and free it and any ressources with it
*
* @param (r) pointer to struct vol
if (dir->d_did == DIRDID_ROOT_PARENT || dir->d_did == DIRDID_ROOT)
return 0;
+ if (dir->d_flags & DIRF_CACHELOCK) {
+ LOG(log_warning, logtype_afpd, "dir_remove(did:%u,'%s'): attempt to remove a locked dir",
+ ntohl(dir->d_did), cfrombstring(dir->d_fullpath));
+ return 0;
+ }
+
if (curdir == dir) {
if (movecwd(vol, vol->v_root) < 0) {
LOG(log_error, logtype_afpd, "dir_remove: can't chdir to : %s", vol->v_root);
}
}
-
LOG(log_debug, logtype_afpd, "dir_remove(did:%u,'%s'): {removing}",
ntohl(dir->d_did), cfrombstring(dir->d_fullpath));
/*
- * $Id: directory.h,v 1.33.4.1 2010-02-01 10:56:08 franklahm Exp $
+ * $Id: directory.h,v 1.33.4.2 2010-02-05 10:27:59 franklahm Exp $
*
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
#define DIRF_AFS (1<<0)
#define DIRF_UFS (2<<0)
-#define DIRF_OFFCNT (1<<4) /* offsprings count is valid */
-#define DIRF_CNID (1<<5) /* renumerate id */
+#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)