diff options
author | Edward Thomson <ethomson@edwardthomson.com> | 2015-01-16 18:35:13 -0500 |
---|---|---|
committer | Edward Thomson <ethomson@microsoft.com> | 2015-01-19 13:28:09 -0600 |
commit | 8d97f707991247c471104d073e788c5117c59384 (patch) | |
tree | 8bac5cd6aad69e8b40137b96d0c24bc7ac23be2a | |
parent | e8909d5d191b1e94f89e09cd0c2a1a43630744fb (diff) | |
download | libgit2-8d97f707991247c471104d073e788c5117c59384.tar.gz |
checkout: don't recreate previous directory
Don't bother trying to recreate the previously created directory
during checkout, for a modest reduction in the number of stats.
-rw-r--r-- | src/checkout.c | 22 | ||||
-rw-r--r-- | src/fileops.c | 36 |
2 files changed, 44 insertions, 14 deletions
diff --git a/src/checkout.c b/src/checkout.c index 04d119405..9ade1552f 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -66,6 +66,7 @@ typedef struct { size_t total_steps; size_t completed_steps; git_checkout_perfdata perfdata; + git_buf last_mkdir; } checkout_data; typedef struct { @@ -1241,9 +1242,24 @@ static int checkout_mkdir( static int mkpath2file( checkout_data *data, const char *path, unsigned int mode) { - return checkout_mkdir( - data, path, git_repository_workdir(data->repo), mode, - GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR); + git_buf *mkdir_path = &data->tmp; + int error; + + if ((error = git_buf_sets(mkdir_path, path)) < 0) + return error; + + git_buf_rtruncate_at_char(mkdir_path, '/'); + + if (data->last_mkdir.size && mkdir_path->size == data->last_mkdir.size && + memcmp(mkdir_path->ptr, data->last_mkdir.ptr, mkdir_path->size) == 0) + return 0; + + if ((error = checkout_mkdir( + data, mkdir_path->ptr, data->opts.target_directory, mode, + GIT_MKDIR_PATH | GIT_MKDIR_VERIFY_DIR)) == 0) + git_buf_swap(&data->last_mkdir, mkdir_path); + + return error; } static int buffer_to_file( diff --git a/src/fileops.c b/src/fileops.c index 926813f5e..8d192f177 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -352,26 +352,40 @@ int git_futils_mkdir_withperf( *tail = '\0'; st.st_mode = 0; - /* make directory */ - perfdata->mkdir_calls++; + /* See what's going on with this path component */ + perfdata->stat_calls++; + + if (p_lstat(make_path.ptr, &st) < 0) { + perfdata->mkdir_calls++; - if (p_mkdir(make_path.ptr, mode) < 0) { - int tmp_errno = giterr_system_last(); + if (errno != ENOENT || p_mkdir(make_path.ptr, mode) < 0) { + giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); + error = GIT_EEXISTS; + goto done; + } + + giterr_clear(); + } else { + /* with exclusive create, existing dir is an error */ + if ((flags & GIT_MKDIR_EXCL) != 0) { + giterr_set(GITERR_INVALID, "Failed to make directory '%s': directory exists", make_path.ptr); + error = GIT_EEXISTS; + goto done; + } - /* ignore error if not at end or if directory already exists */ - if (lastch == '\0') { + if (S_ISLNK(st.st_mode)) { perfdata->stat_calls++; - if (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode)) { - giterr_system_set(tmp_errno); + /* Re-stat the target, make sure it's a directory */ + if (p_stat(make_path.ptr, &st) < 0) { giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); + error = GIT_EEXISTS; goto done; } } - /* with exclusive create, existing dir is an error */ - if ((flags & GIT_MKDIR_EXCL) != 0) { - giterr_set(GITERR_OS, "Directory already exists '%s'", make_path.ptr); + if (!S_ISDIR(st.st_mode)) { + giterr_set(GITERR_INVALID, "Failed to make directory '%s': directory exists", make_path.ptr); error = GIT_EEXISTS; goto done; } |