name-hash: stop storing trailing '/' on paths in index_state.dir_hash
When5102c617
(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] when2eac2a4c
(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>
This commit is contained in:
parent
ebbd7439b1
commit
d28eec2673
2
dir.c
2
dir.c
@ -889,7 +889,7 @@ enum exist_status {
|
|||||||
*/
|
*/
|
||||||
static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
|
static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
|
||||||
{
|
{
|
||||||
const struct cache_entry *ce = cache_dir_exists(dirname, len + 1);
|
const struct cache_entry *ce = cache_dir_exists(dirname, len);
|
||||||
unsigned char endchar;
|
unsigned char endchar;
|
||||||
|
|
||||||
if (!ce)
|
if (!ce)
|
||||||
|
11
name-hash.c
11
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
|
* 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
|
* 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).
|
* in index_state.name_hash (as ordinary cache_entries).
|
||||||
*
|
*
|
||||||
* Note that the cache_entry stored with the dir_entry merely
|
* 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--;
|
namelen--;
|
||||||
if (namelen <= 0)
|
if (namelen <= 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
namelen--;
|
||||||
|
|
||||||
/* lookup existing entry for that directory */
|
/* lookup existing entry for that directory */
|
||||||
dir = find_dir_entry(istate, ce->name, namelen);
|
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 */
|
/* recursively add missing parent directories */
|
||||||
dir->parent = hash_dir_entry(istate, ce, namelen - 1);
|
dir->parent = hash_dir_entry(istate, ce, namelen);
|
||||||
}
|
}
|
||||||
return dir;
|
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
|
* in the dir-hash, submodules are stored in the name-hash, so check
|
||||||
* there, as well.
|
* 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))
|
if (ce && S_ISGITLINK(ce->ce_mode))
|
||||||
return ce;
|
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)
|
struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int icase)
|
||||||
{
|
{
|
||||||
if (namelen > 0 && name[namelen - 1] == '/')
|
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);
|
return index_file_exists(istate, name, namelen, icase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,7 +643,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
|
|||||||
if (*ptr == '/') {
|
if (*ptr == '/') {
|
||||||
struct cache_entry *foundce;
|
struct cache_entry *foundce;
|
||||||
++ptr;
|
++ptr;
|
||||||
foundce = index_dir_exists(istate, ce->name, ptr - ce->name);
|
foundce = index_dir_exists(istate, ce->name, ptr - ce->name - 1);
|
||||||
if (foundce) {
|
if (foundce) {
|
||||||
memcpy((void *)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr);
|
memcpy((void *)startPtr, foundce->name + (startPtr - ce->name), ptr - startPtr);
|
||||||
startPtr = ptr;
|
startPtr = ptr;
|
||||||
|
Loading…
Reference in New Issue
Block a user