void test_repo_open__gitlinked(void) { /* need to have both repo dir and workdir set up correctly */ git_repository *repo = cl_git_sandbox_init("empty_standard_repo"); git_repository *repo2; cl_must_pass(p_mkdir("alternate", 0777)); cl_git_mkfile("alternate/.git", "gitdir: ../empty_standard_repo/.git"); cl_git_pass(git_repository_open(&repo2, "alternate")); cl_assert(git_repository_path(repo2) != NULL); cl_assert_(git__suffixcmp(git_repository_path(repo2), "empty_standard_repo/.git/") == 0, git_repository_path(repo2)); cl_assert_equal_s(git_repository_path(repo), git_repository_path(repo2)); cl_assert(git_repository_workdir(repo2) != NULL); cl_assert_(git__suffixcmp(git_repository_workdir(repo2), "alternate/") == 0, git_repository_workdir(repo2)); git_repository_free(repo2); }
GIT_INLINE(int) validate_existing( const char *make_path, struct stat *st, mode_t mode, uint32_t flags, struct git_futils_mkdir_perfdata *perfdata) { if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) || (S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) { if (p_unlink(make_path) < 0) { giterr_set(GITERR_OS, "Failed to remove %s '%s'", S_ISLNK(st->st_mode) ? "symlink" : "file", make_path); return GIT_EEXISTS; } perfdata->mkdir_calls++; if (p_mkdir(make_path, mode) < 0) { giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path); return GIT_EEXISTS; } } else if (S_ISLNK(st->st_mode)) { /* Re-stat the target, make sure it's a directory */ perfdata->stat_calls++; if (p_stat(make_path, st) < 0) { giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path); return GIT_EEXISTS; } } else if (!S_ISDIR(st->st_mode)) { giterr_set(GITERR_FILESYSTEM, "Failed to make directory '%s': directory exists", make_path); return GIT_EEXISTS; } return 0; }
void test_config_global__open_programdata(void) { git_config *cfg; git_repository *repo; git_buf config_path = GIT_BUF_INIT; git_buf var_contents = GIT_BUF_INIT; if (cl_is_env_set("GITTEST_INVASIVE_FS_STRUCTURE")) cl_skip(); cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_PROGRAMDATA, &config_path)); if (!git_path_isdir(config_path.ptr)) cl_git_pass(p_mkdir(config_path.ptr, 0777)); cl_git_pass(git_buf_puts(&config_path, "/config")); cl_git_pass(git_config_open_ondisk(&cfg, config_path.ptr)); cl_git_pass(git_config_set_string(cfg, "programdata.var", "even higher level")); git_buf_free(&config_path); git_config_free(cfg); git_config_open_default(&cfg); cl_git_pass(git_config_get_string_buf(&var_contents, cfg, "programdata.var")); cl_assert_equal_s("even higher level", var_contents.ptr); git_config_free(cfg); git_buf_free(&var_contents); cl_git_pass(git_repository_init(&repo, "./foo.git", true)); cl_git_pass(git_repository_config(&cfg, repo)); cl_git_pass(git_config_get_string_buf(&var_contents, cfg, "programdata.var")); cl_assert_equal_s("even higher level", var_contents.ptr); git_config_free(cfg); git_buf_free(&var_contents); git_repository_free(repo); cl_fixture_cleanup("./foo.git"); }
static int rebase_setupfiles(git_rebase *rebase) { char onto[GIT_OID_HEXSZ], orig_head[GIT_OID_HEXSZ]; git_oid_fmt(onto, &rebase->onto_id); git_oid_fmt(orig_head, &rebase->orig_head_id); if (p_mkdir(rebase->state_path, REBASE_DIR_MODE) < 0) { giterr_set(GITERR_OS, "Failed to create rebase directory '%s'", rebase->state_path); return -1; } if (git_repository__set_orig_head(rebase->repo, &rebase->orig_head_id) < 0 || rebase_setupfile(rebase, HEAD_NAME_FILE, -1, "%s\n", rebase->orig_head_name) < 0 || rebase_setupfile(rebase, ONTO_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, onto) < 0 || rebase_setupfile(rebase, ORIG_HEAD_FILE, -1, "%.*s\n", GIT_OID_HEXSZ, orig_head) < 0 || rebase_setupfile(rebase, QUIET_FILE, -1, rebase->quiet ? "t\n" : "\n") < 0) return -1; return rebase_setupfiles_merge(rebase); }
//updated void SaveJTRAIL(edict_t *ent, int cmd) { char *opt; char JTRAILFile[256]; char path[256]; if (TrailsBanned()) return; if (ltnodes < 1) { gi.cprintf(ent,PRINT_HIGH,"No jump trails to save!\n"); return; } if (gi.argc() != 3) { if (cmd == 1) gi.cprintf(ent,PRINT_HIGH, "Wrong syntax: jtrailsave <all/view/last> <filename>\n"); else gi.cprintf(ent,PRINT_HIGH, "Wrong syntax: tsave <all/view/last> <filename>\n"); return; } if (BadFileName(gi.args())) { gi.cprintf(ent,PRINT_HIGH,"Illegal characters found in filename. JTrail not saved.\n"); return; } opt = strtok(gi.args()," "); sprintf (path, GAMEVERSION "/jtrail"); p_mkdir(path); sprintf (JTRAILFile, GAMEVERSION "/jtrail/%s-%s.jtrail", level.mapname, strtok(NULL," ")); if (!Q_stricmp(opt,"all")) SaveJTRAIL_all(ent,JTRAILFile); else if (!Q_stricmp(opt,"view")) SaveJTRAIL_view(ent,JTRAILFile); else if (!Q_stricmp(opt,"last")) SaveJTRAIL_last(ent,JTRAILFile); else gi.cprintf(ent,PRINT_HIGH, "Unknown save option \"%s\". Valid options are \"view\", \"all\", and \"last\"\n",opt); }
void test_iterator_workdir__advance_into(void) { git_iterator *i; git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT; g_repo = cl_git_sandbox_init("icase"); i_opts.flags |= GIT_ITERATOR_DONT_IGNORE_CASE | GIT_ITERATOR_DONT_AUTOEXPAND; cl_must_pass(p_mkdir("icase/Empty", 0777)); cl_git_pass(git_iterator_for_workdir(&i, g_repo, NULL, NULL, &i_opts)); expect_advance_into(i, "B"); expect_advance_into(i, "D"); expect_advance_into(i, "Empty/"); expect_advance_into(i, "F"); expect_advance_into(i, "H"); expect_advance_into(i, "J"); expect_advance_into(i, "L/"); expect_advance_into(i, "L/1"); expect_advance_into(i, "L/B"); expect_advance_into(i, "L/D"); expect_advance_into(i, "L/a"); expect_advance_into(i, "L/c"); expect_advance_into(i, "a"); expect_advance_into(i, "c"); expect_advance_into(i, "e"); expect_advance_into(i, "g"); expect_advance_into(i, "i"); expect_advance_into(i, "k/"); expect_advance_into(i, "k/1"); expect_advance_into(i, "k/B"); expect_advance_into(i, "k/D"); expect_advance_into(i, "k/a"); expect_advance_into(i, "k/c"); cl_git_fail_with(GIT_ITEROVER, git_iterator_advance(NULL, i)); git_iterator_free(i); }
void test_index_addall__files_in_folders(void) { git_index *index; git_strarray paths = { NULL, 0 }; addall_create_test_repo(true); cl_git_pass(git_repository_index(&index, g_repo)); cl_git_pass(git_index_add_all(index, NULL, 0, NULL, NULL)); check_stat_data(index, TEST_DIR "/file.bar", true); check_status(g_repo, 2, 0, 0, 0, 0, 0, 1, 0); cl_must_pass(p_mkdir(TEST_DIR "/subdir", 0777)); cl_git_mkfile(TEST_DIR "/subdir/file", "hello!\n"); check_status(g_repo, 2, 0, 0, 1, 0, 0, 1, 0); cl_git_pass(git_index_add_all(index, NULL, 0, NULL, NULL)); check_status(g_repo, 3, 0, 0, 0, 0, 0, 1, 0); git_index_free(index); }
static void configure_templatedir(const char *template_path) { git_buf config_path = GIT_BUF_INIT; git_buf config_data = GIT_BUF_INIT; cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &_tmp_path)); cl_git_pass(git_buf_puts(&_tmp_path, ".tmp")); cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, _tmp_path.ptr)); cl_must_pass(p_mkdir(_tmp_path.ptr, 0777)); cl_git_pass(git_buf_joinpath(&config_path, _tmp_path.ptr, ".gitconfig")); cl_git_pass(git_buf_printf(&config_data, "[init]\n\ttemplatedir = \"%s\"\n", template_path)); cl_git_mkfile(config_path.ptr, config_data.ptr); git_buf_free(&config_path); git_buf_free(&config_data); }
void test_status_worktree__status_file_without_index_or_workdir(void) { git_repository *repo; unsigned int status = 0; git_index *index; cl_git_pass(p_mkdir("wd", 0777)); cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_git_pass(git_repository_set_workdir(repo, "wd", false)); cl_git_pass(git_index_open(&index, "empty-index")); cl_assert_equal_i(0, git_index_entrycount(index)); git_repository_set_index(repo, index); cl_git_pass(git_status_file(&status, repo, "branch_file.txt")); cl_assert_equal_i(GIT_STATUS_INDEX_DELETED, status); git_repository_free(repo); git_index_free(index); cl_git_pass(p_rmdir("wd")); }
void test_diff_racediffiter__basic(void) { git_diff_options opts = GIT_DIFF_OPTIONS_INIT; git_repository *repo = cl_git_sandbox_init("diff"); git_diff *diff; basic_payload exp_a[] = { { "another.txt", GIT_DELTA_MODIFIED }, { "readme.txt", GIT_DELTA_MODIFIED }, { "zzzzz/", GIT_DELTA_IGNORED }, { NULL, 0 } }; cl_must_pass(p_mkdir("diff/zzzzz", 0777)); opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_RECURSE_UNTRACKED_DIRS; opts.notify_cb = notify_cb__basic; opts.payload = exp_a; cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); git_diff_free(diff); }
void test_repo_open__no_config(void) { git_buf path = GIT_BUF_INIT; git_repository *repo; git_config *config; cl_fixture_sandbox("empty_standard_repo"); cl_git_pass(cl_rename( "empty_standard_repo/.gitted", "empty_standard_repo/.git")); /* remove local config */ cl_git_pass(git_futils_rmdir_r( "empty_standard_repo/.git/config", NULL, GIT_RMDIR_REMOVE_FILES)); /* isolate from system level configs */ cl_must_pass(p_mkdir("alternate", 0777)); cl_git_pass(git_path_prettify(&path, "alternate", NULL)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); git_buf_free(&path); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); cl_git_pass(git_repository_config(&config, repo)); cl_git_pass(git_config_set_string(config, "test.set", "42")); git_config_free(config); git_repository_free(repo); cl_fixture_cleanup("empty_standard_repo"); cl_sandbox_set_search_path_defaults(); }
void test_repo_open__bad_gitlinks(void) { git_repository *repo; static const char *bad_links[] = { "garbage\n", "gitdir", "gitdir:\n", "gitdir: foobar", "gitdir: ../invalid", "gitdir: ../invalid2", "gitdir: ../attr/.git with extra stuff", NULL }; const char **scan; cl_git_sandbox_init("attr"); cl_git_pass(p_mkdir("invalid", 0777)); cl_git_pass(git_futils_mkdir_r("invalid2/.git", NULL, 0777)); for (scan = bad_links; *scan != NULL; scan++) { make_gitlink_dir("alternate", *scan); cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL)); } git_futils_rmdir_r("invalid", NULL, GIT_RMDIR_REMOVE_FILES); git_futils_rmdir_r("invalid2", NULL, GIT_RMDIR_REMOVE_FILES); }
void test_iterator_workdir__skips_fifos_and_special_files(void) { #ifndef GIT_WIN32 git_iterator *i; const git_index_entry *e; git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT; g_repo = cl_git_sandbox_init("empty_standard_repo"); cl_must_pass(p_mkdir("empty_standard_repo/dir", 0777)); cl_git_mkfile("empty_standard_repo/file", "not me"); cl_assert(!mkfifo("empty_standard_repo/fifo", 0777)); cl_assert(!access("empty_standard_repo/fifo", F_OK)); i_opts.flags = GIT_ITERATOR_INCLUDE_TREES | GIT_ITERATOR_DONT_AUTOEXPAND; cl_git_pass(git_iterator_for_filesystem( &i, "empty_standard_repo", &i_opts)); cl_git_pass(git_iterator_advance(&e, i)); /* .git */ cl_assert(S_ISDIR(e->mode)); cl_git_pass(git_iterator_advance(&e, i)); /* dir */ cl_assert(S_ISDIR(e->mode)); /* skips fifo */ cl_git_pass(git_iterator_advance(&e, i)); /* file */ cl_assert(S_ISREG(e->mode)); cl_assert_equal_i(GIT_ITEROVER, git_iterator_advance(&e, i)); git_iterator_free(i); #else cl_skip(); #endif }
void test_checkout_tree__can_write_to_empty_dirs(void) { git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid oid; git_object *obj = NULL; assert_on_branch(g_repo, "master"); cl_git_pass(p_mkdir("testrepo/a", 0777)); /* do first checkout with FORCE because we don't know if testrepo * base data is clean for a checkout or not */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_assert(git_path_isfile("testrepo/a/b.txt")); git_object_free(obj); }
void test_checkout_tree__can_checkout_with_last_workdir_item_missing(void) { git_index *index = NULL; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; git_oid tree_id, commit_id; git_tree *tree = NULL; git_commit *commit = NULL; git_repository_index(&index, g_repo); opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_reference_name_to_id(&commit_id, g_repo, "refs/heads/master")); cl_git_pass(git_commit_lookup(&commit, g_repo, &commit_id)); cl_git_pass(git_checkout_tree(g_repo, (git_object *)commit, &opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/master")); cl_git_pass(p_mkdir("./testrepo/this-is-dir", 0777)); cl_git_mkfile("./testrepo/this-is-dir/contained_file", "content\n"); cl_git_pass(git_index_add_bypath(index, "this-is-dir/contained_file")); git_index_write_tree(&tree_id, index); cl_git_pass(git_tree_lookup(&tree, g_repo, &tree_id)); cl_git_pass(p_unlink("./testrepo/this-is-dir/contained_file")); opts.checkout_strategy = GIT_CHECKOUT_SAFE; opts.checkout_strategy = 1; git_checkout_tree(g_repo, (git_object *)tree, &opts); git_tree_free(tree); git_commit_free(commit); git_index_free(index); }
void test_core_rmdir__initialize(void) { git_buf path = GIT_BUF_INIT; cl_must_pass(p_mkdir(empty_tmp_dir, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one")); cl_must_pass(p_mkdir(path.ptr, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_one")); cl_must_pass(p_mkdir(path.ptr, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two")); cl_must_pass(p_mkdir(path.ptr, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/one/two_two/three")); cl_must_pass(p_mkdir(path.ptr, 0777)); cl_git_pass(git_buf_joinpath(&path, empty_tmp_dir, "/two")); cl_must_pass(p_mkdir(path.ptr, 0777)); git_buf_dispose(&path); }
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; }
void test_repo_config__read_with_no_configs_at_all(void) { git_repository *repo; int val; cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); /* with none */ cl_must_pass(p_unlink("empty_standard_repo/.git/config")); cl_assert(!git_path_isfile("empty_standard_repo/.git/config")); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(GIT_ABBREV_DEFAULT, val); git_repository_free(repo); /* with no local config, just system */ cl_sandbox_set_search_path_defaults(); cl_must_pass(p_mkdir("alternate/1", 0777)); cl_git_pass(git_buf_joinpath(&path, path.ptr, "1")); cl_git_rewritefile("alternate/1/gitconfig", "[core]\n\tabbrev = 10\n"); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr)); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(10, val); git_repository_free(repo); /* with just xdg + system */ cl_must_pass(p_mkdir("alternate/2", 0777)); path.ptr[path.size - 1] = '2'; cl_git_rewritefile("alternate/2/config", "[core]\n\tabbrev = 20\n"); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr)); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(20, val); git_repository_free(repo); /* with global + xdg + system */ cl_must_pass(p_mkdir("alternate/3", 0777)); path.ptr[path.size - 1] = '3'; cl_git_rewritefile("alternate/3/.gitconfig", "[core]\n\tabbrev = 30\n"); cl_git_pass(git_libgit2_opts( GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr)); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(30, val); git_repository_free(repo); /* with all configs */ cl_git_rewritefile("empty_standard_repo/.git/config", "[core]\n\tabbrev = 40\n"); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(40, val); git_repository_free(repo); /* with all configs but delete the files ? */ cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(40, val); cl_must_pass(p_unlink("empty_standard_repo/.git/config")); cl_assert(!git_path_isfile("empty_standard_repo/.git/config")); cl_must_pass(p_unlink("alternate/1/gitconfig")); cl_assert(!git_path_isfile("alternate/1/gitconfig")); cl_must_pass(p_unlink("alternate/2/config")); cl_assert(!git_path_isfile("alternate/2/config")); cl_must_pass(p_unlink("alternate/3/.gitconfig")); cl_assert(!git_path_isfile("alternate/3/.gitconfig")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(40, val); git_repository_free(repo); /* reopen */ cl_assert(!git_path_isfile("empty_standard_repo/.git/config")); cl_assert(!git_path_isfile("alternate/3/.gitconfig")); cl_git_pass(git_repository_open(&repo, "empty_standard_repo")); git_repository__cvar_cache_clear(repo); val = -1; cl_git_pass(git_repository__cvar(&val, repo, GIT_CVAR_ABBREV)); cl_assert_equal_i(7, val); git_repository_free(repo); cl_assert(!git_path_exists("empty_standard_repo/.git/config")); cl_assert(!git_path_exists("alternate/3/.gitconfig")); }
void test_diff_iterator__workdir_builtin_ignores(void) { git_repository *repo = cl_git_sandbox_init("attr"); git_iterator *i; git_iterator_options i_opts = GIT_ITERATOR_OPTIONS_INIT; const git_index_entry *entry; int idx; static struct { const char *path; bool ignored; } expected[] = { { "dir/", true }, { "file", false }, { "ign", true }, { "macro_bad", false }, { "macro_test", false }, { "root_test1", false }, { "root_test2", false }, { "root_test3", false }, { "root_test4.txt", false }, { "sub/", false }, { "sub/.gitattributes", false }, { "sub/abc", false }, { "sub/dir/", true }, { "sub/file", false }, { "sub/ign/", true }, { "sub/sub/", false }, { "sub/sub/.gitattributes", false }, { "sub/sub/dir", false }, /* file is not actually a dir */ { "sub/sub/file", false }, { NULL, false } }; cl_git_pass(p_mkdir("attr/sub/sub/.git", 0777)); cl_git_mkfile("attr/sub/.git", "whatever"); i_opts.flags = GIT_ITERATOR_DONT_AUTOEXPAND; i_opts.start = "dir"; i_opts.end = "sub/sub/file"; cl_git_pass(git_iterator_for_workdir( &i, repo, NULL, NULL, &i_opts)); cl_git_pass(git_iterator_current(&entry, i)); for (idx = 0; entry != NULL; ++idx) { int ignored = git_iterator_current_is_ignored(i); cl_assert_equal_s(expected[idx].path, entry->path); cl_assert_(ignored == expected[idx].ignored, expected[idx].path); if (!ignored && (entry->mode == GIT_FILEMODE_TREE || entry->mode == GIT_FILEMODE_COMMIT)) { /* it is possible to advance "into" a submodule */ cl_git_pass(git_iterator_advance_into(&entry, i)); } else { int error = git_iterator_advance(&entry, i); cl_assert(!error || error == GIT_ITEROVER); } } cl_assert(expected[idx].path == NULL); git_iterator_free(i); }
void test_repo_open__from_git_new_workdir(void) { /* The git-new-workdir script that ships with git sets up a bunch of * symlinks to create a second workdir that shares the object db with * another checkout. Libgit2 can open a repo that has been configured * this way. */ cl_git_sandbox_init("empty_standard_repo"); #ifndef GIT_WIN32 git_repository *repo2; git_buf link_tgt = GIT_BUF_INIT, link = GIT_BUF_INIT, body = GIT_BUF_INIT; const char **scan; int link_fd; static const char *links[] = { "config", "refs", "logs/refs", "objects", "info", "hooks", "packed-refs", "remotes", "rr-cache", "svn", NULL }; static const char *copies[] = { "HEAD", NULL }; cl_git_pass(p_mkdir("alternate", 0777)); cl_git_pass(p_mkdir("alternate/.git", 0777)); for (scan = links; *scan != NULL; scan++) { git_buf_joinpath(&link_tgt, "empty_standard_repo/.git", *scan); if (git_path_exists(link_tgt.ptr)) { git_buf_joinpath(&link_tgt, "../../empty_standard_repo/.git", *scan); git_buf_joinpath(&link, "alternate/.git", *scan); if (strchr(*scan, '/')) git_futils_mkpath2file(link.ptr, 0777); cl_assert_(symlink(link_tgt.ptr, link.ptr) == 0, strerror(errno)); } } for (scan = copies; *scan != NULL; scan++) { git_buf_joinpath(&link_tgt, "empty_standard_repo/.git", *scan); if (git_path_exists(link_tgt.ptr)) { git_buf_joinpath(&link, "alternate/.git", *scan); cl_git_pass(git_futils_readbuffer(&body, link_tgt.ptr)); cl_assert((link_fd = git_futils_creat_withpath(link.ptr, 0777, 0666)) >= 0); cl_must_pass(p_write(link_fd, body.ptr, body.size)); p_close(link_fd); } } git_buf_free(&link_tgt); git_buf_free(&link); git_buf_free(&body); cl_git_pass(git_repository_open(&repo2, "alternate")); cl_assert(git_repository_path(repo2) != NULL); cl_assert_(git__suffixcmp(git_repository_path(repo2), "alternate/.git/") == 0, git_repository_path(repo2)); cl_assert(git_repository_workdir(repo2) != NULL); cl_assert_(git__suffixcmp(git_repository_workdir(repo2), "alternate/") == 0, git_repository_workdir(repo2)); git_repository_free(repo2); #endif }
int git_futils_mkdir_relative( const char *relative_path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts) { git_buf make_path = GIT_BUF_INIT; ssize_t root = 0, min_root_len; char lastch = '/', *tail; struct stat st; struct git_futils_mkdir_options empty_opts = {0}; int error; if (!opts) opts = &empty_opts; /* build path and find "root" where we should start calling mkdir */ if (git_path_join_unrooted(&make_path, relative_path, base, &root) < 0) return -1; if ((error = mkdir_canonicalize(&make_path, flags)) < 0 || make_path.size == 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) { bool mkdir_attempted = false; /* 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; if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr)) continue; /* See what's going on with this path component */ opts->perfdata.stat_calls++; retry_lstat: if (p_lstat(make_path.ptr, &st) < 0) { if (mkdir_attempted || errno != ENOENT) { giterr_set(GITERR_OS, "cannot access component in path '%s'", make_path.ptr); error = -1; goto done; } giterr_clear(); opts->perfdata.mkdir_calls++; mkdir_attempted = true; if (p_mkdir(make_path.ptr, mode) < 0) { if (errno == EEXIST) goto retry_lstat; giterr_set(GITERR_OS, "failed to make directory '%s'", make_path.ptr); error = -1; goto done; } } else { if ((error = mkdir_validate_dir( make_path.ptr, &st, mode, flags, opts)) < 0) goto done; } /* chmod if requested and necessary */ if ((error = mkdir_validate_mode( make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0) goto done; if (opts->dir_map && opts->pool) { char *cache_path; size_t alloc_size; GITERR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1); if (!git__is_uint32(alloc_size)) return -1; cache_path = git_pool_malloc(opts->pool, (uint32_t)alloc_size); GITERR_CHECK_ALLOC(cache_path); memcpy(cache_path, make_path.ptr, make_path.size + 1); git_strmap_insert(opts->dir_map, cache_path, cache_path, &error); if (error < 0) goto done; } } error = 0; /* check that full path really is a directory if requested & needed */ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && lastch != '\0') { opts->perfdata.stat_calls++; if (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; }
extern int main(int argc, char * argv[]) { char const * outdir=NULL; char const * bnifile=NULL; FILE * fbni; struct stat s; int a; int forcefile=0; char dash[]="-"; /* unique address used as flag */ if (argc<1 || !argv || !argv[0]) { fprintf(stderr,"bad arguments\n"); return STATUS_FAILURE; } for (a=1; a<argc; a++) if (forcefile && !bnifile) bnifile = argv[a]; else if (strcmp(argv[a],"-")==0 && !bnifile) bnifile = dash; else if (argv[a][0]!='-' && !bnifile) bnifile = argv[a]; else if (forcefile && !outdir) outdir = argv[a]; else if (strcmp(argv[a],"-")==0 && !outdir) outdir = dash; else if (argv[a][0]!='-' && !outdir) outdir = argv[a]; else if (forcefile || argv[a][0]!='-' || strcmp(argv[a],"-")==0) { fprintf(stderr,"%s: extra file argument \"%s\"\n",argv[0],argv[a]); usage(argv[0]); } else if (strcmp(argv[a],"--")==0) forcefile = 1; else if (strcmp(argv[a],"-v")==0 || strcmp(argv[a],"--version")==0) { printf("version "BNETD_VERSION"\n"); return STATUS_SUCCESS; } else if (strcmp(argv[a],"-h")==0 || strcmp(argv[a],"--help")==0 || strcmp(argv[a],"--usage") ==0) usage(argv[0]); else { fprintf(stderr,"%s: unknown option \"%s\"\n",argv[0],argv[a]); usage(argv[0]); } if (!bnifile) { fprintf(stderr,"%s: BNI file not specified\n",argv[0]); usage(argv[0]); } if (!outdir) { fprintf(stderr,"%s: output directory not specified\n",argv[0]); usage(argv[0]); } if (bnifile==dash) fbni = stdin; else if (!(fbni = fopen(bnifile,"r"))) { fprintf(stderr,"%s: could not open BNI file \"%s\" for reading (fopen: %s)\n",argv[0],bnifile,strerror(errno)); return STATUS_FAILURE; } if (outdir==dash) { fprintf(stderr,"%s: can not write directory to <stdout>\n",argv[0]); if (bnifile!=dash && fclose(fbni)<0) fprintf(stderr,"%s: could not close BNI file \"%s\" after reading (fclose: %s)\n",argv[0],bnifile,strerror(errno)); return STATUS_FAILURE; } if (stat(outdir,&s)<0) { if (errno == ENOENT) { fprintf(stderr,"Info: Creating directory \"%s\" ...\n",outdir); if (p_mkdir(outdir,S_IRWXU+S_IRWXG+S_IRWXO)<0) { fprintf(stderr,"%s: could not create output directory \"%s\" (mkdir: %s)",argv[0],outdir,strerror(errno)); if (bnifile!=dash && fclose(fbni)<0) fprintf(stderr,"%s: could not close BNI file \"%s\" after reading (fclose: %s)\n",argv[0],bnifile,strerror(errno)); return STATUS_FAILURE; } } else { fprintf(stderr,"%s: could not stat output directory \"%s\" (stat: %s)\n",argv[0],outdir,strerror(errno)); if (bnifile!=dash && fclose(fbni)<0) fprintf(stderr,"%s: could not close BNI file \"%s\" after reading (fclose: %s)\n",argv[0],bnifile,strerror(errno)); return STATUS_FAILURE; } } else if (S_ISDIR(s.st_mode) == 0) { fprintf(stderr,"%s: \"%s\" is not a directory\n",argv[0],outdir); if (bnifile!=dash && fclose(fbni)<0) fprintf(stderr,"%s: could not close BNI file \"%s\" after reading (fclose: %s)\n",argv[0],bnifile,strerror(errno)); return STATUS_FAILURE; } { unsigned int i; int curry; t_tgaimg * iconimg; t_bnifile * bni; FILE * indexfile; char * indexfilename; fprintf(stderr,"Info: Loading \"%s\" ...\n",bnifile); bni = load_bni(fbni); if (bni == NULL) return STATUS_FAILURE; if (fseek(fbni,bni->dataoffset,SEEK_SET)<0) { fprintf(stderr,"%s: could not seek to TGA data offset %lu (fseek: %s)\n",argv[0],(unsigned long int)bni->dataoffset,strerror(errno)); if (bnifile!=dash && fclose(fbni)<0) fprintf(stderr,"%s: could not close BNI file \"%s\" after reading (fclose: %s)\n",argv[0],bnifile,strerror(errno)); return STATUS_FAILURE; } fprintf(stderr,"Info: Loading image ...\n"); iconimg = load_tga(fbni); if (iconimg == NULL) return STATUS_FAILURE; fprintf(stderr,"Info: Extracting icons ...\n"); indexfilename = malloc(strlen(outdir)+14); sprintf(indexfilename,"%s/bniindex.lst",outdir); fprintf(stderr,"Info: Writing Index to \"%s\" ... \n",indexfilename); indexfile = fopen(indexfilename , "w"); if (indexfile == NULL) { fprintf(stderr,"%s: could not open index file \"%s\" for writing (fopen: %s)\n",argv[0],indexfilename,strerror(errno)); if (bnifile!=dash && fclose(fbni)<0) fprintf(stderr,"%s: could not close BNI file \"%s\" after reading (fclose: %s)\n",argv[0],bnifile,strerror(errno)); return STATUS_FAILURE; } fprintf(indexfile,"unknown1 %08x\n",bni->unknown1); fprintf(indexfile,"unknown2 %08x\n",bni->unknown2); curry = 0; for (i=0; i < bni->numicons; i++) { FILE *dsttga; char *name; t_tgaimg *icn; icn = area2img(iconimg,0,curry,bni->icons->icon[i].x,bni->icons->icon[i].y,tgaimgtype_uncompressed_truecolor); if (icn == NULL) { fprintf(stderr,"Error: area2img failed!\n"); return STATUS_FAILURE; } if (bni->icons->icon[i].id == 0) { int tag = bni->icons->icon[i].tag; name = malloc(strlen(outdir)+10); sprintf(name,"%s/%c%c%c%c.tga",outdir,((tag >> 24) & 0xff),((tag >> 16) & 0xff),((tag >> 8) & 0xff),((tag >> 0) & 0xff)); } else { name = malloc(strlen(outdir)+16); sprintf(name,"%s/%08x.tga",outdir,bni->icons->icon[i].id); } fprintf(stderr,"Info: Writing icon %u(%ux%u) to file \"%s\" ... \n",i+1,icn->width,icn->height,name); curry += icn->height; dsttga = fopen(name,"w"); if (dsttga == NULL) { fprintf(stderr,"%s: could not open ouptut TGA file \"%s\" for writing (fopen: %s)\n",argv[0],name,strerror(errno)); } else { if (write_tga(dsttga,icn) < 0) { fprintf(stderr,"Error: Writing to TGA failed.\n"); } else { int tag = bni->icons->icon[i].tag; if (bni->icons->icon[i].id == 0) { fprintf(indexfile,"icon !%c%c%c%c %d %d %08x\n",((tag >> 24) & 0xff),((tag >> 16) & 0xff),((tag >> 8) & 0xff),((tag >> 0) & 0xff),bni->icons->icon[i].x,bni->icons->icon[i].y,bni->icons->icon[i].unknown); } else { fprintf(indexfile,"icon #%08x %d %d %08x\n",bni->icons->icon[i].id,bni->icons->icon[i].x,bni->icons->icon[i].y,bni->icons->icon[i].unknown); } }
void test_odb_loose__initialize(void) { p_fsync__cnt = 0; cl_must_pass(p_mkdir("test-objects", GIT_OBJECT_DIR_MODE)); }
int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode) { git_buf make_path = GIT_BUF_INIT; size_t start = 0; char *pp, *sp; bool failed = false; if (base != NULL) { /* * when a base is being provided, it is supposed to already exist. * Therefore, no attempt is being made to recursively create this leading path * segment. It's just skipped. */ start = strlen(base); if (git_buf_joinpath(&make_path, base, path) < 0) return -1; } else { int root_path_offset; if (git_buf_puts(&make_path, path) < 0) return -1; root_path_offset = git_path_root(make_path.ptr); if (root_path_offset > 0) { /* * On Windows, will skip the drive name (eg. C: or D:) * or the leading part of a network path (eg. //computer_name ) */ start = root_path_offset; } } pp = make_path.ptr + start; while (!failed && (sp = strchr(pp, '/')) != NULL) { if (sp != pp && git_path_isdir(make_path.ptr) == false) { *sp = 0; /* Do not choke while trying to recreate an existing directory */ if (p_mkdir(make_path.ptr, mode) < 0 && errno != EEXIST) failed = true; *sp = '/'; } pp = sp + 1; } if (*pp != '\0' && !failed) { if (p_mkdir(make_path.ptr, mode) < 0 && errno != EEXIST) failed = true; } git_buf_free(&make_path); if (failed) { giterr_set(GITERR_OS, "Failed to create directory structure at '%s'", path); return -1; } return 0; }
static int checkout_tree_with_blob_ignored_in_workdir(int strategy, bool isdir) { git_oid oid; git_object *obj = NULL; git_checkout_options opts = GIT_CHECKOUT_OPTIONS_INIT; int ignored = 0, error; assert_on_branch(g_repo, "master"); /* do first checkout with FORCE because we don't know if testrepo * base data is clean for a checkout or not */ opts.checkout_strategy = GIT_CHECKOUT_FORCE; cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/dir")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); cl_git_pass(git_checkout_tree(g_repo, obj, &opts)); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/dir")); cl_assert(git_path_isfile("testrepo/README")); cl_assert(git_path_isfile("testrepo/branch_file.txt")); cl_assert(git_path_isfile("testrepo/new.txt")); cl_assert(git_path_isfile("testrepo/a/b.txt")); cl_assert(!git_path_isdir("testrepo/ab")); assert_on_branch(g_repo, "dir"); git_object_free(obj); opts.checkout_strategy = strategy; if (isdir) { cl_must_pass(p_mkdir("testrepo/ab", 0777)); cl_must_pass(p_mkdir("testrepo/ab/4.txt", 0777)); cl_git_mkfile("testrepo/ab/4.txt/file1.txt", "as you wish"); cl_git_mkfile("testrepo/ab/4.txt/file2.txt", "foo bar foo"); cl_git_mkfile("testrepo/ab/4.txt/file3.txt", "inky blinky pinky clyde"); cl_assert(git_path_isdir("testrepo/ab/4.txt")); } else { cl_must_pass(p_mkdir("testrepo/ab", 0777)); cl_git_mkfile("testrepo/ab/4.txt", "as you wish"); cl_assert(git_path_isfile("testrepo/ab/4.txt")); } cl_git_pass(git_ignore_add_rule(g_repo, "ab/4.txt\n")); cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "ab/4.txt")); cl_assert_equal_i(1, ignored); cl_git_pass(git_reference_name_to_id(&oid, g_repo, "refs/heads/subtrees")); cl_git_pass(git_object_lookup(&obj, g_repo, &oid, GIT_OBJ_ANY)); error = git_checkout_tree(g_repo, obj, &opts); git_object_free(obj); 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; }
void test_clone_nonetwork__fail_with_already_existing_but_non_empty_directory(void) { p_mkdir("./foo", GIT_DIR_MODE); cl_git_mkfile("./foo/bar", "Baz!"); cl_git_fail(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); }
void test_repo_setters__initialize(void) { cl_fixture_sandbox("testrepo.git"); cl_git_pass(git_repository_open(&repo, "testrepo.git")); cl_must_pass(p_mkdir("new_workdir", 0777)); }
void test_clone_nonetwork__cope_with_already_existing_directory(void) { p_mkdir("./foo", GIT_DIR_MODE); cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); }
int git_futils_mkdir_ext( const char *path, const char *base, mode_t mode, uint32_t flags, struct git_futils_mkdir_options *opts) { int error = -1; git_buf make_path = GIT_BUF_INIT; ssize_t root = 0, min_root_len, 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; } /* Trim trailing slashes (except the root) */ if ((root_len = git_path_root(make_path.ptr)) < 0) root_len = 0; else root_len++; while (make_path.size > (size_t)root_len && make_path.ptr[make_path.size - 1] == '/') 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_path_dirname_r(&make_path, make_path.ptr); flags |= GIT_MKDIR_SKIP_LAST; } if ((flags & GIT_MKDIR_SKIP_LAST) != 0) { git_path_dirname_r(&make_path, make_path.ptr); } /* We were either given the root path (or trimmed it to * the root), we don't have anything to do. */ if (make_path.size <= (size_t)root_len) { 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; if (opts->dir_map && git_strmap_exists(opts->dir_map, make_path.ptr)) continue; /* See what's going on with this path component */ opts->perfdata.stat_calls++; if (p_lstat(make_path.ptr, &st) < 0) { opts->perfdata.mkdir_calls++; if (errno != ENOENT || p_mkdir(make_path.ptr, mode) < 0) { giterr_set(GITERR_OS, "Failed to make directory '%s'", make_path.ptr); error = GIT_EEXISTS; goto done; } giterr_clear(); } else { /* 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", make_path.ptr); error = GIT_EEXISTS; goto done; } if ((error = validate_existing( make_path.ptr, &st, mode, flags, &opts->perfdata)) < 0) 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) { 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) { char *cache_path; size_t alloc_size; GITERR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1); if (!git__is_uint32(alloc_size)) return -1; cache_path = git_pool_malloc(opts->pool, (uint32_t)alloc_size); GITERR_CHECK_ALLOC(cache_path); memcpy(cache_path, make_path.ptr, make_path.size + 1); git_strmap_insert(opts->dir_map, cache_path, cache_path, error); if (error < 0) goto done; } } error = 0; /* check that full path really is a directory if requested & needed */ if ((flags & GIT_MKDIR_VERIFY_DIR) != 0 && lastch != '\0') { opts->perfdata.stat_calls++; if (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; }