diff options
author | Edward Thomson <ethomson@microsoft.com> | 2015-02-03 01:46:01 -0500 |
---|---|---|
committer | Edward Thomson <ethomson@edwardthomson.com> | 2015-02-04 14:15:13 +0000 |
commit | 500ec5431564d9167985a02909823e1286136d5b (patch) | |
tree | a1bf00580026a74fe044567b8aec10e26be2a347 | |
parent | f58cc280c9ddeff6fd85f56e70073c3ed4fb0650 (diff) | |
download | libgit2-500ec5431564d9167985a02909823e1286136d5b.tar.gz |
checkout: hold seen dir paths in a map
-rw-r--r-- | src/checkout.c | 77 | ||||
-rw-r--r-- | src/fileops.c | 35 | ||||
-rw-r--r-- | src/fileops.h | 13 |
3 files changed, 76 insertions, 49 deletions
diff --git a/src/checkout.c b/src/checkout.c index 04493a3cb..3f65a9ed7 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -29,6 +29,10 @@ #include "merge_file.h" #include "path.h" #include "attr.h" +#include "pool.h" +#include "strmap.h" + +GIT__USE_STRMAP; /* See docs/checkout-internals.md for more information */ @@ -69,7 +73,7 @@ typedef struct { size_t total_steps; size_t completed_steps; git_checkout_perfdata perfdata; - git_buf last_mkdir; + git_strmap *mkdir_map; git_attr_session attr_session; } checkout_data; @@ -1293,25 +1297,6 @@ fail: return error; } -static int checkout_mkdir( - checkout_data *data, - const char *path, - const char *base, - mode_t mode, - unsigned int flags) -{ - struct git_futils_mkdir_perfdata mkdir_perfdata = {0}; - - int error = git_futils_mkdir_withperf( - path, base, mode, flags, &mkdir_perfdata); - - data->perfdata.mkdir_calls += mkdir_perfdata.mkdir_calls; - data->perfdata.stat_calls += mkdir_perfdata.stat_calls; - data->perfdata.chmod_calls += mkdir_perfdata.chmod_calls; - - return error; -} - static bool should_remove_existing(checkout_data *data) { int ignorecase = 0; @@ -1327,31 +1312,43 @@ static bool should_remove_existing(checkout_data *data) #define MKDIR_REMOVE_EXISTING \ MKDIR_NORMAL | GIT_MKDIR_REMOVE_FILES | GIT_MKDIR_REMOVE_SYMLINKS +static int checkout_mkdir( + checkout_data *data, + const char *path, + const char *base, + mode_t mode, + unsigned int flags) +{ + struct git_futils_mkdir_options mkdir_opts = {0}; + int error; + + mkdir_opts.dir_map = data->mkdir_map; + mkdir_opts.pool = &data->pool; + + error = git_futils_mkdir_ext( + path, base, mode, flags, &mkdir_opts); + + data->perfdata.mkdir_calls += mkdir_opts.perfdata.mkdir_calls; + data->perfdata.stat_calls += mkdir_opts.perfdata.stat_calls; + data->perfdata.chmod_calls += mkdir_opts.perfdata.chmod_calls; + + return error; +} + static int mkpath2file( checkout_data *data, const char *path, unsigned int mode) { - git_buf *mkdir_path = &data->tmp; struct stat st; bool remove_existing = should_remove_existing(data); + unsigned int flags = + (remove_existing ? MKDIR_REMOVE_EXISTING : MKDIR_NORMAL) | + GIT_MKDIR_SKIP_LAST; int error; - if ((error = git_buf_sets(mkdir_path, path)) < 0) + if ((error = checkout_mkdir( + data, path, data->opts.target_directory, mode, flags)) < 0) return error; - git_buf_rtruncate_at_char(mkdir_path, '/'); - - if (!data->last_mkdir.size || - data->last_mkdir.size != mkdir_path->size || - memcmp(mkdir_path->ptr, data->last_mkdir.ptr, mkdir_path->size) != 0) { - - if ((error = checkout_mkdir( - data, mkdir_path->ptr, data->opts.target_directory, mode, - remove_existing ? MKDIR_REMOVE_EXISTING : MKDIR_NORMAL)) < 0) - return error; - - git_buf_swap(&data->last_mkdir, mkdir_path); - } - if (remove_existing) { data->perfdata.stat_calls++; @@ -2215,13 +2212,16 @@ static void checkout_data_clear(checkout_data *data) git__free(data->pfx); data->pfx = NULL; - git_buf_free(&data->last_mkdir); + git_strmap_free(data->mkdir_map); + git_buf_free(&data->path); git_buf_free(&data->tmp); git_index_free(data->index); data->index = NULL; + git_strmap_free(data->mkdir_map); + git_attr_session__free(&data->attr_session); } @@ -2360,7 +2360,8 @@ static int checkout_data_init( (error = git_vector_init(&data->update_conflicts, 0, NULL)) < 0 || (error = git_pool_init(&data->pool, 1, 0)) < 0 || (error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 || - (error = git_path_to_dir(&data->path)) < 0) + (error = git_path_to_dir(&data->path)) < 0 || + (error = git_strmap_alloc(&data->mkdir_map)) < 0) goto cleanup; data->workdir_len = git_buf_len(&data->path); diff --git a/src/fileops.c b/src/fileops.c index 2ee9535be..ff2acfc2b 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -7,11 +7,14 @@ #include "common.h" #include "fileops.h" #include "global.h" +#include "strmap.h" #include <ctype.h> #if GIT_WIN32 #include "win32/findfile.h" #endif +GIT__USE_STRMAP; + int git_futils_mkpath2file(const char *file_path, const mode_t mode) { return git_futils_mkdir( @@ -321,12 +324,12 @@ GIT_INLINE(int) validate_existing( return 0; } -int git_futils_mkdir_withperf( +int git_futils_mkdir_ext( const char *path, const char *base, mode_t mode, uint32_t flags, - struct git_futils_mkdir_perfdata *perfdata) + struct git_futils_mkdir_options *opts) { int error = -1; git_buf make_path = GIT_BUF_INIT; @@ -394,11 +397,14 @@ int git_futils_mkdir_withperf( *tail = '\0'; st.st_mode = 0; + if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr)) + continue; + /* See what's going on with this path component */ - perfdata->stat_calls++; + opts->perfdata.stat_calls++; if (p_lstat(make_path.ptr, &st) < 0) { - perfdata->mkdir_calls++; + opts->perfdata.mkdir_calls++; if (errno != ENOENT || p_mkdir(make_path.ptr, mode) < 0) { giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); @@ -416,7 +422,7 @@ int git_futils_mkdir_withperf( } if ((error = validate_existing( - make_path.ptr, &st, mode, flags, perfdata)) < 0) + make_path.ptr, &st, mode, flags, &opts->perfdata)) < 0) goto done; } @@ -425,7 +431,7 @@ int git_futils_mkdir_withperf( (lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) && st.st_mode != mode) { - perfdata->chmod_calls++; + opts->perfdata.chmod_calls++; if ((error = p_chmod(make_path.ptr, mode)) < 0 && lastch == '\0') { @@ -434,6 +440,17 @@ int git_futils_mkdir_withperf( goto done; } } + + if (opts->dir_map && opts->pool) { + char *cache_path = git_pool_malloc(opts->pool, make_path.size + 1); + GITERR_CHECK_ALLOC(cache_path); + + memcpy(cache_path, make_path.ptr, make_path.size + 1); + + git_strmap_insert(opts->dir_map, cache_path, cache_path, error); + if (error < 0) + goto done; + } } error = 0; @@ -441,7 +458,7 @@ int git_futils_mkdir_withperf( /* check that full path really is a directory if requested & needed */ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && lastch != '\0') { - perfdata->stat_calls++; + opts->perfdata.stat_calls++; if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) { giterr_set(GITERR_OS, "Path is not a directory '%s'", @@ -461,8 +478,8 @@ int git_futils_mkdir( mode_t mode, uint32_t flags) { - struct git_futils_mkdir_perfdata perfdata = {0}; - return git_futils_mkdir_withperf(path, base, mode, flags, &perfdata); + struct git_futils_mkdir_options options = {0}; + return git_futils_mkdir_ext(path, base, mode, flags, &options); } int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode) diff --git a/src/fileops.h b/src/fileops.h index 4aaf1781c..0f6466c59 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -11,6 +11,8 @@ #include "map.h" #include "posix.h" #include "path.h" +#include "pool.h" +#include "strmap.h" /** * Filebuffer methods @@ -95,6 +97,13 @@ struct git_futils_mkdir_perfdata size_t chmod_calls; }; +struct git_futils_mkdir_options +{ + git_strmap *dir_map; + git_pool *pool; + struct git_futils_mkdir_perfdata perfdata; +}; + /** * Create a directory or entire path. * @@ -106,10 +115,10 @@ struct git_futils_mkdir_perfdata * @param base Root for relative path. These directories will never be made. * @param mode The mode to use for created directories. * @param flags Combination of the mkdir flags above. - * @param perfdata Performance data, use `git_futils_mkdir` if you don't want this data. + * @param opts Extended options, use `git_futils_mkdir` if you are not interested. * @return 0 on success, else error code */ -extern int git_futils_mkdir_withperf(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_perfdata *perfdata); +extern int git_futils_mkdir_ext(const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts); /** * Create a directory or entire path. Similar to `git_futils_mkdir_withperf` |