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