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:
committed by
Junio C Hamano
parent
443e061a41
commit
867f72bf43
75
symlinks.c
75
symlinks.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user