static void assert_hooks_match( const char *template_dir, const char *repo_dir, const char *hook_path, bool core_filemode) { git_buf expected = GIT_BUF_INIT; git_buf actual = GIT_BUF_INIT; struct stat expected_st, st; cl_git_pass(git_buf_joinpath(&expected, template_dir, hook_path)); cl_git_pass(git_path_lstat(expected.ptr, &expected_st)); cl_git_pass(git_buf_joinpath(&actual, repo_dir, hook_path)); cl_git_pass(git_path_lstat(actual.ptr, &st)); cl_assert(expected_st.st_size == st.st_size); if (GIT_MODE_TYPE(expected_st.st_mode) != GIT_FILEMODE_LINK) { mode_t expected_mode = GIT_MODE_TYPE(expected_st.st_mode) | (GIT_PERMS_FOR_WRITE(expected_st.st_mode) & ~g_umask); if (!core_filemode) { CLEAR_FOR_CORE_FILEMODE(expected_mode); CLEAR_FOR_CORE_FILEMODE(st.st_mode); } cl_assert_equal_i_fmt(expected_mode, st.st_mode, "%07o"); } git_buf_free(&expected); git_buf_free(&actual); }
static void assert_mode_seems_okay( const char *base, const char *path, git_filemode_t expect_mode, bool expect_setgid, bool core_filemode) { git_buf full = GIT_BUF_INIT; struct stat st; cl_git_pass(git_buf_joinpath(&full, base, path)); cl_git_pass(git_path_lstat(full.ptr, &st)); git_buf_free(&full); if (!core_filemode) { CLEAR_FOR_CORE_FILEMODE(expect_mode); CLEAR_FOR_CORE_FILEMODE(st.st_mode); expect_setgid = false; } if (S_ISGID != 0) cl_assert_equal_b(expect_setgid, (st.st_mode & S_ISGID) != 0); cl_assert_equal_b( GIT_PERMS_IS_EXEC(expect_mode), GIT_PERMS_IS_EXEC(st.st_mode)); cl_assert_equal_i_fmt( GIT_MODE_TYPE(expect_mode), GIT_MODE_TYPE(st.st_mode), "%07o"); }
git_vector_foreach(contents, i, ps) { /* skip if before start_stat or after end_stat */ cmp_len = min(start_len, ps->path_len); if (cmp_len && strncomp(ps->path, start_stat, cmp_len) < 0) continue; cmp_len = min(end_len, ps->path_len); if (cmp_len && strncomp(ps->path, end_stat, cmp_len) > 0) continue; git_buf_truncate(&full, prefix_len); if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 || (error = git_path_lstat(full.ptr, &ps->st)) < 0) { if (error == GIT_ENOTFOUND) { giterr_clear(); error = 0; git_vector_remove(contents, i--); continue; } break; } if (S_ISDIR(ps->st.st_mode)) { ps->path[ps->path_len++] = '/'; ps->path[ps->path_len] = '\0'; } }
git_vector_foreach(contents, i, ps) { /* skip if before start_stat or after end_stat */ cmp_len = min(start_len, ps->path_len); if (cmp_len && strncomp(ps->path, start_stat, cmp_len) < 0) continue; cmp_len = min(end_len, ps->path_len); if (cmp_len && strncomp(ps->path, end_stat, cmp_len) > 0) continue; git_buf_truncate(&full, prefix_len); if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 || (error = git_path_lstat(full.ptr, &ps->st)) < 0) break; if (S_ISDIR(ps->st.st_mode)) { if ((error = git_buf_joinpath(&full, full.ptr, ".git")) < 0) break; if (p_access(full.ptr, F_OK) == 0) { ps->st.st_mode = GIT_FILEMODE_COMMIT; } else { ps->path[ps->path_len++] = '/'; ps->path[ps->path_len] = '\0'; } } }
static int blob_create_internal(git_oid *oid, git_repository *repo, const char *content_path, const char *hint_path, bool try_load_filters) { int error; struct stat st; git_odb *odb = NULL; git_off_t size; assert(hint_path || !try_load_filters); if ((error = git_path_lstat(content_path, &st)) < 0 || (error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; size = st.st_size; if (S_ISLNK(st.st_mode)) { error = write_symlink(oid, odb, content_path, (size_t)size); } else { git_vector write_filters = GIT_VECTOR_INIT; int filter_count = 0; if (try_load_filters) { /* Load the filters for writing this file to the ODB */ filter_count = git_filters_load( &write_filters, repo, hint_path, GIT_FILTER_TO_ODB); } if (filter_count < 0) { /* Negative value means there was a critical error */ error = filter_count; } else if (filter_count == 0) { /* No filters need to be applied to the document: we can stream * directly from disk */ error = write_file_stream(oid, odb, content_path, size); } else { /* We need to apply one or more filters */ error = write_file_filtered(oid, odb, content_path, &write_filters); } git_filters_free(&write_filters); /* * TODO: eventually support streaming filtered files, for files * which are bigger than a given threshold. This is not a priority * because applying a filter in streaming mode changes the final * size of the blob, and without knowing its final size, the blob * cannot be written in stream mode to the ODB. * * The plan is to do streaming writes to a tempfile on disk and then * opening streaming that file to the ODB, using * `write_file_stream`. * * CAREFULLY DESIGNED APIS YO */ } return error; }
void test_repo_init__extended_1(void) { git_reference *ref; git_remote *remote; struct stat st; git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT; opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_NO_DOTGIT_DIR; opts.mode = GIT_REPOSITORY_INIT_SHARED_GROUP; opts.workdir_path = "../c_wd"; opts.description = "Awesomest test repository evah"; opts.initial_head = "development"; opts.origin_url = "https://github.com/libgit2/libgit2.git"; cl_git_pass(git_repository_init_ext(&_repo, "root/b/c.git", &opts)); cl_assert(!git__suffixcmp(git_repository_workdir(_repo), "/c_wd/")); cl_assert(!git__suffixcmp(git_repository_path(_repo), "/c.git/")); cl_assert(git_path_isfile("root/b/c_wd/.git")); cl_assert(!git_repository_is_bare(_repo)); /* repo will not be counted as empty because we set head to "development" */ cl_assert(!git_repository_is_empty(_repo)); cl_git_pass(git_path_lstat(git_repository_path(_repo), &st)); cl_assert(S_ISDIR(st.st_mode)); if (cl_is_chmod_supported()) cl_assert((S_ISGID & st.st_mode) == S_ISGID); else cl_assert((S_ISGID & st.st_mode) == 0); cl_git_pass(git_reference_lookup(&ref, _repo, "HEAD")); cl_assert(git_reference_type(ref) == GIT_REF_SYMBOLIC); cl_assert_equal_s("refs/heads/development", git_reference_symbolic_target(ref)); git_reference_free(ref); cl_git_pass(git_remote_lookup(&remote, _repo, "origin")); cl_assert_equal_s("origin", git_remote_name(remote)); cl_assert_equal_s(opts.origin_url, git_remote_url(remote)); git_remote_free(remote); git_repository_free(_repo); cl_fixture_cleanup("root"); }
int git_odb__hashlink(git_oid *out, const char *path) { struct stat st; git_off_t size; int result; if (git_path_lstat(path, &st) < 0) return -1; size = st.st_size; if (!git__is_sizet(size)) { giterr_set(GITERR_OS, "File size overflow for 32-bit systems"); return -1; } if (S_ISLNK(st.st_mode)) { char *link_data; ssize_t read_len; link_data = (char*) git__malloc((size_t)(size + 1)); GITERR_CHECK_ALLOC(link_data); read_len = p_readlink(path, link_data, (size_t)size); link_data[size] = '\0'; if (read_len != (ssize_t)size) { giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", path); git__free(link_data); return -1; } result = git_odb_hash(out, link_data, (size_t)size, GIT_OBJ_BLOB); git__free(link_data); } else { int fd = git_futils_open_ro(path); if (fd < 0) return -1; result = git_odb__hashfd(out, fd, (size_t)size, GIT_OBJ_BLOB); p_close(fd); } return result; }
git_vector_foreach(contents, i, ps) { /* skip if before start_stat or after end_stat */ cmp_len = min(start_len, ps->path_len); if (cmp_len && strncomp(ps->path, start_stat, cmp_len) < 0) continue; cmp_len = min(end_len, ps->path_len); if (cmp_len && strncomp(ps->path, end_stat, cmp_len) > 0) continue; git_buf_truncate(&full, prefix_len); if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 || (error = git_path_lstat(full.ptr, &ps->st)) < 0) { if (error == GIT_ENOTFOUND) { /* file was removed between readdir and lstat */ char *entry_path = git_vector_get(contents, i); git_vector_remove(contents, i--); git__free(entry_path); } else { /* Treat the file as unreadable if we get any other error */ memset(&ps->st, 0, sizeof(ps->st)); ps->st.st_mode = GIT_FILEMODE_UNREADABLE; } giterr_clear(); error = 0; continue; } if (S_ISDIR(ps->st.st_mode)) { ps->path[ps->path_len++] = '/'; ps->path[ps->path_len] = '\0'; } else if (!S_ISREG(ps->st.st_mode) && !S_ISLNK(ps->st.st_mode)) { char *entry_path = git_vector_get(contents, i); git_vector_remove(contents, i--); git__free(entry_path); } }
int git_path_dirload_with_stat( const char *path, size_t prefix_len, git_vector *contents) { int error; unsigned int i; git_path_with_stat *ps; git_buf full = GIT_BUF_INIT; if (git_buf_set(&full, path, prefix_len) < 0) return -1; error = git_path_dirload( path, prefix_len, sizeof(git_path_with_stat) + 1, contents); if (error < 0) { git_buf_free(&full); return error; } git_vector_foreach(contents, i, ps) { size_t path_len = strlen((char *)ps); memmove(ps->path, ps, path_len + 1); ps->path_len = path_len; if ((error = git_buf_joinpath(&full, full.ptr, ps->path)) < 0 || (error = git_path_lstat(full.ptr, &ps->st)) < 0) break; git_buf_truncate(&full, prefix_len); if (S_ISDIR(ps->st.st_mode)) { ps->path[path_len] = '/'; ps->path[path_len + 1] = '\0'; } }
int git_path_diriter_stat(struct stat *out, git_path_diriter *diriter) { assert(out && diriter); return git_path_lstat(diriter->path.ptr, out); }
int git_blob__create_from_paths( git_oid *id, struct stat *out_st, git_repository *repo, const char *content_path, const char *hint_path, mode_t hint_mode, bool try_load_filters) { int error; struct stat st; git_odb *odb = NULL; git_off_t size; mode_t mode; git_buf path = GIT_BUF_INIT; assert(hint_path || !try_load_filters); if (!content_path) { if (git_repository__ensure_not_bare(repo, "create blob from file") < 0) return GIT_EBAREREPO; if (git_buf_joinpath( &path, git_repository_workdir(repo), hint_path) < 0) return -1; content_path = path.ptr; } if ((error = git_path_lstat(content_path, &st)) < 0 || (error = git_repository_odb(&odb, repo)) < 0) goto done; if (S_ISDIR(st.st_mode)) { giterr_set(GITERR_ODB, "cannot create blob from '%s': it is a directory", content_path); error = GIT_EDIRECTORY; goto done; } if (out_st) memcpy(out_st, &st, sizeof(st)); size = st.st_size; mode = hint_mode ? hint_mode : st.st_mode; if (S_ISLNK(mode)) { error = write_symlink(id, odb, content_path, (size_t)size); } else { git_filter_list *fl = NULL; if (try_load_filters) /* Load the filters for writing this file to the ODB */ error = git_filter_list_load( &fl, repo, NULL, hint_path, GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT); if (error < 0) /* well, that didn't work */; else if (fl == NULL) /* No filters need to be applied to the document: we can stream * directly from disk */ error = write_file_stream(id, odb, content_path, size); else { /* We need to apply one or more filters */ error = write_file_filtered(id, &size, odb, content_path, fl); git_filter_list_free(fl); } /* * TODO: eventually support streaming filtered files, for files * which are bigger than a given threshold. This is not a priority * because applying a filter in streaming mode changes the final * size of the blob, and without knowing its final size, the blob * cannot be written in stream mode to the ODB. * * The plan is to do streaming writes to a tempfile on disk and then * opening streaming that file to the ODB, using * `write_file_stream`. * * CAREFULLY DESIGNED APIS YO */ } done: git_odb_free(odb); git_buf_dispose(&path); return error; }
void test_core_mkdir__chmods(void) { struct stat st; mode_t *old = git__malloc(sizeof(mode_t)); *old = p_umask(022); cl_set_cleanup(cleanup_chmod_root, old); cl_git_pass(git_futils_mkdir("r", NULL, 0777, 0)); cl_git_pass(git_futils_mkdir("mode/is/important", "r", 0777, GIT_MKDIR_PATH)); cl_git_pass(git_path_lstat("r/mode", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode/is", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode/is/important", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_futils_mkdir("mode2/is2/important2", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD)); cl_git_pass(git_path_lstat("r/mode2", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode2/is2", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode2/is2/important2", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_futils_mkdir("mode3/is3/important3", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD_PATH)); cl_git_pass(git_path_lstat("r/mode3", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_path_lstat("r/mode3/is3", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_path_lstat("r/mode3/is3/important3", &st)); check_mode(0777, st.st_mode); /* test that we chmod existing dir */ cl_git_pass(git_futils_mkdir("mode/is/important", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD)); cl_git_pass(git_path_lstat("r/mode", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode/is", &st)); check_mode(0755, st.st_mode); cl_git_pass(git_path_lstat("r/mode/is/important", &st)); check_mode(0777, st.st_mode); /* test that we chmod even existing dirs if CHMOD_PATH is set */ cl_git_pass(git_futils_mkdir("mode2/is2/important2.1", "r", 0777, GIT_MKDIR_PATH | GIT_MKDIR_CHMOD_PATH)); cl_git_pass(git_path_lstat("r/mode2", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_path_lstat("r/mode2/is2", &st)); check_mode(0777, st.st_mode); cl_git_pass(git_path_lstat("r/mode2/is2/important2.1", &st)); check_mode(0777, st.st_mode); }