diff options
Diffstat (limited to 'src/fileops.c')
-rw-r--r-- | src/fileops.c | 181 |
1 files changed, 114 insertions, 67 deletions
diff --git a/src/fileops.c b/src/fileops.c index 955bb1bf6..fb2f954d7 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -10,35 +10,40 @@ int git_futils_mkpath2file(const char *file_path, const mode_t mode) { - int error = GIT_SUCCESS; - char target_folder_path[GIT_PATH_MAX]; + int error; + git_buf target_folder = GIT_BUF_INIT; - error = git_path_dirname_r(target_folder_path, sizeof(target_folder_path), file_path); - if (error < GIT_SUCCESS) + error = git_path_dirname_r(&target_folder, file_path); + if (error < GIT_SUCCESS) { + git_buf_free(&target_folder); return git__throw(GIT_EINVALIDPATH, "Failed to recursively build `%s` tree structure. Unable to parse parent folder name", file_path); + } else { + /* reset error */ + error = GIT_SUCCESS; + } /* Does the containing folder exist? */ - if (git_futils_isdir(target_folder_path)) { - git_path_join(target_folder_path, target_folder_path, ""); /* Ensure there's a trailing slash */ - + if (git_futils_isdir(target_folder.ptr) != GIT_SUCCESS) /* Let's create the tree structure */ - error = git_futils_mkdir_r(target_folder_path, mode); - if (error < GIT_SUCCESS) - return error; /* The callee already takes care of setting the correct error message. */ - } + error = git_futils_mkdir_r(target_folder.ptr, NULL, mode); - return GIT_SUCCESS; + git_buf_free(&target_folder); + return error; } -int git_futils_mktmp(char *path_out, const char *filename) +int git_futils_mktmp(git_buf *path_out, const char *filename) { int fd; - strcpy(path_out, filename); - strcat(path_out, "_git2_XXXXXX"); + git_buf_sets(path_out, filename); + git_buf_puts(path_out, "_git2_XXXXXX"); + + if (git_buf_oom(path_out)) + return git__rethrow(git_buf_lasterror(path_out), + "Failed to create temporary file for %s", filename); - if ((fd = p_mkstemp(path_out)) < 0) - return git__throw(GIT_EOSERR, "Failed to create temporary file %s", path_out); + if ((fd = p_mkstemp(path_out->ptr)) < 0) + return git__throw(GIT_EOSERR, "Failed to create temporary file %s", path_out->ptr); return fd; } @@ -180,6 +185,14 @@ int git_futils_readbuffer(git_fbuffer *obj, const char *path) return git_futils_readbuffer_updated(obj, path, NULL, NULL); } +void git_futils_fbuffer_rtrim(git_fbuffer *obj) +{ + unsigned char *buff = obj->data; + while (obj->len > 0 && isspace(buff[obj->len - 1])) + obj->len--; + buff[obj->len] = '\0'; +} + void git_futils_freebuffer(git_fbuffer *obj) { assert(obj); @@ -215,76 +228,72 @@ GIT_INLINE(int) is_dot_or_dotdot(const char *name) } int git_futils_direach( - char *path, - size_t path_sz, - int (*fn)(void *, char *), + git_buf *path, + int (*fn)(void *, git_buf *), void *arg) { - size_t wd_len = strlen(path); + ssize_t wd_len; DIR *dir; struct dirent *de; - if (!wd_len || path_sz < wd_len + 2) - return git__throw(GIT_EINVALIDARGS, "Failed to process `%s` tree structure. Path is either empty or buffer size is too short", path); - - while (path[wd_len - 1] == '/') - wd_len--; - path[wd_len++] = '/'; - path[wd_len] = '\0'; + if (git_path_to_dir(path) < GIT_SUCCESS) + return git_buf_lasterror(path); - dir = opendir(path); + wd_len = path->size; + dir = opendir(path->ptr); if (!dir) - return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path); + return git__throw(GIT_EOSERR, "Failed to process `%s` tree structure. An error occured while opening the directory", path->ptr); while ((de = readdir(dir)) != NULL) { - size_t de_len; int result; if (is_dot_or_dotdot(de->d_name)) continue; - de_len = strlen(de->d_name); - if (path_sz < wd_len + de_len + 1) { - closedir(dir); - return git__throw(GIT_ERROR, "Failed to process `%s` tree structure. Buffer size is too short", path); - } + if (git_buf_puts(path, de->d_name) < GIT_SUCCESS) + return git_buf_lasterror(path); - strcpy(path + wd_len, de->d_name); result = fn(arg, path); - if (result < GIT_SUCCESS) { + + git_buf_truncate(path, wd_len); /* restore path */ + + if (result != GIT_SUCCESS) { closedir(dir); return result; /* The callee is reponsible for setting the correct error message */ } - if (result > 0) { - closedir(dir); - return result; - } } closedir(dir); return GIT_SUCCESS; } -int git_futils_mkdir_r(const char *path, const mode_t mode) +int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode) { int error, root_path_offset; + git_buf make_path = GIT_BUF_INIT; + size_t start; char *pp, *sp; - char *path_copy = git__strdup(path); - if (path_copy == NULL) - return GIT_ENOMEM; + if (base != NULL) { + start = strlen(base); + error = git_buf_joinpath(&make_path, base, path); + } else { + start = 0; + error = git_buf_puts(&make_path, path); + } + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to create `%s` tree structure", path); - error = GIT_SUCCESS; - pp = path_copy; + pp = make_path.ptr + start; - root_path_offset = git_path_root(pp); + root_path_offset = git_path_root(make_path.ptr); if (root_path_offset > 0) pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */ while (error == GIT_SUCCESS && (sp = strchr(pp, '/')) != NULL) { - if (sp != pp && git_futils_isdir(path_copy) < GIT_SUCCESS) { + if (sp != pp && git_futils_isdir(make_path.ptr) < GIT_SUCCESS) { *sp = 0; - error = p_mkdir(path_copy, mode); + error = p_mkdir(make_path.ptr, mode); /* Do not choke while trying to recreate an existing directory */ if (errno == EEXIST) @@ -297,12 +306,12 @@ int git_futils_mkdir_r(const char *path, const mode_t mode) } if (*pp != '\0' && error == GIT_SUCCESS) { - error = p_mkdir(path, mode); + error = p_mkdir(make_path.ptr, mode); if (errno == EEXIST) error = GIT_SUCCESS; } - git__free(path_copy); + git_buf_free(&make_path); if (error < GIT_SUCCESS) return git__throw(error, "Failed to recursively create `%s` tree structure", path); @@ -310,32 +319,34 @@ int git_futils_mkdir_r(const char *path, const mode_t mode) return GIT_SUCCESS; } -static int _rmdir_recurs_foreach(void *opaque, char *path) +static int _rmdir_recurs_foreach(void *opaque, git_buf *path) { int error = GIT_SUCCESS; int force = *(int *)opaque; - if (git_futils_isdir(path) == GIT_SUCCESS) { - size_t root_size = strlen(path); - - if ((error = git_futils_direach(path, GIT_PATH_MAX, _rmdir_recurs_foreach, opaque)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to remove directory `%s`", path); - - path[root_size] = '\0'; - return p_rmdir(path); + if (git_futils_isdir(path->ptr) == GIT_SUCCESS) { + error = git_futils_direach(path, _rmdir_recurs_foreach, opaque); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to remove directory `%s`", path->ptr); + return p_rmdir(path->ptr); } else if (force) { - return p_unlink(path); + return p_unlink(path->ptr); } - return git__rethrow(error, "Failed to remove directory. `%s` is not empty", path); + return git__rethrow(error, "Failed to remove directory. `%s` is not empty", path->ptr); } int git_futils_rmdir_r(const char *path, int force) { - char p[GIT_PATH_MAX]; - strncpy(p, path, GIT_PATH_MAX); - return _rmdir_recurs_foreach(&force, p); + int error; + git_buf p = GIT_BUF_INIT; + + error = git_buf_sets(&p, path); + if (error == GIT_SUCCESS) + error = _rmdir_recurs_foreach(&force, &p); + git_buf_free(&p); + return error; } int git_futils_cmp_path(const char *name1, int len1, int isdir1, @@ -356,3 +367,39 @@ int git_futils_cmp_path(const char *name1, int len1, int isdir1, return 0; } +static int _check_dir_contents( + git_buf *dir, + const char *sub, + int append_on_success, + int (*predicate)(const char *)) +{ + int error = GIT_SUCCESS; + size_t dir_size = dir->size; + size_t sub_size = strlen(sub); + + /* leave base valid even if we could not make space for subdir */ + if ((error = git_buf_try_grow(dir, dir_size + sub_size + 2)) < GIT_SUCCESS) + return error; + + /* save excursion */ + git_buf_joinpath(dir, dir->ptr, sub); + + error = (*predicate)(dir->ptr); + + /* restore excursion */ + if (!append_on_success || error != GIT_SUCCESS) + git_buf_truncate(dir, dir_size); + + return error; +} + +int git_futils_contains_dir(git_buf *base, const char *subdir, int append_if_exists) +{ + return _check_dir_contents(base, subdir, append_if_exists, &git_futils_isdir); +} + +int git_futils_contains_file(git_buf *base, const char *file, int append_if_exists) +{ + return _check_dir_contents(base, file, append_if_exists, &git_futils_isfile); +} + |