Prepare symlink caching for thread-safety

This doesn't actually change the external interfaces, so they are still
thread-unsafe, but it makes the code internally pass a pointer to a
local 'struct cache_def' around, so that the core code can be made
thread-safe.

The threaded index preloading will want to verify that the paths leading
up to a pathname are all real directories.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Linus Torvalds 2009-07-09 13:23:59 -07:00 committed by Junio C Hamano
parent 443e061a41
commit 867f72bf43

View File

@ -38,13 +38,13 @@ static struct cache_def {
int flags;
int track_flags;
int prefix_len_stat_func;
} cache;
} default_cache;
static inline void reset_lstat_cache(void)
static inline void reset_lstat_cache(struct cache_def *cache)
{
cache.path[0] = '\0';
cache.len = 0;
cache.flags = 0;
cache->path[0] = '\0';
cache->len = 0;
cache->flags = 0;
/*
* The track_flags and prefix_len_stat_func members is only
* set by the safeguard rule inside lstat_cache()
@ -70,23 +70,23 @@ static inline void reset_lstat_cache(void)
* of the prefix, where the cache should use the stat() function
* instead of the lstat() function to test each path component.
*/
static int lstat_cache(const char *name, int len,
static int lstat_cache(struct cache_def *cache, const char *name, int len,
int track_flags, int prefix_len_stat_func)
{
int match_len, last_slash, last_slash_dir, previous_slash;
int match_flags, ret_flags, save_flags, max_len, ret;
struct stat st;
if (cache.track_flags != track_flags ||
cache.prefix_len_stat_func != prefix_len_stat_func) {
if (cache->track_flags != track_flags ||
cache->prefix_len_stat_func != prefix_len_stat_func) {
/*
* As a safeguard rule we clear the cache if the
* values of track_flags and/or prefix_len_stat_func
* does not match with the last supplied values.
*/
reset_lstat_cache();
cache.track_flags = track_flags;
cache.prefix_len_stat_func = prefix_len_stat_func;
reset_lstat_cache(cache);
cache->track_flags = track_flags;
cache->prefix_len_stat_func = prefix_len_stat_func;
match_len = last_slash = 0;
} else {
/*
@ -94,10 +94,10 @@ static int lstat_cache(const char *name, int len,
* the 2 "excluding" path types.
*/
match_len = last_slash =
longest_path_match(name, len, cache.path, cache.len,
longest_path_match(name, len, cache->path, cache->len,
&previous_slash);
match_flags = cache.flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (match_flags && match_len == cache.len)
match_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (match_flags && match_len == cache->len)
return match_flags;
/*
* If we now have match_len > 0, we would know that
@ -121,18 +121,18 @@ static int lstat_cache(const char *name, int len,
max_len = len < PATH_MAX ? len : PATH_MAX;
while (match_len < max_len) {
do {
cache.path[match_len] = name[match_len];
cache->path[match_len] = name[match_len];
match_len++;
} while (match_len < max_len && name[match_len] != '/');
if (match_len >= max_len && !(track_flags & FL_FULLPATH))
break;
last_slash = match_len;
cache.path[last_slash] = '\0';
cache->path[last_slash] = '\0';
if (last_slash <= prefix_len_stat_func)
ret = stat(cache.path, &st);
ret = stat(cache->path, &st);
else
ret = lstat(cache.path, &st);
ret = lstat(cache->path, &st);
if (ret) {
ret_flags = FL_LSTATERR;
@ -156,9 +156,9 @@ static int lstat_cache(const char *name, int len,
*/
save_flags = ret_flags & track_flags & (FL_NOENT|FL_SYMLINK);
if (save_flags && last_slash > 0 && last_slash <= PATH_MAX) {
cache.path[last_slash] = '\0';
cache.len = last_slash;
cache.flags = save_flags;
cache->path[last_slash] = '\0';
cache->len = last_slash;
cache->flags = save_flags;
} else if ((track_flags & FL_DIR) &&
last_slash_dir > 0 && last_slash_dir <= PATH_MAX) {
/*
@ -172,11 +172,11 @@ static int lstat_cache(const char *name, int len,
* can still cache the path components before the last
* one (the found symlink or non-existing component).
*/
cache.path[last_slash_dir] = '\0';
cache.len = last_slash_dir;
cache.flags = FL_DIR;
cache->path[last_slash_dir] = '\0';
cache->len = last_slash_dir;
cache->flags = FL_DIR;
} else {
reset_lstat_cache();
reset_lstat_cache(cache);
}
return ret_flags;
}
@ -188,16 +188,17 @@ static int lstat_cache(const char *name, int len,
void invalidate_lstat_cache(const char *name, int len)
{
int match_len, previous_slash;
struct cache_def *cache = &default_cache; /* FIXME */
match_len = longest_path_match(name, len, cache.path, cache.len,
match_len = longest_path_match(name, len, cache->path, cache->len,
&previous_slash);
if (len == match_len) {
if ((cache.track_flags & FL_DIR) && previous_slash > 0) {
cache.path[previous_slash] = '\0';
cache.len = previous_slash;
cache.flags = FL_DIR;
if ((cache->track_flags & FL_DIR) && previous_slash > 0) {
cache->path[previous_slash] = '\0';
cache->len = previous_slash;
cache->flags = FL_DIR;
} else {
reset_lstat_cache();
reset_lstat_cache(cache);
}
}
}
@ -207,7 +208,8 @@ void invalidate_lstat_cache(const char *name, int len)
*/
void clear_lstat_cache(void)
{
reset_lstat_cache();
struct cache_def *cache = &default_cache; /* FIXME */
reset_lstat_cache(cache);
}
#define USE_ONLY_LSTAT 0
@ -217,7 +219,8 @@ void clear_lstat_cache(void)
*/
int has_symlink_leading_path(const char *name, int len)
{
return lstat_cache(name, len,
struct cache_def *cache = &default_cache; /* FIXME */
return lstat_cache(cache, name, len,
FL_SYMLINK|FL_DIR, USE_ONLY_LSTAT) &
FL_SYMLINK;
}
@ -228,7 +231,8 @@ int has_symlink_leading_path(const char *name, int len)
*/
int has_symlink_or_noent_leading_path(const char *name, int len)
{
return lstat_cache(name, len,
struct cache_def *cache = &default_cache; /* FIXME */
return lstat_cache(cache, name, len,
FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT) &
(FL_SYMLINK|FL_NOENT);
}
@ -242,7 +246,8 @@ int has_symlink_or_noent_leading_path(const char *name, int len)
*/
int has_dirs_only_path(const char *name, int len, int prefix_len)
{
return lstat_cache(name, len,
struct cache_def *cache = &default_cache; /* FIXME */
return lstat_cache(cache, name, len,
FL_DIR|FL_FULLPATH, prefix_len) &
FL_DIR;
}