X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=symlinks.c;h=290036744bcfd390f91e75db49bf620bb12c12ea;hb=ee459baa5ce0a144e013a4995fd5be96bbecd05e;hp=88601200114f857a57214a9bf0d02ffd39a83504;hpb=03f94ae9f909952ed5a78917ab319a312889354b;p=git.git diff --git a/symlinks.c b/symlinks.c index 886012001..290036744 100644 --- a/symlinks.c +++ b/symlinks.c @@ -64,11 +64,13 @@ static inline void reset_lstat_cache(struct cache_def *cache) * 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(struct cache_def *cache, const char *name, int len, - int track_flags, int prefix_len_stat_func) +static int lstat_cache_matchlen(struct cache_def *cache, + const char *name, int len, + int *ret_flags, 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; + int save_flags, max_len, ret; struct stat st; if (cache->track_flags != track_flags || @@ -90,13 +92,13 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len, match_len = last_slash = longest_path_match(name, len, cache->path, cache->len, &previous_slash); - match_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK); + *ret_flags = cache->flags & track_flags & (FL_NOENT|FL_SYMLINK); if (!(track_flags & FL_FULLPATH) && match_len == len) match_len = last_slash = previous_slash; - if (match_flags && match_len == cache->len) - return match_flags; + if (*ret_flags && match_len == cache->len) + return match_len; /* * If we now have match_len > 0, we would know that * the matched part will always be a directory. @@ -105,16 +107,16 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len, * a substring of the cache on a path component basis, * we can return immediately. */ - match_flags = track_flags & FL_DIR; - if (match_flags && len == match_len) - return match_flags; + *ret_flags = track_flags & FL_DIR; + if (*ret_flags && len == match_len) + return match_len; } /* * Okay, no match from the cache so far, so now we have to * check the rest of the path components. */ - ret_flags = FL_DIR; + *ret_flags = FL_DIR; last_slash_dir = last_slash; max_len = len < PATH_MAX ? len : PATH_MAX; while (match_len < max_len) { @@ -133,16 +135,16 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len, ret = lstat(cache->path, &st); if (ret) { - ret_flags = FL_LSTATERR; + *ret_flags = FL_LSTATERR; if (errno == ENOENT) - ret_flags |= FL_NOENT; + *ret_flags |= FL_NOENT; } else if (S_ISDIR(st.st_mode)) { last_slash_dir = last_slash; continue; } else if (S_ISLNK(st.st_mode)) { - ret_flags = FL_SYMLINK; + *ret_flags = FL_SYMLINK; } else { - ret_flags = FL_ERR; + *ret_flags = FL_ERR; } break; } @@ -152,7 +154,7 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len, * path types, FL_NOENT, FL_SYMLINK and FL_DIR, can be cached * for the moment! */ - 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) { cache->path[last_slash] = '\0'; cache->len = last_slash; @@ -176,7 +178,16 @@ static int lstat_cache(struct cache_def *cache, const char *name, int len, } else { reset_lstat_cache(cache); } - return ret_flags; + return match_len; +} + +static int lstat_cache(struct cache_def *cache, const char *name, int len, + int track_flags, int prefix_len_stat_func) +{ + int flags; + (void)lstat_cache_matchlen(cache, name, len, &flags, track_flags, + prefix_len_stat_func); + return flags; } #define USE_ONLY_LSTAT 0 @@ -198,15 +209,39 @@ int has_symlink_leading_path(const char *name, int len) } /* - * Return non-zero if path 'name' has a leading symlink component or + * Return zero if path 'name' has a leading symlink component or * if some leading path component does not exists. + * + * Return -1 if leading path exists and is a directory. + * + * Return path length if leading path exists and is neither a + * directory nor a symlink. */ -int has_symlink_or_noent_leading_path(const char *name, int len) +int check_leading_path(const char *name, int 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); + return threaded_check_leading_path(&default_cache, name, len); +} + +/* + * Return zero if path 'name' has a leading symlink component or + * if some leading path component does not exists. + * + * Return -1 if leading path exists and is a directory. + * + * Return path length if leading path exists and is neither a + * directory nor a symlink. + */ +int threaded_check_leading_path(struct cache_def *cache, const char *name, int len) +{ + int flags; + int match_len = lstat_cache_matchlen(cache, name, len, &flags, + FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT); + if (flags & FL_NOENT) + return 0; + else if (flags & FL_DIR) + return -1; + else + return match_len; } /* @@ -218,7 +253,18 @@ 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) { - struct cache_def *cache = &default_cache; /* FIXME */ + return threaded_has_dirs_only_path(&default_cache, name, len, prefix_len); +} + +/* + * Return non-zero if all path components of 'name' exists as a + * directory. If prefix_len > 0, we will test with the stat() + * function instead of the lstat() function for a prefix length of + * 'prefix_len', thus we then allow for symlinks in the prefix part as + * long as those points to real existing directories. + */ +int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len) +{ return lstat_cache(cache, name, len, FL_DIR|FL_FULLPATH, prefix_len) & FL_DIR;