void test_clone_nonetwork__do_not_clean_existing_directory(void) { git_buf path_buf = GIT_BUF_INIT; git_buf_put(&path_buf, "./foo", 5); /* Clone should not remove the directory if it already exists, but * Should clean up entries it creates. */ p_mkdir("./foo", GIT_DIR_MODE); cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options)); cl_assert(git_path_exists("./foo")); /* Make sure the directory is empty. */ cl_git_pass(git_path_direach(&path_buf, dont_call_me, NULL)); /* Try again with a bare repository. */ g_options.bare = true; cl_git_fail(git_clone(&g_repo, "not_a_repo", "./foo", &g_options)); cl_assert(git_path_exists("./foo")); /* Make sure the directory is empty. */ cl_git_pass(git_path_direach(&path_buf, dont_call_me, NULL)); git_buf_free(&path_buf); }
/* this test is equivalent to t18-status.c:statuscb2 */ void test_status_worktree__purged_worktree(void) { status_entry_counts counts; git_repository *repo = cl_git_sandbox_init("status"); git_buf workdir = GIT_BUF_INIT; /* first purge the contents of the worktree */ cl_git_pass(git_buf_sets(&workdir, git_repository_workdir(repo))); cl_git_pass(git_path_direach(&workdir, remove_file_cb, NULL)); git_buf_free(&workdir); /* now get status */ memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = entry_count2; counts.expected_paths = entry_paths2; counts.expected_statuses = entry_statuses2; cl_git_pass( git_status_foreach(repo, cb_status__normal, &counts) ); cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); cl_assert_equal_i(0, counts.wrong_status_flags_count); cl_assert_equal_i(0, counts.wrong_sorted_path); }
int git_futils_cleanupdir_r(const char *path) { int error; git_buf fullpath = GIT_BUF_INIT; futils__rmdir_data data; if ((error = git_buf_put(&fullpath, path, strlen(path))) < 0) goto clean_up; data.base = ""; data.baselen = 0; data.flags = GIT_RMDIR_REMOVE_FILES; data.error = 0; if (!git_path_exists(path)) { giterr_set(GITERR_OS, "Path does not exist: %s" , path); error = GIT_ERROR; goto clean_up; } if (!git_path_isdir(path)) { giterr_set(GITERR_OS, "Path is not a directory: %s" , path); error = GIT_ERROR; goto clean_up; } error = git_path_direach(&fullpath, futils__rmdir_recurs_foreach, &data); if (error == GIT_EUSER) error = data.error; clean_up: git_buf_free(&fullpath); return error; }
static int loose_backend__foreach(git_odb_backend *_backend, git_odb_foreach_cb cb, void *data) { char *objects_dir; int error; git_buf buf = GIT_BUF_INIT; struct foreach_state state; loose_backend *backend = (loose_backend *) _backend; assert(backend && cb); objects_dir = backend->objects_dir; git_buf_sets(&buf, objects_dir); git_path_to_dir(&buf); if (git_buf_oom(&buf)) return -1; memset(&state, 0, sizeof(state)); state.cb = cb; state.data = data; state.dir_len = git_buf_len(&buf); error = git_path_direach(&buf, 0, foreach_cb, &state); git_buf_dispose(&buf); return error; }
static int _rmdir_recurs_foreach(void *opaque, git_buf *path) { git_directory_removal_type removal_type = *(git_directory_removal_type *)opaque; if (git_path_isdir(path->ptr) == true) { if (git_path_direach(path, _rmdir_recurs_foreach, opaque) < 0) return -1; if (p_rmdir(path->ptr) < 0) { if (removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS && (errno == ENOTEMPTY || errno == EEXIST)) return 0; giterr_set(GITERR_OS, "Could not remove directory '%s'", path->ptr); return -1; } return 0; } if (removal_type == GIT_DIRREMOVAL_FILES_AND_DIRS) { if (p_unlink(path->ptr) < 0) { giterr_set(GITERR_OS, "Could not remove directory. File '%s' cannot be removed", path->ptr); return -1; } return 0; } if (removal_type == GIT_DIRREMOVAL_EMPTY_HIERARCHY) { giterr_set(GITERR_OS, "Could not remove directory. File '%s' still present", path->ptr); return -1; } return 0; }
static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) { int error = 0; futils__rmdir_data *data = opaque; struct stat st; if (data->depth > FUTILS_MAX_DEPTH) error = futils__error_cannot_rmdir( path->ptr, "directory nesting too deep"); else if ((error = p_lstat_posixly(path->ptr, &st)) < 0) { if (errno == ENOENT) error = 0; else if (errno == ENOTDIR) { /* asked to remove a/b/c/d/e and a/b is a normal file */ if ((data->flags & GIT_RMDIR_REMOVE_BLOCKERS) != 0) error = futils__rm_first_parent(path, data->base); else futils__error_cannot_rmdir( path->ptr, "parent is not directory"); } else error = git_path_set_error(errno, path->ptr, "rmdir"); } else if (S_ISDIR(st.st_mode)) { data->depth++; error = git_path_direach(path, 0, futils__rmdir_recurs_foreach, data); data->depth--; if (error < 0) return error; if (data->depth == 0 && (data->flags & GIT_RMDIR_SKIP_ROOT) != 0) return error; if ((error = p_rmdir(path->ptr)) < 0) { if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 && (errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY)) error = 0; else error = git_path_set_error(errno, path->ptr, "rmdir"); } } else if ((data->flags & GIT_RMDIR_REMOVE_FILES) != 0) { if (p_unlink(path->ptr) < 0) error = git_path_set_error(errno, path->ptr, "remove"); } else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0) error = futils__error_cannot_rmdir(path->ptr, "still present"); return error; }
static int foreach_cb(void *_state, git_buf *path) { struct foreach_state *state = (struct foreach_state *) _state; /* non-dir is some stray file, ignore it */ if (!git_path_isdir(git_buf_cstr(path))) return 0; return git_path_direach(path, 0, foreach_object_dir_cb, state); }
static int futils__rmdir_recurs_foreach(void *opaque, git_buf *path) { struct stat st; futils__rmdir_data *data = opaque; if ((data->error = p_lstat_posixly(path->ptr, &st)) < 0) { if (errno == ENOENT) data->error = 0; else if (errno == ENOTDIR) { /* asked to remove a/b/c/d/e and a/b is a normal file */ if ((data->flags & GIT_RMDIR_REMOVE_BLOCKERS) != 0) data->error = futils__rm_first_parent(path, data->base); else futils__error_cannot_rmdir( path->ptr, "parent is not directory"); } else futils__error_cannot_rmdir(path->ptr, "cannot access"); } else if (S_ISDIR(st.st_mode)) { int error = git_path_direach(path, futils__rmdir_recurs_foreach, data); if (error < 0) return (error == GIT_EUSER) ? data->error : error; data->error = p_rmdir(path->ptr); if (data->error < 0) { if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) != 0 && (errno == ENOTEMPTY || errno == EEXIST || errno == EBUSY)) data->error = 0; else futils__error_cannot_rmdir(path->ptr, NULL); } } else if ((data->flags & GIT_RMDIR_REMOVE_FILES) != 0) { data->error = p_unlink(path->ptr); if (data->error < 0) futils__error_cannot_rmdir(path->ptr, "cannot be removed"); } else if ((data->flags & GIT_RMDIR_SKIP_NONEMPTY) == 0) data->error = futils__error_cannot_rmdir(path->ptr, "still present"); return data->error; }
bool git_path_is_empty_dir(const char *path) { int error; git_buf dir = GIT_BUF_INIT; if (!git_path_isdir(path)) return false; if ((error = git_buf_sets(&dir, path)) != 0) giterr_clear(); else error = git_path_direach(&dir, 0, path_found_entry, NULL); git_buf_free(&dir); return !error; }
static int find_tmp_file_recurs(void *opaque, git_buf *path) { int error = 0; git_buf *first_tmp_file = opaque; struct stat st; if ((error = p_lstat_posixly(path->ptr, &st)) < 0) return error; if (S_ISDIR(st.st_mode)) return git_path_direach(path, 0, find_tmp_file_recurs, opaque); /* This is the template that's used in git_futils_mktmp. */ if (strstr(git_buf_cstr(path), "_git2_") != NULL) return git_buf_sets(first_tmp_file, git_buf_cstr(path)); return 0; }
static int remove_placeholders_recurs(void *_data, git_buf *path) { remove_data *data = (remove_data *)_data; size_t pathlen; if (git_path_isdir(path->ptr) == true) return git_path_direach(path, remove_placeholders_recurs, data); pathlen = path->size; if (pathlen < data->filename_len) return 0; /* if path ends in '/'+filename (or equals filename) */ if (!strcmp(data->filename, path->ptr + pathlen - data->filename_len) && (pathlen == data->filename_len || path->ptr[pathlen - data->filename_len - 1] == '/')) return p_unlink(path->ptr); return 0; }
/*********************************************************** * * PACKED BACKEND PUBLIC API * * Implement the git_odb_backend API calls * ***********************************************************/ static int pack_backend__refresh(git_odb_backend *backend_) { int error; struct stat st; git_buf path = GIT_BUF_INIT; struct pack_backend *backend = (struct pack_backend *)backend_; if (backend->pack_folder == NULL) return 0; if (p_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) return git_odb__error_notfound("failed to refresh packfiles", NULL); git_buf_sets(&path, backend->pack_folder); /* reload all packs */ error = git_path_direach(&path, 0, packfile_load__cb, backend); git_buf_free(&path); git_vector_sort(&backend->packs); return error; }
int merge_test_workdir(git_repository *repo, const struct merge_index_entry expected[], size_t expected_len) { size_t actual_len = 0, i; git_oid actual_oid, expected_oid; git_buf wd = GIT_BUF_INIT; git_buf_puts(&wd, repo->workdir); git_path_direach(&wd, 0, dircount, &actual_len); if (actual_len != expected_len) return 0; for (i = 0; i < expected_len; i++) { git_blob_create_fromworkdir(&actual_oid, repo, expected[i].path); git_oid_fromstr(&expected_oid, expected[i].oid_str); if (git_oid_cmp(&actual_oid, &expected_oid) != 0) return 0; } git_buf_free(&wd); return 1; }
/* Locate an object matching a given short oid */ static int locate_object_short_oid( git_buf *object_location, git_oid *res_oid, loose_backend *backend, const git_oid *short_oid, size_t len) { char *objects_dir = backend->objects_dir; size_t dir_len = strlen(objects_dir), alloc_len; loose_locate_object_state state; int error; /* prealloc memory for OBJ_DIR/xx/xx..38x..xx */ GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 3); if (git_buf_grow(object_location, alloc_len) < 0) return -1; git_buf_set(object_location, objects_dir, dir_len); git_path_to_dir(object_location); /* save adjusted position at end of dir so it can be restored later */ dir_len = git_buf_len(object_location); /* Convert raw oid to hex formatted oid */ git_oid_fmt((char *)state.short_oid, short_oid); /* Explore OBJ_DIR/xx/ where xx is the beginning of hex formatted short oid */ if (git_buf_put(object_location, (char *)state.short_oid, 3) < 0) return -1; object_location->ptr[object_location->size - 1] = '/'; /* Check that directory exists */ if (git_path_isdir(object_location->ptr) == false) return git_odb__error_notfound("no matching loose object for prefix", short_oid, len); state.dir_len = git_buf_len(object_location); state.short_oid_len = len; state.found = 0; /* Explore directory to find a unique object matching short_oid */ error = git_path_direach( object_location, 0, fn_locate_object_short_oid, &state); if (error < 0 && error != GIT_EAMBIGUOUS) return error; if (!state.found) return git_odb__error_notfound("no matching loose object for prefix", short_oid, len); if (state.found > 1) return git_odb__error_ambiguous("multiple matches in loose objects"); /* Convert obtained hex formatted oid to raw */ error = git_oid_fromstr(res_oid, (char *)state.res_oid); if (error) return error; /* Update the location according to the oid obtained */ GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ); GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2); git_buf_truncate(object_location, dir_len); if (git_buf_grow(object_location, alloc_len) < 0) return -1; git_oid_pathfmt(object_location->ptr + dir_len, res_oid); object_location->size += GIT_OID_HEXSZ + 1; object_location->ptr[object_location->size] = '\0'; return 0; }