mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-09 20:29:27 +00:00
git_path_dirload_with_stat: moved to fs_iterator
This commit is contained in:
parent
ba8ef18a53
commit
7ef005f165
123
src/iterator.c
123
src/iterator.c
@ -920,12 +920,31 @@ struct fs_iterator {
|
||||
|
||||
#define FS_MAX_DEPTH 100
|
||||
|
||||
typedef struct {
|
||||
struct stat st;
|
||||
size_t path_len;
|
||||
char path[GIT_FLEX_ARRAY];
|
||||
} fs_iterator_path_with_stat;
|
||||
|
||||
static int fs_iterator_path_with_stat_cmp(const void *a, const void *b)
|
||||
{
|
||||
const fs_iterator_path_with_stat *psa = a, *psb = b;
|
||||
return strcmp(psa->path, psb->path);
|
||||
}
|
||||
|
||||
static int fs_iterator_path_with_stat_cmp_icase(const void *a, const void *b)
|
||||
{
|
||||
const fs_iterator_path_with_stat *psa = a, *psb = b;
|
||||
return strcasecmp(psa->path, psb->path);
|
||||
}
|
||||
|
||||
static fs_iterator_frame *fs_iterator__alloc_frame(fs_iterator *fi)
|
||||
{
|
||||
fs_iterator_frame *ff = git__calloc(1, sizeof(fs_iterator_frame));
|
||||
git_vector_cmp entry_compare = CASESELECT(
|
||||
iterator__ignore_case(fi),
|
||||
git_path_with_stat_cmp_icase, git_path_with_stat_cmp);
|
||||
fs_iterator_path_with_stat_cmp_icase,
|
||||
fs_iterator_path_with_stat_cmp);
|
||||
|
||||
if (ff && git_vector_init(&ff->entries, 0, entry_compare) < 0) {
|
||||
git__free(ff);
|
||||
@ -967,7 +986,7 @@ static int fs_iterator__advance_over(
|
||||
static int fs_iterator__entry_cmp(const void *i, const void *item)
|
||||
{
|
||||
const fs_iterator *fi = (const fs_iterator *)i;
|
||||
const git_path_with_stat *ps = item;
|
||||
const fs_iterator_path_with_stat *ps = item;
|
||||
return fi->base.prefixcomp(fi->base.start, ps->path);
|
||||
}
|
||||
|
||||
@ -984,6 +1003,96 @@ static void fs_iterator__seek_frame_start(
|
||||
ff->index = 0;
|
||||
}
|
||||
|
||||
static int dirload_with_stat(
|
||||
const char *dirpath,
|
||||
size_t prefix_len,
|
||||
unsigned int flags,
|
||||
const char *start_stat,
|
||||
const char *end_stat,
|
||||
git_vector *contents)
|
||||
{
|
||||
git_path_diriter diriter = {0};
|
||||
const char *path;
|
||||
int (*strncomp)(const char *a, const char *b, size_t sz);
|
||||
size_t start_len = start_stat ? strlen(start_stat) : 0;
|
||||
size_t end_len = end_stat ? strlen(end_stat) : 0;
|
||||
fs_iterator_path_with_stat *ps;
|
||||
size_t path_len, cmp_len, ps_size;
|
||||
int error;
|
||||
|
||||
strncomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ?
|
||||
git__strncasecmp : git__strncmp;
|
||||
|
||||
if ((error = git_path_diriter_init(&diriter, dirpath, flags)) < 0)
|
||||
goto done;
|
||||
|
||||
while ((error = git_path_diriter_next(&path, &path_len, &diriter)) == 0) {
|
||||
if ((error = git_path_diriter_fullpath(&path, &path_len, &diriter)) < 0)
|
||||
goto done;
|
||||
|
||||
assert(path_len > prefix_len);
|
||||
|
||||
/* remove the prefix if requested */
|
||||
path += prefix_len;
|
||||
path_len -= prefix_len;
|
||||
|
||||
/* skip if before start_stat or after end_stat */
|
||||
cmp_len = min(start_len, path_len);
|
||||
if (cmp_len && strncomp(path, start_stat, cmp_len) < 0)
|
||||
continue;
|
||||
cmp_len = min(end_len, path_len);
|
||||
if (cmp_len && strncomp(path, end_stat, cmp_len) > 0)
|
||||
continue;
|
||||
|
||||
/* Make sure to append two bytes, one for the path's null
|
||||
* termination, one for a possible trailing '/' for folders.
|
||||
*/
|
||||
GITERR_CHECK_ALLOC_ADD(&ps_size, sizeof(fs_iterator_path_with_stat), path_len);
|
||||
GITERR_CHECK_ALLOC_ADD(&ps_size, ps_size, 2);
|
||||
|
||||
ps = git__calloc(1, ps_size);
|
||||
ps->path_len = path_len;
|
||||
|
||||
memcpy(ps->path, path, path_len);
|
||||
|
||||
if ((error = git_path_diriter_stat(&ps->st, &diriter)) < 0) {
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
/* file was removed between readdir and lstat */
|
||||
git__free(ps);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Treat the file as unreadable if we get any other error */
|
||||
memset(&ps->st, 0, sizeof(ps->st));
|
||||
ps->st.st_mode = GIT_FILEMODE_UNREADABLE;
|
||||
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
} else if (S_ISDIR(ps->st.st_mode)) {
|
||||
/* Suffix directory paths with a '/' */
|
||||
ps->path[ps->path_len++] = '/';
|
||||
ps->path[ps->path_len] = '\0';
|
||||
} else if(!S_ISREG(ps->st.st_mode) && !S_ISLNK(ps->st.st_mode)) {
|
||||
/* Ignore wacky things in the filesystem */
|
||||
git__free(ps);
|
||||
continue;
|
||||
}
|
||||
|
||||
git_vector_insert(contents, ps);
|
||||
}
|
||||
|
||||
if (error == GIT_ITEROVER)
|
||||
error = 0;
|
||||
|
||||
/* sort now that directory suffix is added */
|
||||
git_vector_sort(contents);
|
||||
|
||||
done:
|
||||
git_path_diriter_free(&diriter);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int fs_iterator__expand_dir(fs_iterator *fi)
|
||||
{
|
||||
int error;
|
||||
@ -998,7 +1107,7 @@ static int fs_iterator__expand_dir(fs_iterator *fi)
|
||||
ff = fs_iterator__alloc_frame(fi);
|
||||
GITERR_CHECK_ALLOC(ff);
|
||||
|
||||
error = git_path_dirload_with_stat(
|
||||
error = dirload_with_stat(
|
||||
fi->path.ptr, fi->root_len, fi->dirload_flags,
|
||||
fi->base.start, fi->base.end, &ff->entries);
|
||||
|
||||
@ -1086,7 +1195,7 @@ static int fs_iterator__advance_over(
|
||||
int error = 0;
|
||||
fs_iterator *fi = (fs_iterator *)self;
|
||||
fs_iterator_frame *ff;
|
||||
git_path_with_stat *next;
|
||||
fs_iterator_path_with_stat *next;
|
||||
|
||||
if (entry != NULL)
|
||||
*entry = NULL;
|
||||
@ -1176,7 +1285,7 @@ static void fs_iterator__free(git_iterator *self)
|
||||
|
||||
static int fs_iterator__update_entry(fs_iterator *fi)
|
||||
{
|
||||
git_path_with_stat *ps;
|
||||
fs_iterator_path_with_stat *ps;
|
||||
|
||||
memset(&fi->entry, 0, sizeof(fi->entry));
|
||||
|
||||
@ -1307,7 +1416,7 @@ GIT_INLINE(bool) workdir_path_is_dotgit(const git_buf *path)
|
||||
* We consider it a submodule if the path is listed as a submodule in
|
||||
* either the tree or the index.
|
||||
*/
|
||||
static int is_submodule(workdir_iterator *wi, git_path_with_stat *ie)
|
||||
static int is_submodule(workdir_iterator *wi, fs_iterator_path_with_stat *ie)
|
||||
{
|
||||
int error, is_submodule = 0;
|
||||
|
||||
@ -1360,7 +1469,7 @@ static int workdir_iterator__enter_dir(fs_iterator *fi)
|
||||
workdir_iterator *wi = (workdir_iterator *)fi;
|
||||
fs_iterator_frame *ff = fi->stack;
|
||||
size_t pos;
|
||||
git_path_with_stat *entry;
|
||||
fs_iterator_path_with_stat *entry;
|
||||
bool found_submodules = false;
|
||||
|
||||
git_dir_flag dir_flag = git_entry__dir_flag(&fi->entry);
|
||||
|
127
src/path.c
127
src/path.c
@ -1078,49 +1078,6 @@ int git_path_direach(
|
||||
return error;
|
||||
}
|
||||
|
||||
static int entry_path_alloc(
|
||||
char **out,
|
||||
const char *path,
|
||||
size_t path_len,
|
||||
const char *de_path,
|
||||
size_t de_len,
|
||||
size_t alloc_extra)
|
||||
{
|
||||
int need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0;
|
||||
size_t alloc_size;
|
||||
char *entry_path;
|
||||
|
||||
GITERR_CHECK_ALLOC_ADD(&alloc_size, path_len, de_len);
|
||||
GITERR_CHECK_ALLOC_ADD(&alloc_size, alloc_size, need_slash);
|
||||
GITERR_CHECK_ALLOC_ADD(&alloc_size, alloc_size, 1);
|
||||
GITERR_CHECK_ALLOC_ADD(&alloc_size, alloc_size, alloc_extra);
|
||||
entry_path = git__calloc(1, alloc_size);
|
||||
GITERR_CHECK_ALLOC(entry_path);
|
||||
|
||||
if (path_len)
|
||||
memcpy(entry_path, path, path_len);
|
||||
|
||||
if (need_slash)
|
||||
entry_path[path_len] = '/';
|
||||
|
||||
memcpy(&entry_path[path_len + need_slash], de_path, de_len);
|
||||
|
||||
*out = entry_path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_path_with_stat_cmp(const void *a, const void *b)
|
||||
{
|
||||
const git_path_with_stat *psa = a, *psb = b;
|
||||
return strcmp(psa->path, psb->path);
|
||||
}
|
||||
|
||||
int git_path_with_stat_cmp_icase(const void *a, const void *b)
|
||||
{
|
||||
const git_path_with_stat *psa = a, *psb = b;
|
||||
return strcasecmp(psa->path, psb->path);
|
||||
}
|
||||
|
||||
int git_path_diriter_init(
|
||||
git_path_diriter *diriter,
|
||||
const char *path,
|
||||
@ -1277,90 +1234,6 @@ int git_path_dirload(
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_path_dirload_with_stat(
|
||||
const char *dirpath,
|
||||
size_t prefix_len,
|
||||
unsigned int flags,
|
||||
const char *start_stat,
|
||||
const char *end_stat,
|
||||
git_vector *contents)
|
||||
{
|
||||
git_path_diriter diriter = {0};
|
||||
const char *path;
|
||||
int (*strncomp)(const char *a, const char *b, size_t sz);
|
||||
size_t start_len = start_stat ? strlen(start_stat) : 0;
|
||||
size_t end_len = end_stat ? strlen(end_stat) : 0;
|
||||
git_path_with_stat *ps;
|
||||
size_t path_len, cmp_len, ps_size;
|
||||
int error;
|
||||
|
||||
strncomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ?
|
||||
git__strncasecmp : git__strncmp;
|
||||
|
||||
if ((error = git_path_diriter_init(&diriter, dirpath, flags)) < 0)
|
||||
goto done;
|
||||
|
||||
while ((error = git_path_diriter_next(&path, &path_len, &diriter)) == 0) {
|
||||
if ((error = git_path_diriter_fullpath(&path, &path_len, &diriter)) < 0)
|
||||
goto done;
|
||||
|
||||
assert(path_len > prefix_len);
|
||||
|
||||
/* remove the prefix if requested */
|
||||
path += prefix_len;
|
||||
path_len -= prefix_len;
|
||||
|
||||
/* skip if before start_stat or after end_stat */
|
||||
cmp_len = min(start_len, path_len);
|
||||
if (cmp_len && strncomp(path, start_stat, cmp_len) < 0)
|
||||
continue;
|
||||
cmp_len = min(end_len, path_len);
|
||||
if (cmp_len && strncomp(path, end_stat, cmp_len) > 0)
|
||||
continue;
|
||||
|
||||
GITERR_CHECK_ALLOC_ADD(&ps_size, sizeof(git_path_with_stat), path_len);
|
||||
GITERR_CHECK_ALLOC_ADD(&ps_size, ps_size, 2);
|
||||
|
||||
ps = git__calloc(1, ps_size);
|
||||
ps->path_len = path_len;
|
||||
|
||||
memcpy(ps->path, path, path_len);
|
||||
|
||||
if ((error = git_path_diriter_stat(&ps->st, &diriter)) < 0) {
|
||||
if (error == GIT_ENOTFOUND) {
|
||||
/* file was removed between readdir and lstat */
|
||||
git__free(ps);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Treat the file as unreadable if we get any other error */
|
||||
memset(&ps->st, 0, sizeof(ps->st));
|
||||
ps->st.st_mode = GIT_FILEMODE_UNREADABLE;
|
||||
|
||||
giterr_clear();
|
||||
error = 0;
|
||||
} else if (S_ISDIR(ps->st.st_mode)) {
|
||||
/* Suffix directory paths with a '/' */
|
||||
ps->path[ps->path_len++] = '/';
|
||||
ps->path[ps->path_len] = '\0';
|
||||
} else if(!S_ISREG(ps->st.st_mode) && !S_ISLNK(ps->st.st_mode)) {
|
||||
/* Ignore wacky things in the filesystem */
|
||||
}
|
||||
|
||||
git_vector_insert(contents, ps);
|
||||
}
|
||||
|
||||
if (error == GIT_ITEROVER)
|
||||
error = 0;
|
||||
|
||||
/* sort now that directory suffix is added */
|
||||
git_vector_sort(contents);
|
||||
|
||||
done:
|
||||
git_path_diriter_free(&diriter);
|
||||
return error;
|
||||
}
|
||||
|
||||
int git_path_from_url_or_path(git_buf *local_path_out, const char *url_or_path)
|
||||
{
|
||||
if (git_path_is_local_file_url(url_or_path))
|
||||
|
36
src/path.h
36
src/path.h
@ -379,42 +379,6 @@ extern int git_path_dirload(
|
||||
size_t prefix_len,
|
||||
uint32_t flags);
|
||||
|
||||
typedef struct {
|
||||
struct stat st;
|
||||
size_t path_len;
|
||||
char path[GIT_FLEX_ARRAY];
|
||||
} git_path_with_stat;
|
||||
|
||||
extern int git_path_with_stat_cmp(const void *a, const void *b);
|
||||
extern int git_path_with_stat_cmp_icase(const void *a, const void *b);
|
||||
|
||||
/**
|
||||
* Load all directory entries along with stat info into a vector.
|
||||
*
|
||||
* This adds four things on top of plain `git_path_dirload`:
|
||||
*
|
||||
* 1. Each entry in the vector is a `git_path_with_stat` struct that
|
||||
* contains both the path and the stat info
|
||||
* 2. The entries will be sorted alphabetically
|
||||
* 3. Entries that are directories will be suffixed with a '/'
|
||||
* 4. Optionally, you can be a start and end prefix and only elements
|
||||
* after the start and before the end (inclusively) will be stat'ed.
|
||||
*
|
||||
* @param path The directory to read from
|
||||
* @param prefix_len The trailing part of path to prefix to entry paths
|
||||
* @param flags GIT_PATH_DIR flags from above
|
||||
* @param start_stat As optimization, only stat values after this prefix
|
||||
* @param end_stat As optimization, only stat values before this prefix
|
||||
* @param contents Vector to fill with git_path_with_stat structures
|
||||
*/
|
||||
extern int git_path_dirload_with_stat(
|
||||
const char *path,
|
||||
size_t prefix_len,
|
||||
uint32_t flags,
|
||||
const char *start_stat,
|
||||
const char *end_stat,
|
||||
git_vector *contents);
|
||||
|
||||
enum { GIT_PATH_NOTEQUAL = 0, GIT_PATH_EQUAL = 1, GIT_PATH_PREFIX = 2 };
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user