diff options
author | Eric Sunshine <sunshine@sunshineco.com> | 2013-09-17 03:06:16 -0400 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2013-09-17 10:08:07 -0700 |
commit | d28eec267374c476de490bff736a627da94575c5 (patch) | |
tree | 00d7242d3d58faca44e07ac39237a9e87b7f3253 /name-hash.c | |
parent | ebbd7439b1b7cce0e8c68fe3e220d71cc58dd980 (diff) | |
download | git-d28eec267374c476de490bff736a627da94575c5.tar.gz |
name-hash: stop storing trailing '/' on paths in index_state.dir_hash
When 5102c617 (Add case insensitivity support for directories when using
git status, 2010-10-03) added directories to the name-hash there was
only a single hash table in which both real cache entries and leading
directory prefixes were registered. To distinguish between the two types
of entries, directories were stored with a trailing '/'.
2092678c (name-hash.c: fix endless loop with core.ignorecase=true,
2013-02-28), however, moved directories to a separate hash table
(index_state.dir_hash) but retained the (now) redundant trailing '/',
thus callers continue to bear the burden of ensuring the slash's
presence before searching the index for a directory. Eliminate this
redundancy by storing paths in the dir-hash without the trailing '/'.
An important benefit of this change is that it eliminates undocumented
and dangerous behavior of dir.c:directory_exists_in_index_icase() in
which it assumes not only that it can validly access one character
beyond the end of its incoming directory argument, but also that that
character will unconditionally be a '/'. This perilous behavior was
"tolerated" because the string passed in by its lone caller always had a
'/' in that position, however, things broke [1] when 2eac2a4c (ls-files
-k: a directory only can be killed if the index has a non-directory,
2013-08-15) added a new caller which failed to respect the undocumented
assumption.
[1]: http://thread.gmane.org/gmane.comp.version-control.git/232727
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'name-hash.c')
-rw-r--r-- | name-hash.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/name-hash.c b/name-hash.c index f06b049bb5..e5b6e1ad23 100644 --- a/name-hash.c +++ b/name-hash.c @@ -58,9 +58,9 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate, { /* * Throw each directory component in the hash for quick lookup - * during a git status. Directory components are stored with their + * during a git status. Directory components are stored without their * closing slash. Despite submodules being a directory, they never - * reach this point, because they are stored without a closing slash + * reach this point, because they are stored * in index_state.name_hash (as ordinary cache_entries). * * Note that the cache_entry stored with the dir_entry merely @@ -78,6 +78,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate, namelen--; if (namelen <= 0) return NULL; + namelen--; /* lookup existing entry for that directory */ dir = find_dir_entry(istate, ce->name, namelen); @@ -97,7 +98,7 @@ static struct dir_entry *hash_dir_entry(struct index_state *istate, } /* recursively add missing parent directories */ - dir->parent = hash_dir_entry(istate, ce, namelen - 1); + dir->parent = hash_dir_entry(istate, ce, namelen); } return dir; } @@ -237,7 +238,7 @@ struct cache_entry *index_dir_exists(struct index_state *istate, const char *nam * 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); + ce = index_file_exists(istate, name, namelen, 1); if (ce && S_ISGITLINK(ce->ce_mode)) return ce; @@ -265,7 +266,7 @@ struct cache_entry *index_file_exists(struct index_state *istate, const char *na 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_dir_exists(istate, name, namelen - 1); return index_file_exists(istate, name, namelen, icase); } |