summaryrefslogtreecommitdiff
path: root/src/fileops.c
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-12-03 16:45:39 -0800
committerRussell Belfer <rb@github.com>2013-12-11 10:57:49 -0800
commit96869a4edb2872934e0e167a726ab240f4270fea (patch)
tree2d770414acef2d1d45a609e004c0aa6fa56d06d7 /src/fileops.c
parent9f77b3f6f5ce6944ec49dfc666ef6b8df0af0c6b (diff)
downloadlibgit2-96869a4edb2872934e0e167a726ab240f4270fea.tar.gz
Improve GIT_EUSER handling
This adds giterr_user_cancel to return GIT_EUSER and clear any error message that is sitting around. As a result of using that in places, we need to be more thorough with capturing errors that happen inside a callback when used internally. To help with that, this also adds giterr_capture and giterr_restore so that when we internally use a foreach-type function that clears errors and converts them to GIT_EUSER, it is easier to restore not just the return value, but the actual error message text.
Diffstat (limited to 'src/fileops.c')
-rw-r--r--src/fileops.c75
1 files changed, 36 insertions, 39 deletions
diff --git a/src/fileops.c b/src/fileops.c
index 5763b370b..0418e9e52 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -403,8 +403,8 @@ typedef struct {
const char *base;
size_t baselen;
uint32_t flags;
- int error;
int depth;
+ git_error_state error;
} futils__rmdir_data;
#define FUTILS_MAX_DEPTH 100
@@ -447,8 +447,8 @@ static int futils__rm_first_parent(git_buf *path, const char *ceiling)
static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
{
+ int error = 0;
futils__rmdir_data *data = opaque;
- int error = data->error;
struct stat st;
if (data->depth > FUTILS_MAX_DEPTH)
@@ -474,13 +474,16 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
data->depth++;
error = git_path_direach(path, 0, futils__rmdir_recurs_foreach, data);
- if (error < 0)
- return (error == GIT_EUSER) ? data->error : error;
+ if (error == GIT_EUSER)
+ return error;
data->depth--;
+ if (error < 0)
+ goto done;
+
if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0)
- return data->error;
+ goto done;
if ((error = p_rmdir(path->ptr)) < 0) {
if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 &&
@@ -499,35 +502,31 @@ static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path)
else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0)
error = futils__error_cannot_rmdir(path->ptr, "still present");
- data->error = error;
- return error;
+done:
+ return giterr_capture(&data->error, error);
}
static int futils__rmdir_empty_parent(void *opaque, git_buf *path)
{
futils__rmdir_data *data = opaque;
- int error;
+ int error = 0;
if (git_buf_len(path) <= data->baselen)
- return GIT_ITEROVER;
-
- error = p_rmdir(git_buf_cstr(path));
+ return giterr_capture(&data->error, GIT_ITEROVER);
- if (error) {
+ if (p_rmdir(git_buf_cstr(path)) < 0) {
int en = errno;
if (en == ENOENT || en == ENOTDIR) {
- giterr_clear();
- error = 0;
+ /* do nothing */
} else if (en == ENOTEMPTY || en == EEXIST || en == EBUSY) {
- giterr_clear();
error = GIT_ITEROVER;
} else {
error = git_path_set_error(errno, git_buf_cstr(path), "rmdir");
}
}
- return error;
+ return giterr_capture(&data->error, error);
}
int git_futils_rmdir_r(
@@ -535,12 +534,13 @@ int git_futils_rmdir_r(
{
int error;
git_buf fullpath = GIT_BUF_INIT;
- futils__rmdir_data data = { 0 };
+ futils__rmdir_data data;
/* build path and find "root" where we should start calling mkdir */
if (git_path_join_unrooted(&fullpath, path, base, NULL) < 0)
return -1;
+ memset(&data, 0, sizeof(data));
data.base = base ? base : "";
data.baselen = base ? strlen(base) : 0;
data.flags = flags;
@@ -548,13 +548,14 @@ int git_futils_rmdir_r(
error = futils__rmdir_recurs_foreach(&data, &fullpath);
/* remove now-empty parents if requested */
- if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0) {
+ if (!error && (flags & GIT_RMDIR_EMPTY_PARENTS) != 0)
error = git_path_walk_up(
&fullpath, base, futils__rmdir_empty_parent, &data);
- if (error == GIT_ITEROVER)
- error = 0;
- }
+ if (error == GIT_EUSER)
+ error = giterr_restore(&data.error);
+ if (error == GIT_ITEROVER)
+ error = 0;
git_buf_free(&fullpath);
@@ -858,7 +859,7 @@ typedef struct {
uint32_t flags;
uint32_t mkdir_flags;
mode_t dirmode;
- int error;
+ git_error_state error;
} cp_r_info;
#define GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT (1u << 10)
@@ -896,23 +897,21 @@ static int _cp_r_callback(void *ref, git_buf *from)
from->ptr[git_path_basename_offset(from)] == '.')
return 0;
- if (git_buf_joinpath(
- &info->to, info->to_root, from->ptr + info->from_prefix) < 0) {
- error = -1;
- goto exit;
- }
+ if ((error = git_buf_joinpath(
+ &info->to, info->to_root, from->ptr + info->from_prefix)) < 0)
+ goto done;
if (!(error = git_path_lstat(info->to.ptr, &to_st)))
exists = true;
else if (error != GIT_ENOTFOUND)
- goto exit;
+ goto done;
else {
giterr_clear();
error = 0;
}
if ((error = git_path_lstat(from->ptr, &from_st)) < 0)
- goto exit;
+ goto done;
if (S_ISDIR(from_st.st_mode)) {
mode_t oldmode = info->dirmode;
@@ -928,15 +927,14 @@ static int _cp_r_callback(void *ref, git_buf *from)
/* recurse onto target directory */
if (!error && (!exists || S_ISDIR(to_st.st_mode))) {
error = git_path_direach(from, 0, _cp_r_callback, info);
-
if (error == GIT_EUSER)
- error = info->error;
+ return error;
}
if (oldmode != 0)
info->dirmode = oldmode;
- goto exit;
+ goto done;
}
if (exists) {
@@ -947,7 +945,7 @@ static int _cp_r_callback(void *ref, git_buf *from)
giterr_set(GITERR_OS, "Cannot overwrite existing file '%s'",
info->to.ptr);
error = -1;
- goto exit;
+ goto done;
}
}
@@ -960,7 +958,7 @@ 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 &&
(error = _cp_r_mkdir(info, from)) < 0)
- goto exit;
+ goto done;
/* make symlink or regular file */
if (S_ISLNK(from_st.st_mode))
@@ -974,9 +972,8 @@ static int _cp_r_callback(void *ref, git_buf *from)
error = git_futils_cp(from->ptr, info->to.ptr, usemode);
}
-exit:
- info->error = error;
- return error;
+done:
+ return giterr_capture(&info->error, error);
}
int git_futils_cp_r(
@@ -992,11 +989,11 @@ int git_futils_cp_r(
if (git_buf_joinpath(&path, from, "") < 0) /* ensure trailing slash */
return -1;
+ memset(&info, 0, sizeof(info));
info.to_root = to;
info.flags = flags;
info.dirmode = dirmode;
info.from_prefix = path.size;
- info.error = 0;
git_buf_init(&info.to, 0);
/* precalculate mkdir flags */
@@ -1019,7 +1016,7 @@ int git_futils_cp_r(
git_buf_free(&info.to);
if (error == GIT_EUSER)
- error = info.error;
+ error = giterr_restore(&info.error);
return error;
}