From fe598f0903012e361eca53c4cb65c27e4e8dfac9 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Tue, 13 Jan 2015 11:18:02 -0600 Subject: mkdir: walk up tree to mkdir Walk up the tree to mkdir, which is less immediately efficient, but allows us to look at intermediate directories that may need attention. --- include/git2/errors.h | 1 + src/fileops.c | 36 +++++++++++++++++++++++++----------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/include/git2/errors.h b/include/git2/errors.h index 9b4cc7c00..ef4fabb7d 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -93,6 +93,7 @@ typedef enum { GITERR_CHERRYPICK, GITERR_DESCRIBE, GITERR_REBASE, + GITERR_FILESYSTEM } git_error_t; /** diff --git a/src/fileops.c b/src/fileops.c index 926813f5e..ea0f4e1f7 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_FILESYSTEM, "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_FILESYSTEM, "Failed to make directory '%s': directory exists", make_path.ptr); error = GIT_EEXISTS; goto done; } -- cgit v1.2.1