Commit 7ef005f165518a9f76774c392fa2895dc1b34c96

Edward Thomson 2015-04-29T14:04:01

git_path_dirload_with_stat: moved to fs_iterator

diff --git a/src/iterator.c b/src/iterator.c
index 93815b4..7e89b77 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 7285acc..d8f3c23 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 ff743f6..4900dce 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 };
 
 /*