4 * Hashing names in the index state
6 * Copyright (C) 2008 Linus Torvalds
8 #define NO_THE_INDEX_COMPATIBILITY_MACROS
12 * This removes bit 5 if bit 6 is set.
14 * That will make US-ASCII characters hash to their upper-case
15 * equivalent. We could easily do this one whole word at a time,
16 * but that's for future worries.
18 static inline unsigned char icase_hash(unsigned char c
)
20 return c
& ~((c
& 0x40) >> 1);
23 static unsigned int hash_name(const char *name
, int namelen
)
25 unsigned int hash
= 0x123;
28 unsigned char c
= *name
++;
35 static void hash_index_entry_directories(struct index_state
*istate
, struct cache_entry
*ce
)
38 * Throw each directory component in the hash for quick lookup
39 * during a git status. Directory components are stored with their
40 * closing slash. Despite submodules being a directory, they never
41 * reach this point, because they are stored without a closing slash
44 * Note that the cache_entry stored with the directory does not
45 * represent the directory itself. It is a pointer to an existing
46 * filename, and its only purpose is to represent existence of the
47 * directory in the cache. It is very possible multiple directory
48 * hash entries may point to the same cache_entry.
53 const char *ptr
= ce
->name
;
55 while (*ptr
&& *ptr
!= '/')
59 hash
= hash_name(ce
->name
, ptr
- ce
->name
);
60 if (!lookup_hash(hash
, &istate
->name_hash
)) {
61 pos
= insert_hash(hash
, ce
, &istate
->name_hash
);
71 static void hash_index_entry(struct index_state
*istate
, struct cache_entry
*ce
)
76 if (ce
->ce_flags
& CE_HASHED
)
78 ce
->ce_flags
|= CE_HASHED
;
80 hash
= hash_name(ce
->name
, ce_namelen(ce
));
81 pos
= insert_hash(hash
, ce
, &istate
->name_hash
);
88 hash_index_entry_directories(istate
, ce
);
91 static void lazy_init_name_hash(struct index_state
*istate
)
95 if (istate
->name_hash_initialized
)
97 for (nr
= 0; nr
< istate
->cache_nr
; nr
++)
98 hash_index_entry(istate
, istate
->cache
[nr
]);
99 istate
->name_hash_initialized
= 1;
102 void add_name_hash(struct index_state
*istate
, struct cache_entry
*ce
)
104 ce
->ce_flags
&= ~CE_UNHASHED
;
105 if (istate
->name_hash_initialized
)
106 hash_index_entry(istate
, ce
);
109 static int slow_same_name(const char *name1
, int len1
, const char *name2
, int len2
)
115 unsigned char c1
= *name1
++;
116 unsigned char c2
= *name2
++;
128 static int same_name(const struct cache_entry
*ce
, const char *name
, int namelen
, int icase
)
130 int len
= ce_namelen(ce
);
133 * Always do exact compare, even if we want a case-ignoring comparison;
134 * we do the quick exact one first, because it will be the common case.
136 if (len
== namelen
&& !cache_name_compare(name
, namelen
, ce
->name
, len
))
143 * If the entry we're comparing is a filename (no trailing slash), then compare
144 * the lengths exactly.
146 if (name
[namelen
- 1] != '/')
147 return slow_same_name(name
, namelen
, ce
->name
, len
);
150 * For a directory, we point to an arbitrary cache_entry filename. Just
151 * make sure the directory portion matches.
153 return slow_same_name(name
, namelen
, ce
->name
, namelen
< len
? namelen
: len
);
156 struct cache_entry
*index_name_exists(struct index_state
*istate
, const char *name
, int namelen
, int icase
)
158 unsigned int hash
= hash_name(name
, namelen
);
159 struct cache_entry
*ce
;
161 lazy_init_name_hash(istate
);
162 ce
= lookup_hash(hash
, &istate
->name_hash
);
165 if (!(ce
->ce_flags
& CE_UNHASHED
)) {
166 if (same_name(ce
, name
, namelen
, icase
))
173 * Might be a submodule. Despite submodules being directories,
174 * they are stored in the name hash without a closing slash.
175 * When ignore_case is 1, directories are stored in the name hash
176 * with their closing slash.
178 * The side effect of this storage technique is we have need to
179 * remove the slash from name and perform the lookup again without
180 * the slash. If a match is made, S_ISGITLINK(ce->mode) will be
183 if (icase
&& name
[namelen
- 1] == '/') {
184 ce
= index_name_exists(istate
, name
, namelen
- 1, icase
);
185 if (ce
&& S_ISGITLINK(ce
->ce_mode
))