]> arthur.barton.de Git - netatalk.git/commitdiff
Protect dircache from duplicates
authorFrank Lahm <franklahm@googlemail.com>
Fri, 25 Mar 2011 16:07:31 +0000 (17:07 +0100)
committerFrank Lahm <franklahm@googlemail.com>
Fri, 25 Mar 2011 16:07:31 +0000 (17:07 +0100)
etc/afpd/dircache.c
etc/afpd/dircache.h
etc/afpd/directory.c
etc/afpd/file.c

index 0cc751d2fa595289a753c1194eb7a9e4f79f772e..53359ed451652731c183fcfc63e1f7b829d94ffa 100644 (file)
@@ -365,7 +365,11 @@ struct dir *dircache_search_by_did(const struct vol *vol, cnid_t cnid)
  *
  * @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, time_t ctime)
+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;
@@ -421,19 +425,45 @@ struct dir *dircache_search_by_name(const struct vol *vol, const struct dir *dir
  *
  * @returns 0 on success, -1 on error which should result in an abort
  */
-int dircache_add(struct dir *dir)
+int dircache_add(const struct vol *vol,
+                 struct dir *dir)
 {
-   AFP_ASSERT(dir);
-   AFP_ASSERT(ntohl(dir->d_pdid) >= 2);
-   AFP_ASSERT(ntohl(dir->d_did) >= CNID_START);
-   AFP_ASSERT(dir->d_u_name);
-   AFP_ASSERT(dir->d_vid);
-   AFP_ASSERT(dircache->hash_nodecount <= dircache_maxsize);
+    struct dir *cdir = NULL;
+    struct dir key;
+    hnode_t *hn;
+
+    AFP_ASSERT(dir);
+    AFP_ASSERT(ntohl(dir->d_pdid) >= 2);
+    AFP_ASSERT(ntohl(dir->d_did) >= CNID_START);
+    AFP_ASSERT(dir->d_u_name);
+    AFP_ASSERT(dir->d_vid);
+    AFP_ASSERT(dircache->hash_nodecount <= dircache_maxsize);
 
     /* Check if cache is full */
     if (dircache->hash_nodecount == dircache_maxsize)
         dircache_evict();
 
+    /* 
+     * Make sure we don't add duplicates
+     */
+
+    /* Search primary cache by CNID */
+    key.d_vid = dir->d_vid;
+    key.d_did = dir->d_did;
+    if ((hn = hash_lookup(dircache, &key))) {
+        /* Found an entry with the same CNID, delete it */
+        dir_remove(vol, hnode_get(hn));
+        dircache_stat.expunged++;
+    }
+    key.d_vid = vol->v_vid;
+    key.d_pdid = dir->d_did;
+    key.d_u_name = dir->d_u_name;
+    if ((hn = hash_lookup(index_didname, &key))) {
+        /* Found an entry with the same DID/name, delete it */
+        dir_remove(vol, hnode_get(hn));
+        dircache_stat.expunged++;
+    }
+
     /* Add it to the main dircache */
     if (hash_alloc_insert(dircache, dir, dir) == 0) {
         dircache_dump();
index 69c5f9abebd40ae197cecae82a60f4421d81ae98..16c2df1dbde26ab5d3d994d429172a98fa9bcc7a 100644 (file)
@@ -32,7 +32,7 @@
 #define DIRCACHE_ALL  (DIRCACHE|DIDNAME_INDEX|QUEUE_INDEX)
 
 extern int        dircache_init(int reqsize);
-extern int        dircache_add(struct dir *);
+extern int        dircache_add(const struct vol *, 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, time_t ctime);
index c90ebe1bedf56f8574d17549a640c2f74858fb97..2987985dbba920dfe759e084b8969c3b481a3aec 100644 (file)
@@ -573,7 +573,7 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did)
     }
     
     /* Add it to the cache only if it's a dir */
-    if (dircache_add(ret) != 0) { /* 7 */
+    if (dircache_add(vol, ret) != 0) { /* 7 */
         err = 1;
         goto exit;
     }
@@ -837,7 +837,7 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i
         goto exit;
     }
 
-    if ((dircache_add(cdir)) != 0) { /* 4 */
+    if ((dircache_add(vol, cdir)) != 0) { /* 4 */
         LOG(log_error, logtype_afpd, "dir_add: fatal dircache error: %s", cfrombstr(fullpath));
         exit(EXITERR_SYS);
     }
@@ -917,6 +917,7 @@ int dir_remove(const struct vol *vol, struct dir *dir)
     return 0;
 }
 
+#if 0 /* unused */
 /*!
  * @brief Modify a struct dir, adjust cache
  *
@@ -988,13 +989,14 @@ int dir_modify(const struct vol *vol,
         dir->d_m_name_ucs2 = NULL;
 
     /* Re-add it to the cache */
-    if ((dircache_add(dir)) != 0) {
+    if ((dircache_add(vol, dir)) != 0) {
         dircache_dump();
         AFP_PANIC("dir_modify");
     }
 
     return ret;
 }
+#endif
 
 /*!
  * @brief Resolve a catalog node name path
index 6888182fd41f755807e3e8f2c0f5d27a77b7f26e..f7df604982f3b966f102d96125479c358f5952a4 100644 (file)
@@ -350,7 +350,7 @@ int getmetadata(struct vol *vol,
                     exit(EXITERR_SYS);
                 }
 
-                if ((dircache_add(cachedfile)) != 0) {
+                if ((dircache_add(vol, cachedfile)) != 0) {
                     LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error");
                     exit(EXITERR_SYS);
                 }