Commit 81aaf370 by Edward Thomson

mkdir: chmod existing paths with `GIT_MKDIR_CHMOD`

parent e24c60db
...@@ -289,48 +289,76 @@ void git_futils_mmap_free(git_map *out) ...@@ -289,48 +289,76 @@ void git_futils_mmap_free(git_map *out)
p_munmap(out); p_munmap(out);
} }
GIT_INLINE(int) validate_existing( GIT_INLINE(int) mkdir_validate_dir(
const char *make_path, const char *path,
struct stat *st, struct stat *st,
mode_t mode, mode_t mode,
uint32_t flags, uint32_t flags,
struct git_futils_mkdir_perfdata *perfdata) struct git_futils_mkdir_options *opts)
{ {
/* 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", path);
return GIT_EEXISTS;
}
if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) || if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) ||
(S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) { (S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) {
if (p_unlink(make_path) < 0) { if (p_unlink(path) < 0) {
giterr_set(GITERR_OS, "Failed to remove %s '%s'", giterr_set(GITERR_OS, "Failed to remove %s '%s'",
S_ISLNK(st->st_mode) ? "symlink" : "file", make_path); S_ISLNK(st->st_mode) ? "symlink" : "file", path);
return GIT_EEXISTS; return GIT_EEXISTS;
} }
perfdata->mkdir_calls++; opts->perfdata.mkdir_calls++;
if (p_mkdir(make_path, mode) < 0) { if (p_mkdir(path, mode) < 0) {
giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path); giterr_set(GITERR_OS, "Failed to make directory '%s'", path);
return GIT_EEXISTS; return GIT_EEXISTS;
} }
} }
else if (S_ISLNK(st->st_mode)) { else if (S_ISLNK(st->st_mode)) {
/* Re-stat the target, make sure it's a directory */ /* Re-stat the target, make sure it's a directory */
perfdata->stat_calls++; opts->perfdata.stat_calls++;
if (p_stat(make_path, st) < 0) { if (p_stat(path, st) < 0) {
giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path); giterr_set(GITERR_OS, "Failed to make directory '%s'", path);
return GIT_EEXISTS; return GIT_EEXISTS;
} }
} }
else if (!S_ISDIR(st->st_mode)) { else if (!S_ISDIR(st->st_mode)) {
giterr_set(GITERR_FILESYSTEM, giterr_set(GITERR_FILESYSTEM,
"Failed to make directory '%s': directory exists", make_path); "Failed to make directory '%s': directory exists", path);
return GIT_EEXISTS; return GIT_EEXISTS;
} }
return 0; return 0;
} }
GIT_INLINE(int) mkdir_validate_mode(
const char *path,
struct stat *st,
bool terminal_path,
mode_t mode,
uint32_t flags,
struct git_futils_mkdir_options *opts)
{
if (((terminal_path && (flags & GIT_MKDIR_CHMOD) != 0) ||
(flags & GIT_MKDIR_CHMOD_PATH) != 0) && st->st_mode != mode) {
opts->perfdata.chmod_calls++;
if (p_chmod(path, mode) < 0) {
giterr_set(GITERR_OS, "failed to set permissions on '%s'", path);
return -1;
}
}
return 0;
}
GIT_INLINE(int) mkdir_canonicalize( GIT_INLINE(int) mkdir_canonicalize(
git_buf *path, git_buf *path,
...@@ -431,15 +459,11 @@ int git_futils_mkdir( ...@@ -431,15 +459,11 @@ int git_futils_mkdir(
* validate it. * validate it.
*/ */
if (depth == 0) { if (depth == 0) {
if ((error = validate_existing(make_path.ptr, &st, mode, flags, &opts.perfdata)) < 0) error = mkdir_validate_dir(make_path.ptr, &st, mode, flags, &opts);
goto done;
if ((flags & GIT_MKDIR_EXCL) != 0) { if (!error)
giterr_set(GITERR_FILESYSTEM, "failed to make directory '%s': " error = mkdir_validate_mode(
"directory exists", make_path.ptr); make_path.ptr, &st, true, mode, flags, &opts);
error = GIT_EEXISTS;
goto done;
}
goto done; goto done;
} }
...@@ -545,32 +569,15 @@ retry_lstat: ...@@ -545,32 +569,15 @@ retry_lstat:
goto done; goto done;
} }
} else { } else {
/* with exclusive create, existing dir is an error */ if ((error = mkdir_validate_dir(
if ((flags & GIT_MKDIR_EXCL) != 0) { make_path.ptr, &st, mode, flags, opts)) < 0)
giterr_set(GITERR_FILESYSTEM, "Failed to make directory '%s': directory exists", make_path.ptr);
error = GIT_EEXISTS;
goto done; goto done;
}
if ((error = validate_existing(
make_path.ptr, &st, mode, flags, &opts->perfdata)) < 0)
goto done;
} }
/* chmod if requested and necessary */ /* chmod if requested and necessary */
if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 || if ((error = mkdir_validate_mode(
(lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) && make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0)
st.st_mode != mode) { goto done;
opts->perfdata.chmod_calls++;
if ((error = p_chmod(make_path.ptr, mode)) < 0 &&
lastch == '\0') {
giterr_set(GITERR_OS, "Failed to set permissions on '%s'",
make_path.ptr);
goto done;
}
}
if (opts->dir_map && opts->pool) { if (opts->dir_map && opts->pool) {
char *cache_path; char *cache_path;
......
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