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; }
static int diff_file_content_load_workdir_file( git_diff_file_content *fc, git_buf *path) { int error = 0; git_vector filters = GIT_VECTOR_INIT; git_buf raw = GIT_BUF_INIT, filtered = GIT_BUF_INIT; git_file fd = git_futils_open_ro(git_buf_cstr(path)); if (fd < 0) return fd; if (!fc->file->size && !(fc->file->size = git_futils_filesize(fd))) goto cleanup; if (diff_file_content_binary_by_size(fc)) goto cleanup; if ((error = git_filters_load( &filters, fc->repo, fc->file->path, GIT_FILTER_TO_ODB)) < 0) goto cleanup; /* error >= is a filter count */ if (error == 0) { if (!(error = git_futils_mmap_ro( &fc->map, fd, 0, (size_t)fc->file->size))) fc->flags |= GIT_DIFF_FLAG__UNMAP_DATA; else /* fall through to try readbuffer below */ giterr_clear(); } if (error != 0) { error = git_futils_readbuffer_fd(&raw, fd, (size_t)fc->file->size); if (error < 0) goto cleanup; if (!filters.length) git_buf_swap(&filtered, &raw); else error = git_filters_apply(&filtered, &raw, &filters); if (!error) { fc->map.len = git_buf_len(&filtered); fc->map.data = git_buf_detach(&filtered); fc->flags |= GIT_DIFF_FLAG__FREE_DATA; } git_buf_free(&raw); git_buf_free(&filtered); } cleanup: git_filters_free(&filters); p_close(fd); return error; }
static int blob_content_to_file( git_blob *blob, const char *path, mode_t entry_filemode, git_checkout_opts *opts) { int error = -1, nb_filters = 0; mode_t file_mode = opts->file_mode; bool dont_free_filtered = false; git_buf unfiltered = GIT_BUF_INIT, filtered = GIT_BUF_INIT; git_vector filters = GIT_VECTOR_INIT; if (opts->disable_filters || (nb_filters = git_filters_load( &filters, git_object_owner((git_object *)blob), path, GIT_FILTER_TO_WORKTREE)) == 0) { /* Create a fake git_buf from the blob raw data... */ filtered.ptr = blob->odb_object->raw.data; filtered.size = blob->odb_object->raw.len; /* ... and make sure it doesn't get unexpectedly freed */ dont_free_filtered = true; } if (nb_filters < 0) return nb_filters; if (nb_filters > 0) { if ((error = git_blob__getbuf(&unfiltered, blob)) < 0) goto cleanup; if ((error = git_filters_apply(&filtered, &unfiltered, &filters)) < 0) goto cleanup; } /* Allow overriding of file mode */ if (!file_mode) file_mode = entry_filemode; error = buffer_to_file(&filtered, path, opts->dir_mode, opts->file_open_flags, file_mode); cleanup: git_filters_free(&filters); git_buf_free(&unfiltered); if (!dont_free_filtered) git_buf_free(&filtered); return error; }