Commit b3f6cef0 by Edward Thomson

dirload: loop conditional; less path mangling

parent e05531dd
...@@ -32,6 +32,11 @@ ...@@ -32,6 +32,11 @@
#define PATH__MAX_UNC_LEN (32767) #define PATH__MAX_UNC_LEN (32767)
/* Using _FIND_FIRST_EX_LARGE_FETCH may increase performance in Windows 7
* and better. Prior versions will ignore this.
*/
#define _FIND_FIRST_EX_LARGE_FETCH 2
GIT_INLINE(int) path__cwd(wchar_t *path, int size) GIT_INLINE(int) path__cwd(wchar_t *path, int size)
{ {
int len; int len;
...@@ -309,6 +314,45 @@ char *git_win32_path_8dot3_name(const char *path) ...@@ -309,6 +314,45 @@ char *git_win32_path_8dot3_name(const char *path)
return shortname; return shortname;
} }
GIT_INLINE(int) path_with_stat_alloc(
git_path_with_stat **out,
const char *parent_path,
size_t parent_path_len,
const char *child_path,
size_t child_path_len,
bool trailing_slash)
{
git_path_with_stat *ps;
int inner_slash =
(parent_path_len > 0 && parent_path[parent_path_len-1] != '/');
size_t path_len, ps_size;
GITERR_CHECK_ALLOC_ADD(&path_len, parent_path_len, inner_slash);
GITERR_CHECK_ALLOC_ADD(&path_len, path_len, child_path_len);
GITERR_CHECK_ALLOC_ADD(&path_len, path_len, trailing_slash ? 1 : 0);
GITERR_CHECK_ALLOC_ADD(&ps_size, sizeof(git_path_with_stat), path_len);
ps = git__calloc(1, ps_size);
GITERR_CHECK_ALLOC(ps);
if (parent_path_len)
memcpy(ps->path, parent_path, parent_path_len);
if (inner_slash)
ps->path[parent_path_len] = '/';
memcpy(&ps->path[parent_path_len + inner_slash], child_path, child_path_len);
if (trailing_slash)
ps->path[path_len-1] = '/';
ps->path_len = path_len;
*out = ps;
return 0;
}
#if !defined(__MINGW32__) #if !defined(__MINGW32__)
int git_win32_path_dirload_with_stat( int git_win32_path_dirload_with_stat(
const char *path, const char *path,
...@@ -326,11 +370,9 @@ int git_win32_path_dirload_with_stat( ...@@ -326,11 +370,9 @@ int git_win32_path_dirload_with_stat(
size_t cmp_len; size_t cmp_len;
size_t start_len = start_stat ? strlen(start_stat) : 0; size_t start_len = start_stat ? strlen(start_stat) : 0;
size_t end_len = end_stat ? strlen(end_stat) : 0; size_t end_len = end_stat ? strlen(end_stat) : 0;
size_t path_size = strlen(path);
const char *repo_path = path + prefix_len;
size_t repo_path_len = strlen(repo_path);
char work_path[PATH__MAX_UNC_LEN]; char work_path[PATH__MAX_UNC_LEN];
size_t path_len; const char *suffix;
size_t path_len, work_path_len, suffix_len;
if (!git_win32__findfirstfile_filter(pathw, path)) { if (!git_win32__findfirstfile_filter(pathw, path)) {
giterr_set(GITERR_OS, "Could not parse the path '%s'", path); giterr_set(GITERR_OS, "Could not parse the path '%s'", path);
...@@ -338,14 +380,23 @@ int git_win32_path_dirload_with_stat( ...@@ -338,14 +380,23 @@ int git_win32_path_dirload_with_stat(
} }
strncomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ? strncomp = (flags & GIT_PATH_DIR_IGNORE_CASE) != 0 ?
git__strncasecmp : git__strncmp; git__strncasecmp : git__strncmp;
path_len = strlen(path);
suffix = path + prefix_len;
suffix_len = path_len - prefix_len;
/* use of FIND_FIRST_EX_LARGE_FETCH flag in the FindFirstFileExW call could benefit perormance /* use of FIND_FIRST_EX_LARGE_FETCH flag in the FindFirstFileExW call could benefit perormance
* here when querying large repositories on Windows 7 (0x0600) or newer versions of Windows. * here when querying large repositories on Windows 7 (0x0600) or newer versions of Windows.
* doing so could introduce compatibility issues on older versions of Windows. */ * doing so could introduce compatibility issues on older versions of Windows. */
dir.h = FindFirstFileExW(pathw, FindExInfoBasic, &dir.f, FindExSearchNameMatch, NULL, 0); dir.h = FindFirstFileExW(
dir.first = 1; pathw,
FindExInfoBasic,
&dir.f,
FindExSearchNameMatch,
NULL,
_FIND_FIRST_EX_LARGE_FETCH);
if (dir.h == INVALID_HANDLE_VALUE) { if (dir.h == INVALID_HANDLE_VALUE) {
error = -1; error = -1;
...@@ -353,64 +404,56 @@ int git_win32_path_dirload_with_stat( ...@@ -353,64 +404,56 @@ int git_win32_path_dirload_with_stat(
goto clean_up_and_exit; goto clean_up_and_exit;
} }
if (repo_path_len > PATH__MAX_UNC_LEN) { do {
error = -1; if (git_path_is_dot_or_dotdotW(dir.f.cFileName))
giterr_set(GITERR_OS, "Could not open directory '%s'", path); continue;
goto clean_up_and_exit;
} if ((work_path_len = git__utf16_to_8(work_path, PATH__MAX_UNC_LEN, dir.f.cFileName)) < 0) {
error = -1;
memcpy(work_path, repo_path, repo_path_len); giterr_set(GITERR_OS, "Could not convert path to UTF-8 (path too long?)");
goto clean_up_and_exit;
while (1) { }
if (!git_path_is_dot_or_dotdotW(dir.f.cFileName)) { work_path[work_path_len] = '\0';
path_len = git__utf16_to_8(work_path + repo_path_len, ARRAYSIZE(work_path) - repo_path_len, dir.f.cFileName);
/* TODO: what about junctions to directories? */
work_path[path_len + repo_path_len] = '\0'; if ((error = path_with_stat_alloc(&ps,
path_len = path_len + repo_path_len; suffix, suffix_len,
work_path, work_path_len,
cmp_len = min(start_len, path_len); (dir.f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)) < 0)
if (!(cmp_len && strncomp(work_path, start_stat, cmp_len) < 0)) { goto clean_up_and_exit;
cmp_len = min(end_len, path_len);
/* skip if before start_stat or after end_stat */
if (!(cmp_len && strncomp(work_path, end_stat, cmp_len) > 0)) { cmp_len = min(start_len, work_path_len);
ps = git__calloc(1, sizeof(git_path_with_stat) + path_len + 2); if (cmp_len && strncomp(ps->path, start_stat, cmp_len) < 0) {
git__free(ps);
if ((error = git_win32__file_attribute_to_stat(&ps->st, continue;
(WIN32_FILE_ATTRIBUTE_DATA *)&dir.f, }
NULL)) < 0) {
git__free(ps);
goto clean_up_and_exit;
}
memcpy(ps->path, work_path, path_len + 1); cmp_len = min(end_len, work_path_len);
ps->path_len = path_len; if (cmp_len && strncomp(ps->path, end_stat, cmp_len) > 0) {
git__free(ps);
continue;
}
if (S_ISDIR(ps->st.st_mode)) { if ((error = git_win32__file_attribute_to_stat(&ps->st,
ps->path[ps->path_len++] = '/'; (WIN32_FILE_ATTRIBUTE_DATA *)&dir.f,
ps->path[ps->path_len] = '\0'; NULL)) < 0) {
} else if (!S_ISREG(ps->st.st_mode) && !S_ISLNK(ps->st.st_mode)) { git__free(ps);
git__free(ps); goto clean_up_and_exit;
ps = NULL; }
}
if (ps) if (!S_ISDIR(ps->st.st_mode) && !S_ISREG(ps->st.st_mode) && !S_ISLNK(ps->st.st_mode)) {
git_vector_insert(contents, ps); git__free(ps);
} continue;
}
} }
memset(&dir.f, 0, sizeof(git_path_with_stat)); git_vector_insert(contents, ps);
dir.first = 0; } while (FindNextFileW(dir.h, &dir.f));
if (!FindNextFileW(dir.h, &dir.f)) { if (GetLastError() != ERROR_NO_MORE_FILES) {
if (GetLastError() == ERROR_NO_MORE_FILES) error = -1;
break; giterr_set(GITERR_OS, "Could not get attributes for file in '%s'", path);
else { goto clean_up_and_exit;
error = -1;
giterr_set(GITERR_OS, "Could not get attributes for file in '%s'", path);
goto clean_up_and_exit;
}
}
} }
/* sort now that directory suffix is added */ /* sort now that directory suffix is added */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment