diff options
author | Andreas Gruenbacher <agruen@gnu.org> | 2015-03-01 01:08:54 +0100 |
---|---|---|
committer | Andreas Gruenbacher <agruen@gnu.org> | 2015-03-05 22:57:44 +0100 |
commit | 914d06b7c3cc613df7617fae5903dbcaee601d5d (patch) | |
tree | 9a4a29613430c5059beb7fa1d43376fdf7901974 | |
parent | c5705fd476957f0854bc0d7dbd05e444f8f73760 (diff) | |
download | patch-914d06b7c3cc613df7617fae5903dbcaee601d5d.tar.gz |
Invalidate child dirfd cache entries when their parent goes away
If we don't do that, a directory could be removed from the cache, a new
directory with the same dirfd could be created, and the entries from the old
directory would appear in the new directory.
* src/safe.c (struct cached_dirfd): Keep track of the children of each dirfd
cache entry.
(remove_cached_dirfd): Remove all the entry's children from the lookup hash,
take them off the list of children, and initialize the children's
children_link. Then, remove the entry itself from its parent. This has no
effect if the entry doesn't have a parent because then, children_link is empty.
(openat_cached): Add new dirfd cache entries to their parent's list of children
and initialize the entry's list of children.
(traverse_another_path): Also initialize cwd's list of children.
-rw-r--r-- | src/safe.c | 13 |
1 files changed, 13 insertions, 0 deletions
@@ -55,6 +55,7 @@ unsigned long dirfd_cache_misses; struct cached_dirfd { struct list_head lru_link; + struct list_head children_link, children; struct cached_dirfd *parent; char *name; @@ -124,6 +125,14 @@ static struct cached_dirfd *lookup_cached_dirfd (struct cached_dirfd *dir, const static void remove_cached_dirfd (struct cached_dirfd *entry) { + while (! list_empty (&entry->children)) + { + struct cached_dirfd *child = + list_entry (entry->children.next, struct cached_dirfd, children_link); + list_del_init (&child->children_link); + hash_delete (cached_dirfds, child); + } + list_del (&entry->children_link); list_del (&entry->lru_link); hash_delete (cached_dirfds, entry); free_cached_dirfd (entry); @@ -208,6 +217,8 @@ static struct cached_dirfd *openat_cached (struct cached_dirfd *dir, const char /* Store new cache entry */ entry = xmalloc (sizeof (struct cached_dirfd)); INIT_LIST_HEAD (&entry->lru_link); + list_add (&entry->children_link, &dir->children); + INIT_LIST_HEAD (&entry->children); entry->parent = dir; entry->name = xstrdup (name); entry->fd = fd; @@ -358,6 +369,8 @@ static int traverse_another_path (const char **pathname, int keepfd) struct symlink *stack = NULL; unsigned int steps = count_path_components (path); + INIT_LIST_HEAD (&cwd.children); + if (steps > MAX_PATH_COMPONENTS) { errno = ELOOP; |