From db5360f3f4966c4586d072bd1440880773185b81 Mon Sep 17 00:00:00 2001 From: Eric Sunshine Date: Tue, 17 Sep 2013 03:06:14 -0400 Subject: name-hash: refactor polymorphic index_name_exists() Depending upon the absence or presence of a trailing '/' on the incoming pathname, index_name_exists() checks either if a file is present in the index or if a directory is represented within the index. Each caller explicitly chooses the mode of operation by adding or removing a trailing '/' before invoking index_name_exists(). Since these two modes of operations are disjoint and have no code in common (one searches index_state.name_hash; the other dir_hash), they can be represented more naturally as distinct functions: one to search for a file, and one for a directory. Splitting index searching into two functions relieves callers of the artificial burden of having to add or remove a slash to select the mode of operation; instead they just call the desired function. A subsequent patch will take advantage of this benefit in order to eliminate the requirement that the incoming pathname for a directory search must have a trailing slash. (In order to avoid disturbing in-flight topics, index_name_exists() is retained as a thin wrapper dispatching either to index_dir_exists() or index_file_exists().) Signed-off-by: Eric Sunshine Signed-off-by: Junio C Hamano --- name-hash.c | 54 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 30 insertions(+), 24 deletions(-) (limited to 'name-hash.c') diff --git a/name-hash.c b/name-hash.c index 617c86c53..f06b049bb 100644 --- a/name-hash.c +++ b/name-hash.c @@ -222,7 +222,29 @@ static int same_name(const struct cache_entry *ce, const char *name, int namelen return slow_same_name(name, namelen, ce->name, len); } -struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase) +struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen) +{ + struct cache_entry *ce; + struct dir_entry *dir; + + lazy_init_name_hash(istate); + dir = find_dir_entry(istate, name, namelen); + if (dir && dir->nr) + return dir->ce; + + /* + * It might be a submodule. Unlike plain directories, which are stored + * in the dir-hash, submodules are stored in the name-hash, so check + * there, as well. + */ + ce = index_file_exists(istate, name, namelen - 1, 1); + if (ce && S_ISGITLINK(ce->ce_mode)) + return ce; + + return NULL; +} + +struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int icase) { unsigned int hash = hash_name(name, namelen); struct cache_entry *ce; @@ -237,32 +259,16 @@ struct cache_entry *index_name_exists(struct index_state *istate, const char *na } ce = ce->next; } - - /* - * When looking for a directory (trailing '/'), it might be a - * submodule or a directory. Despite submodules being directories, - * they are stored in the name hash without a closing slash. - * When ignore_case is 1, directories are stored in a separate hash - * table *with* their closing slash. - * - * The side effect of this storage technique is we have need to - * lookup the directory in a separate hash table, and if not found - * remove the slash from name and perform the lookup again without - * the slash. If a match is made, S_ISGITLINK(ce->mode) will be - * true. - */ - if (icase && name[namelen - 1] == '/') { - struct dir_entry *dir = find_dir_entry(istate, name, namelen); - if (dir && dir->nr) - return dir->ce; - - ce = index_name_exists(istate, name, namelen - 1, icase); - if (ce && S_ISGITLINK(ce->ce_mode)) - return ce; - } return NULL; } +struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase) +{ + if (namelen > 0 && name[namelen - 1] == '/') + return index_dir_exists(istate, name, namelen); + return index_file_exists(istate, name, namelen, icase); +} + static int free_dir_entry(void *entry, void *unused) { struct dir_entry *dir = entry; -- cgit v1.2.1