void test_filter_crlf__to_worktree(void) { git_filter_list *fl; git_filter *crlf; git_buf in = { 0 }, out = { 0 }; cl_git_pass(git_filter_list_new( &fl, g_repo, GIT_FILTER_TO_WORKTREE, 0)); crlf = git_filter_lookup(GIT_FILTER_CRLF); cl_assert(crlf != NULL); cl_git_pass(git_filter_list_push(fl, crlf, NULL)); in.ptr = "Some text\nRight here\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); #ifdef GIT_WIN32 cl_assert_equal_s("Some text\r\nRight here\r\n", out.ptr); #else cl_assert_equal_s("Some text\nRight here\n", out.ptr); #endif git_filter_list_free(fl); git_buf_free(&out); }
int git_blob_filtered_content( git_buf *out, git_blob *blob, const char *path, int check_for_binary_data) { int error = 0; git_filter_list *fl = NULL; assert(blob && path && out); git_buf_sanitize(out); if (check_for_binary_data && git_blob_is_binary(blob)) return 0; if (!(error = git_filter_list_load( &fl, git_blob_owner(blob), blob, path, GIT_FILTER_TO_WORKTREE, GIT_FILTER_DEFAULT))) { error = git_filter_list_apply_to_blob(out, fl, blob); git_filter_list_free(fl); } return error; }
static int diff_file_content_load_workdir_file( git_diff_file_content *fc, git_buf *path, git_diff_options *diff_opts) { int error = 0; git_filter_list *fl = NULL; git_file fd = git_futils_open_ro(git_buf_cstr(path)); git_buf raw = GIT_BUF_INIT; if (fd < 0) return fd; if (!fc->file->size && !(fc->file->size = git_futils_filesize(fd))) goto cleanup; if ((diff_opts->flags & GIT_DIFF_SHOW_BINARY) == 0 && diff_file_content_binary_by_size(fc)) goto cleanup; if ((error = git_filter_list_load( &fl, fc->repo, NULL, fc->file->path, GIT_FILTER_TO_ODB, GIT_FILTER_ALLOW_UNSAFE)) < 0) goto cleanup; /* if there are no filters, try to mmap the file */ if (fl == NULL) { if (!(error = git_futils_mmap_ro( &fc->map, fd, 0, (size_t)fc->file->size))) { fc->flags |= GIT_DIFF_FLAG__UNMAP_DATA; goto cleanup; } /* if mmap failed, fall through to try readbuffer below */ giterr_clear(); } if (!(error = git_futils_readbuffer_fd(&raw, fd, (size_t)fc->file->size))) { git_buf out = GIT_BUF_INIT; error = git_filter_list_apply_to_data(&out, fl, &raw); if (out.ptr != raw.ptr) git_buf_dispose(&raw); if (!error) { fc->map.len = out.size; fc->map.data = out.ptr; fc->flags |= GIT_DIFF_FLAG__FREE_DATA; } } cleanup: git_filter_list_free(fl); p_close(fd); return error; }
void test_filter_ident__to_odb(void) { git_filter_list *fl; git_filter *ident; cl_git_pass(git_filter_list_new( &fl, g_repo, GIT_FILTER_TO_ODB, 0)); ident = git_filter_lookup(GIT_FILTER_IDENT); cl_assert(ident != NULL); cl_git_pass(git_filter_list_push(fl, ident, NULL)); add_blob_and_filter( "Hello\n$Id$\nFun stuff\n", fl, "Hello\n$Id$\nFun stuff\n"); add_blob_and_filter( "Hello\n$Id: b69e2387aafcaf73c4de5b9ab59abe27fdadee30$\nFun stuff\n", fl, "Hello\n$Id$\nFun stuff\n"); add_blob_and_filter( "Hello\n$Id: Any junk you may have left here$\nFun stuff\n", fl, "Hello\n$Id$\nFun stuff\n"); add_blob_and_filter( "Hello\n$Id:$\nFun stuff\n", fl, "Hello\n$Id$\nFun stuff\n"); add_blob_and_filter( "Hello\n$Id:x$\nFun stuff\n", fl, "Hello\n$Id$\nFun stuff\n"); add_blob_and_filter( "$Id$\nAt the start\n", fl, "$Id$\nAt the start\n"); add_blob_and_filter( "$Id: lots of random text that should be removed from here$\nAt the start\n", fl, "$Id$\nAt the start\n"); add_blob_and_filter( "$Id: lots of random text that should not be removed without a terminator\nAt the start\n", fl, "$Id: lots of random text that should not be removed without a terminator\nAt the start\n"); add_blob_and_filter( "At the end\n$Id$", fl, "At the end\n$Id$"); add_blob_and_filter( "At the end\n$Id:$", fl, "At the end\n$Id$"); add_blob_and_filter( "At the end\n$Id:asdfasdf$", fl, "At the end\n$Id$"); add_blob_and_filter( "At the end\n$Id", fl, "At the end\n$Id"); add_blob_and_filter( "At the end\n$IddI", fl, "At the end\n$IddI"); add_blob_and_filter("$Id$", fl, "$Id$"); add_blob_and_filter("$Id: any$", fl, "$Id$"); add_blob_and_filter("$Id: any long stuff goes here you see$", fl, "$Id$"); add_blob_and_filter("$Id: ", fl, "$Id: "); add_blob_and_filter("$Id", fl, "$Id"); add_blob_and_filter("$I", fl, "$I"); add_blob_and_filter("Id$", fl, "Id$"); git_filter_list_free(fl); }
static int filter_for(const char *filename, const char *filter) { git_filter_list *fl; int filtered; cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, filename, GIT_FILTER_TO_WORKTREE, 0)); filtered = git_filter_list_contains(fl, filter); git_filter_list_free(fl); return filtered; }
void test_filter_custom__can_register_a_custom_filter_in_the_repository(void) { git_filter_list *fl; cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_WORKTREE)); /* expect: bitflip, reverse, crlf */ cl_assert_equal_sz(3, git_filter_list_length(fl)); git_filter_list_free(fl); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "herocorp", GIT_FILTER_TO_WORKTREE)); /* expect: bitflip, reverse - possibly crlf depending on global config */ { size_t flen = git_filter_list_length(fl); cl_assert(flen == 2 || flen == 3); } git_filter_list_free(fl); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "hero.bin", GIT_FILTER_TO_WORKTREE)); /* expect: bitflip, reverse */ cl_assert_equal_sz(2, git_filter_list_length(fl)); git_filter_list_free(fl); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "heroflip", GIT_FILTER_TO_WORKTREE)); /* expect: bitflip (because of -reverse) */ cl_assert_equal_sz(1, git_filter_list_length(fl)); git_filter_list_free(fl); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "doesntapplytome.bin", GIT_FILTER_TO_WORKTREE)); /* expect: none */ cl_assert_equal_sz(0, git_filter_list_length(fl)); git_filter_list_free(fl); }
void test_filter_custom__to_odb(void) { git_filter_list *fl; git_buf out = { 0 }; git_buf in = GIT_BUF_INIT_CONST(workdir_data, strlen(workdir_data)); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "herofile", GIT_FILTER_TO_ODB)); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_i(BITFLIPPED_AND_REVERSED_DATA_LEN, out.size); cl_assert_equal_i( 0, memcmp(bitflipped_and_reversed_data, out.ptr, out.size)); git_filter_list_free(fl); git_buf_free(&out); }
void test_object_blob_filter__to_odb(void) { git_filter_list *fl = NULL; git_config *cfg; int i; git_blob *blob; git_buf out = GIT_BUF_INIT, zeroed; cl_git_pass(git_repository_config(&cfg, g_repo)); cl_assert(cfg); git_attr_cache_flush(g_repo); cl_git_append2file("empty_standard_repo/.gitattributes", "*.txt text\n"); cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "filename.txt", GIT_FILTER_TO_ODB, 0)); cl_assert(fl != NULL); for (i = 0; i < CRLF_NUM_TEST_OBJECTS; i++) { cl_git_pass(git_blob_lookup(&blob, g_repo, &g_crlf_oids[i])); /* try once with allocated blob */ cl_git_pass(git_filter_list_apply_to_blob(&out, fl, blob)); cl_assert_equal_sz(g_crlf_filtered[i].size, out.size); cl_assert_equal_i( 0, memcmp(out.ptr, g_crlf_filtered[i].ptr, out.size)); /* try again with zeroed blob */ memset(&zeroed, 0, sizeof(zeroed)); cl_git_pass(git_filter_list_apply_to_blob(&zeroed, fl, blob)); cl_assert_equal_sz(g_crlf_filtered[i].size, zeroed.size); cl_assert_equal_i( 0, memcmp(zeroed.ptr, g_crlf_filtered[i].ptr, zeroed.size)); git_buf_free(&zeroed); git_blob_free(blob); } git_filter_list_free(fl); git_buf_free(&out); git_config_free(cfg); }
void test_filter_crlf__with_safecrlf_and_unsafe_allowed(void) { git_filter_list *fl; git_filter *crlf; git_buf in = {0}, out = GIT_BUF_INIT; cl_repo_set_bool(g_repo, "core.safecrlf", true); cl_git_pass(git_filter_list_new( &fl, g_repo, GIT_FILTER_TO_ODB, GIT_FILTER_ALLOW_UNSAFE)); crlf = git_filter_lookup(GIT_FILTER_CRLF); cl_assert(crlf != NULL); cl_git_pass(git_filter_list_push(fl, crlf, NULL)); /* Normalized \r\n succeeds with safecrlf */ in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr); /* Mix of line endings fails with safecrlf, but allowed to pass */ in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); /* TODO: check for warning */ cl_assert_equal_s("Mixed\nup\nLF\nand\nCRLF\nline-endings.\n", out.ptr); /* Normalized \n fails with safecrlf, but allowed to pass */ in.ptr = "Normal\nLF\nonly\nline-endings.\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); /* TODO: check for warning */ cl_assert_equal_s("Normal\nLF\nonly\nline-endings.\n", out.ptr); git_filter_list_free(fl); git_buf_free(&out); }
void test_filter_wildcard__none(void) { git_filter_list *fl; git_buf in = GIT_BUF_INIT, out = GIT_BUF_INIT; cl_git_pass(git_filter_list_load( &fl, g_repo, NULL, "none-foo", GIT_FILTER_TO_ODB, 0)); cl_git_pass(git_buf_put(&in, (char *)input, DATA_LEN)); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_i(DATA_LEN, out.size); cl_assert_equal_i( 0, memcmp(input, out.ptr, out.size)); git_filter_list_free(fl); git_buf_dispose(&out); git_buf_dispose(&in); }
void test_filter_crlf__safecrlf_warn(void) { git_filter_list *fl; git_filter *crlf; git_buf in = {0}, out = GIT_BUF_INIT; cl_repo_set_string(g_repo, "core.safecrlf", "warn"); cl_git_pass(git_filter_list_new( &fl, g_repo, GIT_FILTER_TO_ODB, 0)); crlf = git_filter_lookup(GIT_FILTER_CRLF); cl_assert(crlf != NULL); cl_git_pass(git_filter_list_push(fl, crlf, NULL)); /* Normalized \r\n succeeds with safecrlf=warn */ in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr); /* Mix of line endings succeeds with safecrlf=warn */ in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); /* TODO: check for warning */ cl_assert_equal_s("Mixed\nup\nLF\nand\nCRLF\nline-endings.\n", out.ptr); /* Normalized \n is reversible, so does not fail with safecrlf=warn */ in.ptr = "Normal\nLF\nonly\nline-endings.\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s(in.ptr, out.ptr); git_filter_list_free(fl); git_buf_free(&out); }
void test_filter_crlf__with_safecrlf(void) { git_filter_list *fl; git_filter *crlf; git_buf in = {0}, out = GIT_BUF_INIT; cl_repo_set_bool(g_repo, "core.safecrlf", true); cl_git_pass(git_filter_list_new( &fl, g_repo, GIT_FILTER_TO_ODB, 0)); crlf = git_filter_lookup(GIT_FILTER_CRLF); cl_assert(crlf != NULL); cl_git_pass(git_filter_list_push(fl, crlf, NULL)); /* Normalized \r\n succeeds with safecrlf */ in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr); /* Mix of line endings fails with safecrlf */ in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_fail(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_i(giterr_last()->klass, GITERR_FILTER); /* Normalized \n is reversible, so does not fail with safecrlf */ in.ptr = "Normal\nLF\nonly\nline-endings.\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s(in.ptr, out.ptr); git_filter_list_free(fl); git_buf_free(&out); }
void test_filter_ident__to_worktree(void) { git_filter_list *fl; git_filter *ident; cl_git_pass(git_filter_list_new( &fl, g_repo, GIT_FILTER_TO_WORKTREE, 0)); ident = git_filter_lookup(GIT_FILTER_IDENT); cl_assert(ident != NULL); cl_git_pass(git_filter_list_push(fl, ident, NULL)); add_blob_and_filter( "Hello\n$Id$\nFun stuff\n", fl, "Hello\n$Id: b69e2387aafcaf73c4de5b9ab59abe27fdadee30$\nFun stuff\n"); add_blob_and_filter( "Hello\n$Id: Junky$\nFun stuff\n", fl, "Hello\n$Id: 45cd107a7102911cb2a7df08404674327fa050b9$\nFun stuff\n"); add_blob_and_filter( "$Id$\nAt the start\n", fl, "$Id: b13415c767abc196fb95bd17070e8c1113e32160$\nAt the start\n"); add_blob_and_filter( "At the end\n$Id$", fl, "At the end\n$Id: 1344925c6bc65b34c5a7b50f86bf688e48e9a272$"); add_blob_and_filter( "$Id$", fl, "$Id: b3f5ebfb5843bc43ceecff6d4f26bb37c615beb1$"); add_blob_and_filter( "$Id: Some sort of junk goes here$", fl, "$Id: ab2dd3853c7c9a4bff55aca2bea077a73c32ac06$"); add_blob_and_filter("$Id: ", fl, "$Id: "); add_blob_and_filter("$Id", fl, "$Id"); add_blob_and_filter("$I", fl, "$I"); add_blob_and_filter("Id$", fl, "Id$"); git_filter_list_free(fl); }
void test_filter_crlf__no_safecrlf(void) { git_filter_list *fl; git_filter *crlf; git_buf in = {0}, out = GIT_BUF_INIT; cl_git_pass(git_filter_list_new( &fl, g_repo, GIT_FILTER_TO_ODB, 0)); crlf = git_filter_lookup(GIT_FILTER_CRLF); cl_assert(crlf != NULL); cl_git_pass(git_filter_list_push(fl, crlf, NULL)); /* Normalized \r\n succeeds with safecrlf */ in.ptr = "Normal\r\nCRLF\r\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s("Normal\nCRLF\nline-endings.\n", out.ptr); /* Mix of line endings fails with safecrlf */ in.ptr = "Mixed\nup\r\nLF\nand\r\nCRLF\nline-endings.\r\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s("Mixed\nup\nLF\nand\nCRLF\nline-endings.\n", out.ptr); /* Normalized \n fails with safecrlf */ in.ptr = "Normal\nLF\nonly\nline-endings.\n"; in.size = strlen(in.ptr); cl_git_pass(git_filter_list_apply_to_data(&out, fl, &in)); cl_assert_equal_s("Normal\nLF\nonly\nline-endings.\n", out.ptr); git_filter_list_free(fl); git_buf_free(&out); }
static int workdir_reader_read( git_buf *out, git_oid *out_id, git_filemode_t *out_filemode, git_reader *_reader, const char *filename) { workdir_reader *reader = (workdir_reader *)_reader; git_buf path = GIT_BUF_INIT; struct stat st; git_filemode_t filemode; git_filter_list *filters = NULL; const git_index_entry *idx_entry; git_oid id; int error; if ((error = git_buf_joinpath(&path, git_repository_workdir(reader->repo), filename)) < 0) goto done; if ((error = p_lstat(path.ptr, &st)) < 0) { if (error == -1 && errno == ENOENT) error = GIT_ENOTFOUND; giterr_set(GITERR_OS, "could not stat '%s'", path.ptr); goto done; } filemode = git_futils_canonical_mode(st.st_mode); /* * Patch application - for example - uses the filtered version of * the working directory data to match git. So we will run the * workdir -> ODB filter on the contents in this workdir reader. */ if ((error = git_filter_list_load(&filters, reader->repo, NULL, filename, GIT_FILTER_TO_ODB, GIT_FILTER_DEFAULT)) < 0) goto done; if ((error = git_filter_list_apply_to_file(out, filters, reader->repo, path.ptr)) < 0) goto done; if (out_id || reader->index) { if ((error = git_odb_hash(&id, out->ptr, out->size, GIT_OBJ_BLOB)) < 0) goto done; } if (reader->index) { if (!(idx_entry = git_index_get_bypath(reader->index, filename, 0)) || filemode != idx_entry->mode || !git_oid_equal(&id, &idx_entry->id)) { error = GIT_READER_MISMATCH; goto done; } } if (out_id) git_oid_cpy(out_id, &id); if (out_filemode) *out_filemode = filemode; done: git_filter_list_free(filters); git_buf_dispose(&path); return error; }
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; }