diff options
author | Vicent Martà <vicent@github.com> | 2013-03-06 03:35:28 +0400 |
---|---|---|
committer | Vicent Martà <vicent@github.com> | 2013-03-06 03:35:28 +0400 |
commit | b72f5d4038a21a27efcdec350376af0342ccf3f0 (patch) | |
tree | 73428317a150fa30e7b3efcaabcd73b503e50295 /src/fileops.c | |
parent | 3d74702eec07f2208211a72581c115340517ea4b (diff) | |
parent | 18f08264082dd436914c3c06d369e7a98ddf17aa (diff) |
Merge pull request #1369 from arrbee/repo-init-template-hooks
More tests (and fixes) for initializing repo from template
Diffstat (limited to 'src/fileops.c')
-rw-r--r-- | src/fileops.c | 122 |
1 files changed, 80 insertions, 42 deletions
diff --git a/src/fileops.c b/src/fileops.c index 6429e55b4..c1824e812 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -272,6 +272,10 @@ int git_futils_mkdir( } /* if we are not supposed to made the last element, truncate it */ + if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) { + git_buf_rtruncate_at_char(&make_path, '/'); + flags |= GIT_MKDIR_SKIP_LAST; + } if ((flags & GIT_MKDIR_SKIP_LAST) != 0) git_buf_rtruncate_at_char(&make_path, '/'); @@ -303,34 +307,34 @@ int git_futils_mkdir( int already_exists = 0; switch (errno) { - case EEXIST: - if (!lastch && (flags & GIT_MKDIR_VERIFY_DIR) != 0 && - !git_path_isdir(make_path.ptr)) { - giterr_set( - GITERR_OS, "Existing path is not a directory '%s'", - make_path.ptr); - error = GIT_ENOTFOUND; - goto fail; - } - - already_exists = 1; - break; - case ENOSYS: - /* Solaris can generate this error if you try to mkdir - * a path which is already a mount point. In that case, - * the path does already exist; but it's not implied by - * the definition of the error, so let's recheck */ - if (git_path_isdir(make_path.ptr)) { - already_exists = 1; - break; - } - - /* Fall through */ - errno = ENOSYS; - default: - giterr_set(GITERR_OS, "Failed to make directory '%s'", + case EEXIST: + if (!lastch && (flags & GIT_MKDIR_VERIFY_DIR) != 0 && + !git_path_isdir(make_path.ptr)) { + giterr_set( + GITERR_OS, "Existing path is not a directory '%s'", make_path.ptr); + error = GIT_ENOTFOUND; goto fail; + } + + already_exists = 1; + break; + case ENOSYS: + /* Solaris can generate this error if you try to mkdir + * a path which is already a mount point. In that case, + * the path does already exist; but it's not implied by + * the definition of the error, so let's recheck */ + if (git_path_isdir(make_path.ptr)) { + already_exists = 1; + break; + } + + /* Fall through */ + errno = ENOSYS; + default: + giterr_set(GITERR_OS, "Failed to make directory '%s'", + make_path.ptr); + goto fail; } if (already_exists && (flags & GIT_MKDIR_EXCL) != 0) { @@ -714,8 +718,33 @@ typedef struct { mode_t dirmode; } cp_r_info; +#define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10) + +static int _cp_r_mkdir(cp_r_info *info, git_buf *from) +{ + int error = 0; + + /* create root directory the first time we need to create a directory */ + if ((info->flags & GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT) == 0) { + error = git_futils_mkdir( + info->to_root, NULL, info->dirmode, + (info->flags & GIT_CPDIR_CHMOD_DIRS) ? GIT_MKDIR_CHMOD : 0); + + info->flags |= GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT; + } + + /* create directory with root as base to prevent excess chmods */ + if (!error) + error = git_futils_mkdir( + from->ptr + info->from_prefix, info->to_root, + info->dirmode, info->mkdir_flags); + + return error; +} + static int _cp_r_callback(void *ref, git_buf *from) { + int error = 0; cp_r_info *info = ref; struct stat from_st, to_st; bool exists = false; @@ -737,24 +766,22 @@ static int _cp_r_callback(void *ref, git_buf *from) } else exists = true; - if (git_path_lstat(from->ptr, &from_st) < 0) - return -1; + if ((error = git_path_lstat(from->ptr, &from_st)) < 0) + return error; if (S_ISDIR(from_st.st_mode)) { - int error = 0; mode_t oldmode = info->dirmode; /* if we are not chmod'ing, then overwrite dirmode */ - if ((info->flags & GIT_CPDIR_CHMOD) == 0) + if ((info->flags & GIT_CPDIR_CHMOD_DIRS) == 0) info->dirmode = from_st.st_mode; /* make directory now if CREATE_EMPTY_DIRS is requested and needed */ if (!exists && (info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) != 0) - error = git_futils_mkdir( - info->to.ptr, NULL, info->dirmode, info->mkdir_flags); + error = _cp_r_mkdir(info, from); /* recurse onto target directory */ - if (!exists || S_ISDIR(to_st.st_mode)) + if (!error && (!exists || S_ISDIR(to_st.st_mode))) error = git_path_direach(from, _cp_r_callback, info); if (oldmode != 0) @@ -782,15 +809,22 @@ static int _cp_r_callback(void *ref, git_buf *from) /* Make container directory on demand if needed */ if ((info->flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0 && - git_futils_mkdir( - info->to.ptr, NULL, info->dirmode, info->mkdir_flags) < 0) - return -1; + (error = _cp_r_mkdir(info, from)) < 0) + return error; /* make symlink or regular file */ if (S_ISLNK(from_st.st_mode)) - return cp_link(from->ptr, info->to.ptr, (size_t)from_st.st_size); - else - return git_futils_cp(from->ptr, info->to.ptr, from_st.st_mode); + error = cp_link(from->ptr, info->to.ptr, (size_t)from_st.st_size); + else { + mode_t usemode = from_st.st_mode; + + if ((info->flags & GIT_CPDIR_SIMPLE_TO_MODE) != 0) + usemode = (usemode & 0111) ? 0777 : 0666; + + error = git_futils_cp(from->ptr, info->to.ptr, usemode); + } + + return error; } int git_futils_cp_r( @@ -803,7 +837,7 @@ int git_futils_cp_r( git_buf path = GIT_BUF_INIT; cp_r_info info; - if (git_buf_sets(&path, from) < 0) + if (git_buf_joinpath(&path, from, "") < 0) /* ensure trailing slash */ return -1; info.to_root = to; @@ -814,12 +848,16 @@ int git_futils_cp_r( /* precalculate mkdir flags */ if ((flags & GIT_CPDIR_CREATE_EMPTY_DIRS) == 0) { + /* if not creating empty dirs, then use mkdir to create the path on + * demand right before files are copied. + */ info.mkdir_flags = GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST; - if ((flags & GIT_CPDIR_CHMOD) != 0) + if ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) info.mkdir_flags |= GIT_MKDIR_CHMOD_PATH; } else { + /* otherwise, we will do simple mkdir as directories are encountered */ info.mkdir_flags = - ((flags & GIT_CPDIR_CHMOD) != 0) ? GIT_MKDIR_CHMOD : 0; + ((flags & GIT_CPDIR_CHMOD_DIRS) != 0) ? GIT_MKDIR_CHMOD : 0; } error = _cp_r_callback(&info, &path); |