From 7ef005f165518a9f76774c392fa2895dc1b34c96 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Wed, 29 Apr 2015 14:04:01 -0400 Subject: git_path_dirload_with_stat: moved to fs_iterator --- src/iterator.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++---- src/path.c | 127 --------------------------------------------------------- src/path.h | 36 ---------------- 3 files changed, 116 insertions(+), 170 deletions(-) diff --git a/src/iterator.c b/src/iterator.c index 93815b478..7e89b77cc 100644 --- a/src/iterator.c +++ b/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); diff --git a/src/path.c b/src/path.c index 7285acc62..d8f3c234e 100644 --- a/src/path.c +++ b/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)) diff --git a/src/path.h b/src/path.h index ff743f626..4900dceb0 100644 --- a/src/path.h +++ b/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 }; /* -- cgit v1.2.1