]> arthur.barton.de Git - netatalk.git/commitdiff
Enhance dircache robustness, dircache statistics logged in SIGALARM
authorFrank Lahm <franklahm@googlemail.com>
Mon, 1 Nov 2010 16:31:43 +0000 (17:31 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Mon, 1 Nov 2010 16:31:43 +0000 (17:31 +0100)
etc/afpd/afp_dsi.c
etc/afpd/catsearch.c
etc/afpd/dircache.c
etc/afpd/dircache.h
etc/afpd/directory.c
etc/afpd/directory.h
etc/afpd/enumerate.c
etc/afpd/file.c
etc/afpd/filedir.c
etc/afpd/volume.c
include/atalk/directory.h

index 90facbee6508d41606d67df95035897378a7dade..277e412bc1bc94101ef45f0745bfe83e40e85d89 100644 (file)
@@ -214,6 +214,8 @@ static void alarm_handler(int sig _U_)
      * may use alarm() */
     setitimer(ITIMER_REAL, &dsi->timer, NULL);
 
+    log_dircache_stat();
+
     /* we got some traffic from the client since the previous timer 
      * tick. */
     if ((child.flags & CHILD_DATA)) {
index 3aa043497b37c40e17702ef51b3248cb97914eaa..70c93f15207a1ff7d48e2fdeb93fd91ba8a89947 100644 (file)
@@ -600,7 +600,7 @@ static int catsearch(struct vol *vol, struct dir *dir,
                                   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.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) ) ) {
index a01139a2eb8ba85bcc8d4fd15735b719ed7730fe..41635beb4082894e570a752e5bc0393816f2511c 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <assert.h>
+#include <time.h>
 
 #include <atalk/util.h>
 #include <atalk/cnid.h>
  * The dircache is a LRU cache, whenever it fills up we call dircache_evict internally which removes
  * DIRCACHE_FREE_QUANTUM elements from the cache.
  *
- * There is only one cache for all volumes, so of course we use the volume is in hashing calculations.
+ * There is only one cache for all volumes, so of course we use the volume id in hashing calculations.
+ *
+ * In order to avoid cache poisoning, we store the cached entries st_ctime from stat in
+ * struct dir.ctime_dircache. Later when we search the cache we compare the stored
+ * value with the result of a fresh stat. If the times differ, we remove the cached
+ * entry and return "no entry found in cache".
+ * A elements ctime changes when
+ *   1) the element is renamed
+ *      (we loose the cached entry here, but it will expire when the cache fills)
+ *   2) its a directory and an object has been created therein
+ *   3) the element is deleted and recreated under the same name
+ * Using ctime leads to cache eviction in case 2) where it wouldn't be necessary, because
+ * the dir itself (name, CNID, ...) hasn't changed, but there's no other way.
  *
  * Indexes
  * =======
 static hash_t       *dircache;        /* The actual cache */
 static unsigned int dircache_maxsize; /* cache maximum size */
 
+static struct dircache_stat {
+    unsigned long long lookups;
+    unsigned long long hits;
+    unsigned long long misses;
+    unsigned long long added;
+    unsigned long long removed;
+    unsigned long long expunged;
+    unsigned long long evicted;
+} dircache_stat;
+
 /* FNV 1a */
 static hash_val_t hash_vid_did(const void *key)
 {
@@ -210,7 +233,7 @@ static int hash_comp_didname(const void *k1, const void *k2)
  * queue index on dircache */
 
 static q_t *index_queue;    /* the index itself */
-static unsigned int queue_count;
+static unsigned long queue_count;
 
 /*!
  * @brief Remove a fixed number of (oldest) entries from the cache and indexes
@@ -251,8 +274,8 @@ static void dircache_evict(void)
         dir_free(dir);                                        /* 4 */
     }
 
-   AFP_ASSERT(queue_count == dircache->hash_nodecount);
-
+    AFP_ASSERT(queue_count == dircache->hash_nodecount);
+    dircache_stat.evicted += DIRCACHE_FREE_QUANTUM;
     LOG(log_debug, logtype_afpd, "dircache: {finished cache eviction}");
 }
 
@@ -262,50 +285,92 @@ static void dircache_evict(void)
  ********************************************************/
 
 /*!
- * @brief Search the dircache via a CNID
+ * @brief Search the dircache via a CNID for a directory
+ *
+ * Found cache entries are expunged if both the parent directory st_ctime and the objects
+ * st_ctime are modified.
+ * This func builds on the fact, that all our code only ever needs to and does search
+ * the dircache by CNID expecting directories to be returned, but not files.
+ * Thus
+ * (1) if we find a file (d_fullpath == NULL) for a given CNID we
+ *     (1a) remove it from the cache
+ *     (1b) return NULL indicating nothing found
+ * (2) we can then use d_fullpath to stat the directory
  *
- * @param vol    (r) pointer to struct vol
- * @param cnid   (r) CNID of the file or directory
+ * @param vol      (r) pointer to struct vol
+ * @param cnid     (r) CNID of the directory to search
  *
- * @returns Pointer to struct dir if found, else NULL
+ * @returns            Pointer to struct dir if found, else NULL
  */
 struct dir *dircache_search_by_did(const struct vol *vol, cnid_t cnid)
 {
     struct dir *cdir = NULL;
     struct dir key;
+    struct stat st;
     hnode_t *hn;
 
-   AFP_ASSERT(vol);
-   AFP_ASSERT(ntohl(cnid) >= CNID_START);
+    AFP_ASSERT(vol);
+    AFP_ASSERT(ntohl(cnid) >= CNID_START);
 
+    dircache_stat.lookups++;
     key.d_vid = vol->v_vid;
     key.d_did = cnid;
     if ((hn = hash_lookup(dircache, &key)))
         cdir = hnode_get(hn);
 
-    if (cdir)
-        LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {cached: path:'%s'}",
-            ntohl(cnid), cfrombstr(cdir->d_u_name));
-    else
-        LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {not in cache}", ntohl(cnid));
+    if (cdir) {
+        if (cdir->d_fullpath == NULL) { /* (1) */
+            LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {not a directory:\"%s\"}",
+                ntohl(cnid), cfrombstr(cdir->d_u_name));
+            (void)dir_remove(vol, cdir); /* (1a) */
+            dircache_stat.expunged++;
+            return NULL;        /* (1b) */
 
+        }
+        if (lstat(cfrombstr(cdir->d_fullpath), &st) != 0) {
+            LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {missing:\"%s\"}",
+                ntohl(cnid), cfrombstr(cdir->d_fullpath));
+            (void)dir_remove(vol, cdir);
+            dircache_stat.expunged++;
+            return NULL;
+        }
+        if (cdir->ctime_dircache != st.st_ctime) {
+            LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {modified:\"%s\"}",
+                ntohl(cnid), cfrombstr(cdir->d_u_name));
+            (void)dir_remove(vol, cdir);
+            dircache_stat.expunged++;
+            return NULL;
+        }
+        LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {cached: path:\"%s\"}",
+            ntohl(cnid), cfrombstr(cdir->d_fullpath));
+        dircache_stat.hits++;
+    } else {
+        LOG(log_debug, logtype_afpd, "dircache(cnid:%u): {not in cache}", ntohl(cnid));
+        dircache_stat.hits++;
+    }
+    
     return cdir;
 }
 
 /*!
  * @brief Search the cache via did/name hashtable
  *
- * @param vol    (r) volume
- * @param dir    (r) directory
- * @param name   (r) name (server side encoding)
- * @parma len    (r) strlen of name
+ * Found cache entries are expunged if both the parent directory st_ctime and the objects
+ * st_ctime are modified.
+ *
+ * @param vol      (r) volume
+ * @param dir      (r) directory
+ * @param name     (r) name (server side encoding)
+ * @parma len      (r) strlen of name
+ * @param ctime    (r) current st_ctime from stat
  *
  * @returns pointer to struct dir if found in cache, else NULL
  */
-struct dir *dircache_search_by_name(const struct vol *vol, const struct dir *dir, char *name, int len)
+struct dir *dircache_search_by_name(const struct vol *vol, const struct dir *dir, char *name, int len, time_t ctime)
 {
     struct dir *cdir = NULL;
     struct dir key;
+
     hnode_t *hn;
     static_bstring uname = {-1, len, (unsigned char *)name};
 
@@ -315,6 +380,7 @@ struct dir *dircache_search_by_name(const struct vol *vol, const struct dir *dir
     AFP_ASSERT(len == strlen(name));
     AFP_ASSERT(len < 256);
 
+    dircache_stat.lookups++;
     LOG(log_debug, logtype_afpd, "dircache_search_by_name(did:%u, \"%s\")",
         ntohl(dir->d_did), name);
 
@@ -327,12 +393,22 @@ struct dir *dircache_search_by_name(const struct vol *vol, const struct dir *dir
             cdir = hnode_get(hn);
     }
 
-    if (cdir)
-        LOG(log_debug, logtype_afpd, "dircache(did:%u, '%s'): {found in cache}",
+    if (cdir) {
+        if (cdir->ctime_dircache != ctime) {
+            LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {modified}",
+                ntohl(dir->d_did), name);
+            (void)dir_remove(vol, cdir);
+            dircache_stat.expunged++;
+            return NULL;
+        }
+        LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {found in cache}",
             ntohl(dir->d_did), name);
-    else
-        LOG(log_debug, logtype_afpd, "dircache(did:%u,'%s'): {not in cache}",
+        dircache_stat.hits++;
+    } else {
+        LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {not in cache}",
             ntohl(dir->d_did), name);
+        dircache_stat.misses++;
+    }
 
     return cdir;
 }
@@ -379,6 +455,7 @@ int dircache_add(struct dir *dir)
         queue_count++;
     }
 
+    dircache_stat.added++;
     LOG(log_debug, logtype_afpd, "dircache(did:%u,'%s'): {added}",
         ntohl(dir->d_did), cfrombstr(dir->d_u_name));
 
@@ -433,8 +510,9 @@ void dircache_remove(const struct vol *vol _U_, struct dir *dir, int flags)
     LOG(log_debug, logtype_afpd, "dircache(did:%u,\"%s\"): {removed}",
         ntohl(dir->d_did), cfrombstr(dir->d_u_name));
 
-   AFP_ASSERT(queue_count == index_didname->hash_nodecount 
-           && queue_count == dircache->hash_nodecount);
+    dircache_stat.removed++;
+    AFP_ASSERT(queue_count == index_didname->hash_nodecount 
+               && queue_count == dircache->hash_nodecount);
 }
 
 /*!
@@ -484,6 +562,23 @@ int dircache_init(int reqsize)
     return 0;
 }
 
+/*!
+ * Log dircache statistics
+ */
+void log_dircache_stat(void)
+{
+    LOG(log_debug, logtype_afpd, "dircache_stat: "
+        "entries: %lu, lookups: %llu, hits: %llu, misses: %llu, added: %llu, removed: %llu, expunged: %llu, evicted: %llu",
+        queue_count,
+        dircache_stat.lookups,
+        dircache_stat.hits,
+        dircache_stat.misses,
+        dircache_stat.added,
+        dircache_stat.removed,
+        dircache_stat.expunged,
+        dircache_stat.evicted);
+}
+
 /*!
  * @brief Dump dircache to /tmp/dircache.PID
  */
@@ -506,7 +601,7 @@ void dircache_dump(void)
     }
     setbuf(dump, NULL);
 
-    fprintf(dump, "Number of cache entries in LRU queue: %u\n", queue_count);
+    fprintf(dump, "Number of cache entries in LRU queue: %lu\n", queue_count);
     fprintf(dump, "Configured maximum cache size: %u\n\n", dircache_maxsize);
 
     fprintf(dump, "Primary CNID index:\n");
index d261ea57821589f81306cf5fbd964c81a11a4a33..69c5f9abebd40ae197cecae82a60f4421d81ae98 100644 (file)
@@ -1,5 +1,4 @@
 /*
-   $Id: dircache.h,v 1.1.2.5 2010-02-11 14:13:06 franklahm Exp $
    Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
 
    This program is free software; you can redistribute it and/or modify
@@ -16,6 +15,8 @@
 #ifndef DIRCACHE_H 
 #define DIRCACHE_H
 
+#include <sys/types.h>
+
 #include <atalk/volume.h>
 #include <atalk/directory.h>
 
 #define DIRCACHE      (1 << 0)
 #define DIDNAME_INDEX (1 << 1)
 #define QUEUE_INDEX   (1 << 2)
+#define DIRCACHE_ALL  (DIRCACHE|DIDNAME_INDEX|QUEUE_INDEX)
 
 extern int        dircache_init(int reqsize);
 extern int        dircache_add(struct dir *);
 extern void       dircache_remove(const struct vol *, struct dir *, int flag);
 extern struct dir *dircache_search_by_did(const struct vol *vol, cnid_t did);
-extern struct dir *dircache_search_by_name(const struct vol *, const struct dir *dir, char *name, int len);
+extern struct dir *dircache_search_by_name(const struct vol *, const struct dir *dir, char *name, int len, time_t ctime);
 extern void       dircache_dump(void);
-
+extern void       log_dircache_stat(void);
 #endif /* DIRCACHE_H */
index e91ee70aacd29f5a3e9df767fe970048ffd71663..61a385f1f2f6f62db98ce85f6de63ed45f9b4573 100644 (file)
@@ -555,12 +555,12 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did)
     }
 
     /* Create struct dir */
-    if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath)) == NULL) { /* 6 */
+    if ((ret = dir_new(mpath, upath, vol, pdid, did, fullpath, st.st_ctime)) == NULL) { /* 6 */
         LOG(log_error, logtype_afpd, "dirlookup(did: %u) {%s, %s}: %s", ntohl(did), mpath, upath, strerror(errno));
         err = 1;
         goto exit;
     }
-
+    
     /* Add it to the cache only if it's a dir */
     if (dircache_add(ret) != 0) { /* 7 */
         err = 1;
@@ -677,7 +677,8 @@ int caseenumerate(const struct vol *vol, struct path *path, struct dir *dir)
  * @param vol      (r) pointer to struct vol
  * @param pdid     (r) Parent CNID
  * @param did      (r) CNID
- * @param fullpath (r) Full unix path to dir or NULL for files
+ * @param path     (r) Full unix path to dir or NULL for files
+ * @param ctime    (r) st_ctime from stat
  *
  * @returns pointer to new struct dir or NULL on error
  *
@@ -688,7 +689,8 @@ struct dir *dir_new(const char *m_name,
                     const struct vol *vol,
                     cnid_t pdid,
                     cnid_t did,
-                    bstring path)
+                    bstring path,
+                    time_t ctime)
 {
     struct dir *dir;
 
@@ -722,6 +724,7 @@ struct dir *dir_new(const char *m_name,
     dir->d_pdid = pdid;
     dir->d_vid = vol->v_vid;
     dir->d_fullpath = path;
+    dir->ctime_dircache = ctime;
     return dir;
 }
 
@@ -746,8 +749,7 @@ void dir_free(struct dir *dir)
  * @brief Create struct dir from struct path
  *
  * Create a new struct dir from struct path. Then add it to the cache.
- * The caller must have assured that the dir is not already in the cache,
- * cf theAFP_ASSERTion.
+ *
  * 1. Open adouble file, get CNID from it.
  * 2. Search the database, hinting with the CNID from (1).
  * 3. Build fullpath and create struct dir.
@@ -776,7 +778,7 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i
     AFP_ASSERT(path);
     AFP_ASSERT(len > 0);
 
-    if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name))) != NULL) {
+    if ((cdir = dircache_search_by_name(vol, dir, path->u_name, strlen(path->u_name), path->st.st_ctime)) != NULL) {
         /* there's a stray entry in the dircache */
         LOG(log_debug, logtype_afpd, "dir_add(did:%u,'%s/%s'): {stray cache entry: did:%u,'%s', removing}",
             ntohl(dir->d_did), cfrombstr(dir->d_fullpath), path->u_name,
@@ -819,7 +821,7 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i
     }
 
     /* Allocate and initialize struct dir */
-    if ((cdir = dir_new( path->m_name, path->u_name, vol, dir->d_did, id, fullpath)) == NULL) { /* 3 */
+    if ((cdir = dir_new( path->m_name, path->u_name, vol, dir->d_did, id, fullpath, path->st.st_ctime)) == NULL) { /* 3 */
         err = 4;
         goto exit;
     }
@@ -1169,7 +1171,7 @@ struct path *cname(struct vol *vol, struct dir *dir, char **cpath)
 
             /* Search the cache */
             int unamelen = strlen(ret.u_name);
-            cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen); /* 14 */
+            cdir = dircache_search_by_name(vol, dir, ret.u_name, unamelen, ret.st.st_ctime); /* 14 */
             if (cdir == NULL) {
                 /* Not in cache, create one */
                 if ((cdir = dir_add(vol, dir, &ret, unamelen)) == NULL) { /* 15 */
@@ -2332,7 +2334,7 @@ int afp_mapid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *r
             return AFPERR_PARAM;
         LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request");
         uuidtype_t type;
-        len = getnamefromuuid( ibuf, &name, &type);
+        len = getnamefromuuid((unsigned char*) ibuf, &name, &type);
         if (len != 0)       /* its a error code, not len */
             return AFPERR_NOITEM;
         switch (type) {
@@ -2464,13 +2466,13 @@ int afp_mapname(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, siz
             break;
         case 5 :        /* username -> UUID */
             LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
-            if (0 != getuuidfromname(ibuf, UUID_USER, rbuf))
+            if (0 != getuuidfromname(ibuf, UUID_USER, (unsigned char *)rbuf))
                 return AFPERR_NOITEM;
             *rbuflen = UUID_BINSIZE;
             break;
         case 6 :        /* groupname -> UUID */
             LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf);
-            if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf))
+            if (0 != getuuidfromname(ibuf, UUID_GROUP, (unsigned char *)rbuf))
                 return AFPERR_NOITEM;
             *rbuflen = UUID_BINSIZE;
             break;
index c9e193d96b23034a7180faa3627c7a56173116fd..4b9ed48f3ac4ad13ef163e01e854cb4fd8d979f0 100644 (file)
@@ -109,7 +109,7 @@ struct maccess {
 typedef int (*dir_loop)(struct dirent *, char *, void *);
 
 extern struct dir *dir_new(const char *mname, const char *uname, const struct vol *,
-                           cnid_t pdid, cnid_t did, bstring fullpath); /* volume.c needs it once */
+                           cnid_t pdid, cnid_t did, bstring fullpath, time_t ctime);
 extern void        dir_free (struct dir *);
 extern struct dir  *dir_add(struct vol *, const struct dir *, struct path *, int);
 extern int         dir_modify(const struct vol *vol, struct dir *dir, cnid_t pdid, cnid_t did,
index 49625bdc2f0586d598ffe22715bc09e044bbf331..79869dbd0d84fc3256ca7ec8999b02a323f1950f 100644 (file)
@@ -19,6 +19,7 @@
 #include <atalk/adouble.h>
 #include <atalk/vfs.h>
 #include <atalk/cnid.h>
+#include <atalk/util.h>
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
 
@@ -268,10 +269,8 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
         return path_error(o_path, AFPERR_NODIR );
     }
 
-    LOG(log_debug, logtype_afpd, "enumerate(vid:%u, did:%u, cwddid:%u, cwd:'%s', name:'%s', f/d:%04x/%04x, rc:%u, i:%u, max:%u)",
-        ntohs(vid), ntohl(did), ntohl(curdir->d_did),
-        cfrombstr(curdir->d_fullpath), o_path->u_name,
-        fbitmap, dbitmap, reqcnt, sindex, maxsz);
+    LOG(log_debug, logtype_afpd, "enumerate(\"%s/%s\", f/d:%04x/%04x, rc:%u, i:%u, max:%u)",
+        getcwdpath(), o_path->u_name, fbitmap, dbitmap, reqcnt, sindex, maxsz);
 
     data = rbuf + 3 * sizeof( u_int16_t );
     sz = 3 * sizeof( u_int16_t );      /* fbitmap, dbitmap, reqcount */
@@ -375,7 +374,7 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
                 continue;
             }
             int len = strlen(s_path.u_name);
-            if ((dir = dircache_search_by_name(vol, curdir, s_path.u_name, len)) == NULL) {
+            if ((dir = dircache_search_by_name(vol, curdir, s_path.u_name, len, s_path.st.st_ctime)) == NULL) {
                 if ((dir = dir_add(vol, curdir, &s_path, len)) == NULL) {
                     LOG(log_error, logtype_afpd, "enumerate(vid:%u, did:%u, name:'%s'): error adding dir: '%s'",
                         ntohs(vid), ntohl(did), o_path->u_name, s_path.u_name);
@@ -389,6 +388,7 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_,
             if ( fbitmap == 0 ) {
                 continue;
             }
+            /* files are added to the dircache in getfilparams() -> getmetadata() */
             if (AFP_OK != ( ret = getfilparams(vol, fbitmap, &s_path, curdir, 
                                      data + header , &esz )) ) {
                 return( ret );
index 1528003b819a3a8bff18186402a9cb00e869d7aa..d3bf5600b36e1f68c91a15d3b1fadfe2eaa73f71 100644 (file)
@@ -326,7 +326,7 @@ int getmetadata(struct vol *vol,
         if (!path->id) {
             struct dir *cachedfile;
             int len = strlen(upath);
-            if ((cachedfile = dircache_search_by_name(vol, dir, upath, len)) != NULL)
+            if ((cachedfile = dircache_search_by_name(vol, dir, upath, len, st->st_ctime)) != NULL)
                 id = cachedfile->d_did;
             else {
                 id = get_id(vol, adp, st, dir->d_did, upath, len);
@@ -343,10 +343,11 @@ int getmetadata(struct vol *vol,
                     }
                 }
                 
-                if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, NULL)) == NULL) {
+                if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, NULL, st->st_ctime)) == NULL) {
                     LOG(log_error, logtype_afpd, "getmetadata: error from dir_new");
                     exit(EXITERR_SYS);
                 }
+
                 if ((dircache_add(cachedfile)) != 0) {
                     LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error");
                     exit(EXITERR_SYS);
@@ -2235,12 +2236,11 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U
     /* id's need switching. src -> dest and dest -> src. 
      * we need to re-stat() if it was a cross device copy.
     */
-    if (sid) {
-       cnid_delete(vol->v_cdb, sid);
-    }
-    if (did) {
-       cnid_delete(vol->v_cdb, did);
-    }
+    if (sid)
+        cnid_delete(vol->v_cdb, sid);
+    if (did)
+        cnid_delete(vol->v_cdb, did);
+
     if ((did && ( (crossdev && lstat( upath, &srcst) < 0) || 
                 cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
        ||
@@ -2334,5 +2334,11 @@ err_exchangefile:
        ad_close(addp, ADFLAGS_HF);
     }
 
+    struct dir *cached;
+    if ((cached = dircache_search_by_did(vol, sid)) != NULL)
+        (void)dir_remove(vol, cached);
+    if ((cached = dircache_search_by_did(vol, did)) != NULL)
+        (void)dir_remove(vol, cached);
+
     return err;
 }
index 16a32ef6af39a39f092c98bcb9ad75e058aafed4..be7056a796ab9c0729d1b8d4307c54ca5f3818d8 100644 (file)
@@ -463,12 +463,10 @@ static int moveandrename(const struct vol *vol,
 
         /* Remove it from the cache */
         struct dir *cacheddir = dircache_search_by_did(vol, id);
-        if (cacheddir == NULL) {
-            LOG(log_warning, logtype_afpd,"Not cached: \"%s/%s\"", getcwdpath(), upath);
-            rc = AFPERR_MISC;
-            goto exit;
+        if (cacheddir) {
+            LOG(log_warning, logtype_afpd,"Still cached: \"%s/%s\"", getcwdpath(), upath);
+            (void)dir_remove(vol, cacheddir);
         }
-        (void)dir_remove(vol, cacheddir);
 
         /* fix up the catalog entry */
         cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath));
@@ -608,7 +606,7 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size
             rc = deletefile(vol, -1, upath, 1);
 
             struct dir *cachedfile;
-            if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath)))) {
+            if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath), s_path->st.st_ctime))) {
                 dircache_remove(vol, cachedfile, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX);
                 dir_free(cachedfile);
             }
index 257ca3ec8b73948f9ea80529176b0f8b134b0cda..e4dc04108a90110c03e7ec3925c0c1f2ae083f15 100644 (file)
@@ -2172,7 +2172,8 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
                        volume,
                        DIRDID_ROOT_PARENT,
                        DIRDID_ROOT,
-                       bfromcstr(volume->v_path))
+                       bfromcstr(volume->v_path),
+                       st.st_ctime)
             ) == NULL) {
         free(vol_mname);
         LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) );
@@ -2180,7 +2181,6 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
         goto openvol_err;
     }
     free(vol_mname);
-
     volume->v_root = dir;
     curdir = dir;
 
index dd889dbb874018677e8dcc0861c4e2fe777101bf..079d01c3d054386a7541d1f2a5cb07d9823bec59 100644 (file)
@@ -58,7 +58,8 @@ struct dir {
     ucs2_t      *d_m_name_ucs2;       /* mac name as UCS2 */
     qnode_t     *qidx_node;           /* pointer to position in queue index */
     void        *d_ofork;             /* oforks using this directory. */
-    time_t      ctime;                /* inode ctime */
+    time_t      ctime;                /* inode ctime, used and modified by reenumeration */
+    time_t      ctime_dircache;       /* inode ctime, used and modified by dircache */
     int         d_flags;              /* directory flags */
     cnid_t      d_pdid;               /* CNID of parent directory */
     cnid_t      d_did;                /* CNID of directory */