void test_core_rmdir__can_remove_empty_parents(void) { git_buf file = GIT_BUF_INIT; cl_git_pass( git_buf_joinpath(&file, empty_tmp_dir, "/one/two_two/three/file.txt")); cl_git_mkfile(git_buf_cstr(&file), "dummy"); cl_assert(git_path_isfile(git_buf_cstr(&file))); cl_git_pass(git_futils_rmdir_r("one/two_two/three/file.txt", empty_tmp_dir, GIT_RMDIR_REMOVE_FILES | GIT_RMDIR_EMPTY_PARENTS)); cl_assert(!git_path_exists(git_buf_cstr(&file))); git_buf_rtruncate_at_char(&file, '/'); /* three (only contained file.txt) */ cl_assert(!git_path_exists(git_buf_cstr(&file))); git_buf_rtruncate_at_char(&file, '/'); /* two_two (only contained three) */ cl_assert(!git_path_exists(git_buf_cstr(&file))); git_buf_rtruncate_at_char(&file, '/'); /* one (contained two_one also) */ cl_assert(git_path_exists(git_buf_cstr(&file))); cl_assert(git_path_exists(empty_tmp_dir) == true); git_buf_dispose(&file); cl_git_pass(git_futils_rmdir_r(empty_tmp_dir, NULL, GIT_RMDIR_EMPTY_HIERARCHY)); }
static void check_tree_entry( git_iterator *i, const char *oid, const char *oid_p, const char *oid_pp, const char *oid_ppp) { const git_index_entry *ie; const git_tree_entry *te; const git_tree *tree; git_buf path = GIT_BUF_INIT; cl_git_pass(git_iterator_current_tree_entry(&te, i)); cl_assert(te); cl_assert(git_oid_streq(te->oid, oid) == 0); cl_git_pass(git_iterator_current(&ie, i)); cl_git_pass(git_buf_sets(&path, ie->path)); if (oid_p) { git_buf_rtruncate_at_char(&path, '/'); cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr)); cl_assert(tree); cl_assert(git_oid_streq(git_tree_id(tree), oid_p) == 0); } if (oid_pp) { git_buf_rtruncate_at_char(&path, '/'); cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr)); cl_assert(tree); cl_assert(git_oid_streq(git_tree_id(tree), oid_pp) == 0); } if (oid_ppp) { git_buf_rtruncate_at_char(&path, '/'); cl_git_pass(git_iterator_current_parent_tree(&tree, i, path.ptr)); cl_assert(tree); cl_assert(git_oid_streq(git_tree_id(tree), oid_ppp) == 0); } git_buf_free(&path); }
static int futils__rm_first_parent(git_buf *path, const char *ceiling) { int error = GIT_ENOTFOUND; struct stat st; while (error == GIT_ENOTFOUND) { git_buf_rtruncate_at_char(path, '/'); if (!path->size || git__prefixcmp(path->ptr, ceiling) != 0) error = 0; else if (p_lstat_posixly(path->ptr, &st) == 0) { if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) error = p_unlink(path->ptr); else if (!S_ISDIR(st.st_mode)) error = -1; /* fail to remove non-regular file */ } else if (errno != ENOTDIR) error = -1; } if (error) futils__error_cannot_rmdir(path->ptr, "cannot remove parent"); return error; }
int git_futils_mkdir( const char *path, const char *base, mode_t mode, uint32_t flags) { int error = -1; git_buf make_path = GIT_BUF_INIT; ssize_t root = 0, min_root_len; char lastch = '/', *tail; struct stat st; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&make_path, path, base, &root) < 0) return -1; if (make_path.size == 0) { giterr_set(GITERR_OS, "Attempt to create empty path"); goto done; } /* remove trailing slashes on path */ while (make_path.ptr[make_path.size - 1] == '/') { make_path.size--; make_path.ptr[make_path.size] = '\0'; } /* 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, '/'); /* if nothing left after truncation, then we're done! */ if (!make_path.size) { error = 0; goto done; } /* if we are not supposed to make the whole path, reset root */ if ((flags & GIT_MKDIR_PATH) == 0) root = git_buf_rfind(&make_path, '/'); /* advance root past drive name or network mount prefix */ min_root_len = git_path_root(make_path.ptr); if (root < min_root_len) root = min_root_len; while (root >= 0 && make_path.ptr[root] == '/') ++root; /* clip root to make_path length */ if (root > (ssize_t)make_path.size) root = (ssize_t)make_path.size; /* i.e. NUL byte of string */ if (root < 0) root = 0; /* walk down tail of path making each directory */ for (tail = &make_path.ptr[root]; *tail; *tail = lastch) { /* advance tail to include next path component */ while (*tail == '/') tail++; while (*tail && *tail != '/') tail++; /* truncate path at next component */ lastch = *tail; *tail = '\0'; st.st_mode = 0; /* make directory */ if (p_mkdir(make_path.ptr, mode) < 0) { int tmp_errno = giterr_system_last(); /* ignore error if not at end or if directory already exists */ if (lastch == '\0' && (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) { giterr_system_set(tmp_errno); giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); 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); error = GIT_EEXISTS; goto done; } } /* chmod if requested and necessary */ if (((flags & GIT_MKDIR_CHMOD_PATH) != 0 || (lastch == '\0' && (flags & GIT_MKDIR_CHMOD) != 0)) && st.st_mode != mode && (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; } } error = 0; /* check that full path really is a directory if requested & needed */ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && lastch != '\0' && (p_stat(make_path.ptr, &st) < 0 || !S_ISDIR(st.st_mode))) { giterr_set(GITERR_OS, "Path is not a directory '%s'", make_path.ptr); error = GIT_ENOTFOUND; } done: git_buf_free(&make_path); return error; }
int git_futils_mkdir( const char *path, const char *base, mode_t mode, uint32_t flags) { git_buf make_path = GIT_BUF_INIT; ssize_t root = 0; char lastch, *tail; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&make_path, path, base, &root) < 0) return -1; if (make_path.size == 0) { giterr_set(GITERR_OS, "Attempt to create empty path"); goto fail; } /* remove trailing slashes on path */ while (make_path.ptr[make_path.size - 1] == '/') { make_path.size--; make_path.ptr[make_path.size] = '\0'; } /* if we are not supposed to made the last element, truncate it */ if ((flags & GIT_MKDIR_SKIP_LAST) != 0) git_buf_rtruncate_at_char(&make_path, '/'); /* if we are not supposed to make the whole path, reset root */ if ((flags & GIT_MKDIR_PATH) == 0) root = git_buf_rfind(&make_path, '/'); /* clip root to make_path length */ if (root >= (ssize_t)make_path.size) root = (ssize_t)make_path.size - 1; if (root < 0) root = 0; tail = & make_path.ptr[root]; while (*tail) { /* advance tail to include next path component */ while (*tail == '/') tail++; while (*tail && *tail != '/') tail++; /* truncate path at next component */ lastch = *tail; *tail = '\0'; /* make directory */ if (p_mkdir(make_path.ptr, mode) < 0 && (errno != EEXIST || (flags & GIT_MKDIR_EXCL) != 0)) { giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); goto fail; } /* chmod if requested */ if ((flags & GIT_MKDIR_CHMOD_PATH) != 0 || ((flags & GIT_MKDIR_CHMOD) != 0 && lastch == '\0')) { if (p_chmod(make_path.ptr, mode) < 0) { giterr_set(GITERR_OS, "Failed to set permissions on '%s'", make_path.ptr); goto fail; } } *tail = lastch; } git_buf_free(&make_path); return 0; fail: git_buf_free(&make_path); return -1; }