diff options
Diffstat (limited to 'src/filter.c')
-rw-r--r-- | src/filter.c | 1147 |
1 files changed, 0 insertions, 1147 deletions
diff --git a/src/filter.c b/src/filter.c deleted file mode 100644 index 73497cb30..000000000 --- a/src/filter.c +++ /dev/null @@ -1,1147 +0,0 @@ -/* - * Copyright (C) the libgit2 contributors. All rights reserved. - * - * This file is part of libgit2, distributed under the GNU GPL v2 with - * a Linking Exception. For full terms see the included COPYING file. - */ - -#include "filter.h" - -#include "common.h" -#include "futils.h" -#include "hash.h" -#include "repository.h" -#include "runtime.h" -#include "git2/sys/filter.h" -#include "git2/config.h" -#include "blob.h" -#include "attr_file.h" -#include "array.h" - -struct git_filter_source { - git_repository *repo; - const char *path; - git_oid oid; /* zero if unknown (which is likely) */ - uint16_t filemode; /* zero if unknown */ - git_filter_mode_t mode; - git_filter_options options; -}; - -typedef struct { - const char *filter_name; - git_filter *filter; - void *payload; -} git_filter_entry; - -struct git_filter_list { - git_array_t(git_filter_entry) filters; - git_filter_source source; - git_buf *temp_buf; - char path[GIT_FLEX_ARRAY]; -}; - -typedef struct { - char *filter_name; - git_filter *filter; - int priority; - int initialized; - size_t nattrs, nmatches; - char *attrdata; - const char *attrs[GIT_FLEX_ARRAY]; -} git_filter_def; - -static int filter_def_priority_cmp(const void *a, const void *b) -{ - int pa = ((const git_filter_def *)a)->priority; - int pb = ((const git_filter_def *)b)->priority; - return (pa < pb) ? -1 : (pa > pb) ? 1 : 0; -} - -struct git_filter_registry { - git_rwlock lock; - git_vector filters; -}; - -static struct git_filter_registry filter_registry; - -static void git_filter_global_shutdown(void); - - -static int filter_def_scan_attrs( - git_buf *attrs, size_t *nattr, size_t *nmatch, const char *attr_str) -{ - const char *start, *scan = attr_str; - int has_eq; - - *nattr = *nmatch = 0; - - if (!scan) - return 0; - - while (*scan) { - while (git__isspace(*scan)) scan++; - - for (start = scan, has_eq = 0; *scan && !git__isspace(*scan); ++scan) { - if (*scan == '=') - has_eq = 1; - } - - if (scan > start) { - (*nattr)++; - if (has_eq || *start == '-' || *start == '+' || *start == '!') - (*nmatch)++; - - if (has_eq) - git_buf_putc(attrs, '='); - git_buf_put(attrs, start, scan - start); - git_buf_putc(attrs, '\0'); - } - } - - return 0; -} - -static void filter_def_set_attrs(git_filter_def *fdef) -{ - char *scan = fdef->attrdata; - size_t i; - - for (i = 0; i < fdef->nattrs; ++i) { - const char *name, *value; - - switch (*scan) { - case '=': - name = scan + 1; - for (scan++; *scan != '='; scan++) /* find '=' */; - *scan++ = '\0'; - value = scan; - break; - case '-': - name = scan + 1; value = git_attr__false; break; - case '+': - name = scan + 1; value = git_attr__true; break; - case '!': - name = scan + 1; value = git_attr__unset; break; - default: - name = scan; value = NULL; break; - } - - fdef->attrs[i] = name; - fdef->attrs[i + fdef->nattrs] = value; - - scan += strlen(scan) + 1; - } -} - -static int filter_def_name_key_check(const void *key, const void *fdef) -{ - const char *name = - fdef ? ((const git_filter_def *)fdef)->filter_name : NULL; - return name ? git__strcmp(key, name) : -1; -} - -static int filter_def_filter_key_check(const void *key, const void *fdef) -{ - const void *filter = fdef ? ((const git_filter_def *)fdef)->filter : NULL; - return (key == filter) ? 0 : -1; -} - -/* Note: callers must lock the registry before calling this function */ -static int filter_registry_insert( - const char *name, git_filter *filter, int priority) -{ - git_filter_def *fdef; - size_t nattr = 0, nmatch = 0, alloc_len; - git_buf attrs = GIT_BUF_INIT; - - if (filter_def_scan_attrs(&attrs, &nattr, &nmatch, filter->attributes) < 0) - return -1; - - GIT_ERROR_CHECK_ALLOC_MULTIPLY(&alloc_len, nattr, 2); - GIT_ERROR_CHECK_ALLOC_MULTIPLY(&alloc_len, alloc_len, sizeof(char *)); - GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, sizeof(git_filter_def)); - - fdef = git__calloc(1, alloc_len); - GIT_ERROR_CHECK_ALLOC(fdef); - - fdef->filter_name = git__strdup(name); - GIT_ERROR_CHECK_ALLOC(fdef->filter_name); - - fdef->filter = filter; - fdef->priority = priority; - fdef->nattrs = nattr; - fdef->nmatches = nmatch; - fdef->attrdata = git_buf_detach(&attrs); - - filter_def_set_attrs(fdef); - - if (git_vector_insert(&filter_registry.filters, fdef) < 0) { - git__free(fdef->filter_name); - git__free(fdef->attrdata); - git__free(fdef); - return -1; - } - - git_vector_sort(&filter_registry.filters); - return 0; -} - -int git_filter_global_init(void) -{ - git_filter *crlf = NULL, *ident = NULL; - int error = 0; - - if (git_rwlock_init(&filter_registry.lock) < 0) - return -1; - - if ((error = git_vector_init(&filter_registry.filters, 2, - filter_def_priority_cmp)) < 0) - goto done; - - if ((crlf = git_crlf_filter_new()) == NULL || - filter_registry_insert( - GIT_FILTER_CRLF, crlf, GIT_FILTER_CRLF_PRIORITY) < 0 || - (ident = git_ident_filter_new()) == NULL || - filter_registry_insert( - GIT_FILTER_IDENT, ident, GIT_FILTER_IDENT_PRIORITY) < 0) - error = -1; - - if (!error) - error = git_runtime_shutdown_register(git_filter_global_shutdown); - -done: - if (error) { - git_filter_free(crlf); - git_filter_free(ident); - } - - return error; -} - -static void git_filter_global_shutdown(void) -{ - size_t pos; - git_filter_def *fdef; - - if (git_rwlock_wrlock(&filter_registry.lock) < 0) - return; - - git_vector_foreach(&filter_registry.filters, pos, fdef) { - if (fdef->filter && fdef->filter->shutdown) { - fdef->filter->shutdown(fdef->filter); - fdef->initialized = false; - } - - git__free(fdef->filter_name); - git__free(fdef->attrdata); - git__free(fdef); - } - - git_vector_free(&filter_registry.filters); - - git_rwlock_wrunlock(&filter_registry.lock); - git_rwlock_free(&filter_registry.lock); -} - -/* Note: callers must lock the registry before calling this function */ -static int filter_registry_find(size_t *pos, const char *name) -{ - return git_vector_search2( - pos, &filter_registry.filters, filter_def_name_key_check, name); -} - -/* Note: callers must lock the registry before calling this function */ -static git_filter_def *filter_registry_lookup(size_t *pos, const char *name) -{ - git_filter_def *fdef = NULL; - - if (!filter_registry_find(pos, name)) - fdef = git_vector_get(&filter_registry.filters, *pos); - - return fdef; -} - - -int git_filter_register( - const char *name, git_filter *filter, int priority) -{ - int error; - - GIT_ASSERT_ARG(name); - GIT_ASSERT_ARG(filter); - - if (git_rwlock_wrlock(&filter_registry.lock) < 0) { - git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); - return -1; - } - - if (!filter_registry_find(NULL, name)) { - git_error_set( - GIT_ERROR_FILTER, "attempt to reregister existing filter '%s'", name); - error = GIT_EEXISTS; - goto done; - } - - error = filter_registry_insert(name, filter, priority); - -done: - git_rwlock_wrunlock(&filter_registry.lock); - return error; -} - -int git_filter_unregister(const char *name) -{ - size_t pos; - git_filter_def *fdef; - int error = 0; - - GIT_ASSERT_ARG(name); - - /* cannot unregister default filters */ - if (!strcmp(GIT_FILTER_CRLF, name) || !strcmp(GIT_FILTER_IDENT, name)) { - git_error_set(GIT_ERROR_FILTER, "cannot unregister filter '%s'", name); - return -1; - } - - if (git_rwlock_wrlock(&filter_registry.lock) < 0) { - git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); - return -1; - } - - if ((fdef = filter_registry_lookup(&pos, name)) == NULL) { - git_error_set(GIT_ERROR_FILTER, "cannot find filter '%s' to unregister", name); - error = GIT_ENOTFOUND; - goto done; - } - - git_vector_remove(&filter_registry.filters, pos); - - if (fdef->initialized && fdef->filter && fdef->filter->shutdown) { - fdef->filter->shutdown(fdef->filter); - fdef->initialized = false; - } - - git__free(fdef->filter_name); - git__free(fdef->attrdata); - git__free(fdef); - -done: - git_rwlock_wrunlock(&filter_registry.lock); - return error; -} - -static int filter_initialize(git_filter_def *fdef) -{ - int error = 0; - - if (!fdef->initialized && fdef->filter && fdef->filter->initialize) { - if ((error = fdef->filter->initialize(fdef->filter)) < 0) - return error; - } - - fdef->initialized = true; - return 0; -} - -git_filter *git_filter_lookup(const char *name) -{ - size_t pos; - git_filter_def *fdef; - git_filter *filter = NULL; - - if (git_rwlock_rdlock(&filter_registry.lock) < 0) { - git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); - return NULL; - } - - if ((fdef = filter_registry_lookup(&pos, name)) == NULL || - (!fdef->initialized && filter_initialize(fdef) < 0)) - goto done; - - filter = fdef->filter; - -done: - git_rwlock_rdunlock(&filter_registry.lock); - return filter; -} - -void git_filter_free(git_filter *filter) -{ - git__free(filter); -} - -git_repository *git_filter_source_repo(const git_filter_source *src) -{ - return src->repo; -} - -const char *git_filter_source_path(const git_filter_source *src) -{ - return src->path; -} - -uint16_t git_filter_source_filemode(const git_filter_source *src) -{ - return src->filemode; -} - -const git_oid *git_filter_source_id(const git_filter_source *src) -{ - return git_oid_is_zero(&src->oid) ? NULL : &src->oid; -} - -git_filter_mode_t git_filter_source_mode(const git_filter_source *src) -{ - return src->mode; -} - -uint32_t git_filter_source_flags(const git_filter_source *src) -{ - return src->options.flags; -} - -static int filter_list_new( - git_filter_list **out, const git_filter_source *src) -{ - git_filter_list *fl = NULL; - size_t pathlen = src->path ? strlen(src->path) : 0, alloclen; - - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_filter_list), pathlen); - GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); - - fl = git__calloc(1, alloclen); - GIT_ERROR_CHECK_ALLOC(fl); - - if (src->path) - memcpy(fl->path, src->path, pathlen); - fl->source.repo = src->repo; - fl->source.path = fl->path; - fl->source.mode = src->mode; - - memcpy(&fl->source.options, &src->options, sizeof(git_filter_options)); - - *out = fl; - return 0; -} - -static int filter_list_check_attributes( - const char ***out, - git_repository *repo, - git_filter_session *filter_session, - git_filter_def *fdef, - const git_filter_source *src) -{ - const char **strs = git__calloc(fdef->nattrs, sizeof(const char *)); - git_attr_options attr_opts = GIT_ATTR_OPTIONS_INIT; - size_t i; - int error; - - GIT_ERROR_CHECK_ALLOC(strs); - - if ((src->options.flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0) - attr_opts.flags |= GIT_ATTR_CHECK_NO_SYSTEM; - - if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0) - attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_HEAD; - - if ((src->options.flags & GIT_FILTER_ATTRIBUTES_FROM_COMMIT) != 0) { - attr_opts.flags |= GIT_ATTR_CHECK_INCLUDE_COMMIT; - -#ifndef GIT_DEPRECATE_HARD - if (src->options.commit_id) - git_oid_cpy(&attr_opts.attr_commit_id, src->options.commit_id); - else -#endif - git_oid_cpy(&attr_opts.attr_commit_id, &src->options.attr_commit_id); - } - - error = git_attr_get_many_with_session( - strs, repo, filter_session->attr_session, &attr_opts, src->path, fdef->nattrs, fdef->attrs); - - /* if no values were found but no matches are needed, it's okay! */ - if (error == GIT_ENOTFOUND && !fdef->nmatches) { - git_error_clear(); - git__free((void *)strs); - return 0; - } - - for (i = 0; !error && i < fdef->nattrs; ++i) { - const char *want = fdef->attrs[fdef->nattrs + i]; - git_attr_value_t want_type, found_type; - - if (!want) - continue; - - want_type = git_attr_value(want); - found_type = git_attr_value(strs[i]); - - if (want_type != found_type) - error = GIT_ENOTFOUND; - else if (want_type == GIT_ATTR_VALUE_STRING && - strcmp(want, strs[i]) && - strcmp(want, "*")) - error = GIT_ENOTFOUND; - } - - if (error) - git__free((void *)strs); - else - *out = strs; - - return error; -} - -int git_filter_list_new( - git_filter_list **out, - git_repository *repo, - git_filter_mode_t mode, - uint32_t flags) -{ - git_filter_source src = { 0 }; - src.repo = repo; - src.path = NULL; - src.mode = mode; - src.options.flags = flags; - return filter_list_new(out, &src); -} - -int git_filter_list__load( - git_filter_list **filters, - git_repository *repo, - git_blob *blob, /* can be NULL */ - const char *path, - git_filter_mode_t mode, - git_filter_session *filter_session) -{ - int error = 0; - git_filter_list *fl = NULL; - git_filter_source src = { 0 }; - git_filter_entry *fe; - size_t idx; - git_filter_def *fdef; - - if (git_rwlock_rdlock(&filter_registry.lock) < 0) { - git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); - return -1; - } - - src.repo = repo; - src.path = path; - src.mode = mode; - - memcpy(&src.options, &filter_session->options, sizeof(git_filter_options)); - - if (blob) - git_oid_cpy(&src.oid, git_blob_id(blob)); - - git_vector_foreach(&filter_registry.filters, idx, fdef) { - const char **values = NULL; - void *payload = NULL; - - if (!fdef || !fdef->filter) - continue; - - if (fdef->nattrs > 0) { - error = filter_list_check_attributes( - &values, repo, - filter_session, fdef, &src); - - if (error == GIT_ENOTFOUND) { - error = 0; - continue; - } else if (error < 0) - break; - } - - if (!fdef->initialized && (error = filter_initialize(fdef)) < 0) - break; - - if (fdef->filter->check) - error = fdef->filter->check( - fdef->filter, &payload, &src, values); - - git__free((void *)values); - - if (error == GIT_PASSTHROUGH) - error = 0; - else if (error < 0) - break; - else { - if (!fl) { - if ((error = filter_list_new(&fl, &src)) < 0) - break; - - fl->temp_buf = filter_session->temp_buf; - } - - fe = git_array_alloc(fl->filters); - GIT_ERROR_CHECK_ALLOC(fe); - - fe->filter = fdef->filter; - fe->filter_name = fdef->filter_name; - fe->payload = payload; - } - } - - git_rwlock_rdunlock(&filter_registry.lock); - - if (error && fl != NULL) { - git_array_clear(fl->filters); - git__free(fl); - fl = NULL; - } - - *filters = fl; - return error; -} - -int git_filter_list_load_ext( - git_filter_list **filters, - git_repository *repo, - git_blob *blob, /* can be NULL */ - const char *path, - git_filter_mode_t mode, - git_filter_options *opts) -{ - git_filter_session filter_session = GIT_FILTER_SESSION_INIT; - - if (opts) - memcpy(&filter_session.options, opts, sizeof(git_filter_options)); - - return git_filter_list__load( - filters, repo, blob, path, mode, &filter_session); -} - -int git_filter_list_load( - git_filter_list **filters, - git_repository *repo, - git_blob *blob, /* can be NULL */ - const char *path, - git_filter_mode_t mode, - uint32_t flags) -{ - git_filter_session filter_session = GIT_FILTER_SESSION_INIT; - - filter_session.options.flags = flags; - - return git_filter_list__load( - filters, repo, blob, path, mode, &filter_session); -} - -void git_filter_list_free(git_filter_list *fl) -{ - uint32_t i; - - if (!fl) - return; - - for (i = 0; i < git_array_size(fl->filters); ++i) { - git_filter_entry *fe = git_array_get(fl->filters, i); - if (fe->filter->cleanup) - fe->filter->cleanup(fe->filter, fe->payload); - } - - git_array_clear(fl->filters); - git__free(fl); -} - -int git_filter_list_contains( - git_filter_list *fl, - const char *name) -{ - size_t i; - - GIT_ASSERT_ARG(name); - - if (!fl) - return 0; - - for (i = 0; i < fl->filters.size; i++) { - if (strcmp(fl->filters.ptr[i].filter_name, name) == 0) - return 1; - } - - return 0; -} - -int git_filter_list_push( - git_filter_list *fl, git_filter *filter, void *payload) -{ - int error = 0; - size_t pos; - git_filter_def *fdef = NULL; - git_filter_entry *fe; - - GIT_ASSERT_ARG(fl); - GIT_ASSERT_ARG(filter); - - if (git_rwlock_rdlock(&filter_registry.lock) < 0) { - git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); - return -1; - } - - if (git_vector_search2( - &pos, &filter_registry.filters, - filter_def_filter_key_check, filter) == 0) - fdef = git_vector_get(&filter_registry.filters, pos); - - git_rwlock_rdunlock(&filter_registry.lock); - - if (fdef == NULL) { - git_error_set(GIT_ERROR_FILTER, "cannot use an unregistered filter"); - return -1; - } - - if (!fdef->initialized && (error = filter_initialize(fdef)) < 0) - return error; - - fe = git_array_alloc(fl->filters); - GIT_ERROR_CHECK_ALLOC(fe); - fe->filter = filter; - fe->payload = payload; - - return 0; -} - -size_t git_filter_list_length(const git_filter_list *fl) -{ - return fl ? git_array_size(fl->filters) : 0; -} - -struct buf_stream { - git_writestream parent; - git_buf *target; - bool complete; -}; - -static int buf_stream_write( - git_writestream *s, const char *buffer, size_t len) -{ - struct buf_stream *buf_stream = (struct buf_stream *)s; - GIT_ASSERT_ARG(buf_stream); - GIT_ASSERT(buf_stream->complete == 0); - - return git_buf_put(buf_stream->target, buffer, len); -} - -static int buf_stream_close(git_writestream *s) -{ - struct buf_stream *buf_stream = (struct buf_stream *)s; - GIT_ASSERT_ARG(buf_stream); - - GIT_ASSERT(buf_stream->complete == 0); - buf_stream->complete = 1; - - return 0; -} - -static void buf_stream_free(git_writestream *s) -{ - GIT_UNUSED(s); -} - -static void buf_stream_init(struct buf_stream *writer, git_buf *target) -{ - memset(writer, 0, sizeof(struct buf_stream)); - - writer->parent.write = buf_stream_write; - writer->parent.close = buf_stream_close; - writer->parent.free = buf_stream_free; - writer->target = target; - - git_buf_clear(target); -} - -int git_filter_list_apply_to_buffer( - git_buf *out, - git_filter_list *filters, - const char *in, - size_t in_len) -{ - struct buf_stream writer; - int error; - - if ((error = git_buf_sanitize(out)) < 0) - return error; - - buf_stream_init(&writer, out); - - if ((error = git_filter_list_stream_buffer(filters, - in, in_len, &writer.parent)) < 0) - return error; - - GIT_ASSERT(writer.complete); - return error; -} - -int git_filter_list__convert_buf( - git_buf *out, - git_filter_list *filters, - git_buf *in) -{ - int error; - - if (!filters || git_filter_list_length(filters) == 0) { - git_buf_swap(out, in); - git_buf_dispose(in); - return 0; - } - - error = git_filter_list_apply_to_buffer(out, filters, - in->ptr, in->size); - - if (!error) - git_buf_dispose(in); - - return error; -} - -int git_filter_list_apply_to_file( - git_buf *out, - git_filter_list *filters, - git_repository *repo, - const char *path) -{ - struct buf_stream writer; - int error; - - buf_stream_init(&writer, out); - - if ((error = git_filter_list_stream_file( - filters, repo, path, &writer.parent)) < 0) - return error; - - GIT_ASSERT(writer.complete); - return error; -} - -static int buf_from_blob(git_buf *out, git_blob *blob) -{ - git_object_size_t rawsize = git_blob_rawsize(blob); - - if (!git__is_sizet(rawsize)) { - git_error_set(GIT_ERROR_OS, "blob is too large to filter"); - return -1; - } - - git_buf_attach_notowned(out, git_blob_rawcontent(blob), (size_t)rawsize); - return 0; -} - -int git_filter_list_apply_to_blob( - git_buf *out, - git_filter_list *filters, - git_blob *blob) -{ - struct buf_stream writer; - int error; - - buf_stream_init(&writer, out); - - if ((error = git_filter_list_stream_blob( - filters, blob, &writer.parent)) < 0) - return error; - - GIT_ASSERT(writer.complete); - return error; -} - -struct buffered_stream { - git_writestream parent; - git_filter *filter; - int (*write_fn)(git_filter *, void **, git_buf *, const git_buf *, const git_filter_source *); - const git_filter_source *source; - void **payload; - git_buf input; - git_buf temp_buf; - git_buf *output; - git_writestream *target; -}; - -static int buffered_stream_write( - git_writestream *s, const char *buffer, size_t len) -{ - struct buffered_stream *buffered_stream = (struct buffered_stream *)s; - GIT_ASSERT_ARG(buffered_stream); - - return git_buf_put(&buffered_stream->input, buffer, len); -} - -static int buffered_stream_close(git_writestream *s) -{ - struct buffered_stream *buffered_stream = (struct buffered_stream *)s; - git_buf *writebuf; - git_error_state error_state = {0}; - int error; - - GIT_ASSERT_ARG(buffered_stream); - - error = buffered_stream->write_fn( - buffered_stream->filter, - buffered_stream->payload, - buffered_stream->output, - &buffered_stream->input, - buffered_stream->source); - - if (error == GIT_PASSTHROUGH) { - writebuf = &buffered_stream->input; - } else if (error == 0) { - if ((error = git_buf_sanitize(buffered_stream->output)) < 0) - return error; - - writebuf = buffered_stream->output; - } else { - /* close stream before erroring out taking care - * to preserve the original error */ - git_error_state_capture(&error_state, error); - buffered_stream->target->close(buffered_stream->target); - git_error_state_restore(&error_state); - return error; - } - - if ((error = buffered_stream->target->write( - buffered_stream->target, writebuf->ptr, writebuf->size)) == 0) - error = buffered_stream->target->close(buffered_stream->target); - - return error; -} - -static void buffered_stream_free(git_writestream *s) -{ - struct buffered_stream *buffered_stream = (struct buffered_stream *)s; - - if (buffered_stream) { - git_buf_dispose(&buffered_stream->input); - git_buf_dispose(&buffered_stream->temp_buf); - git__free(buffered_stream); - } -} - -int git_filter_buffered_stream_new( - git_writestream **out, - git_filter *filter, - int (*write_fn)(git_filter *, void **, git_buf *, const git_buf *, const git_filter_source *), - git_buf *temp_buf, - void **payload, - const git_filter_source *source, - git_writestream *target) -{ - struct buffered_stream *buffered_stream = git__calloc(1, sizeof(struct buffered_stream)); - GIT_ERROR_CHECK_ALLOC(buffered_stream); - - buffered_stream->parent.write = buffered_stream_write; - buffered_stream->parent.close = buffered_stream_close; - buffered_stream->parent.free = buffered_stream_free; - buffered_stream->filter = filter; - buffered_stream->write_fn = write_fn; - buffered_stream->output = temp_buf ? temp_buf : &buffered_stream->temp_buf; - buffered_stream->payload = payload; - buffered_stream->source = source; - buffered_stream->target = target; - - if (temp_buf) - git_buf_clear(temp_buf); - - *out = (git_writestream *)buffered_stream; - return 0; -} - -static int setup_stream( - git_writestream **out, - git_filter_entry *fe, - git_filter_list *filters, - git_writestream *last_stream) -{ -#ifndef GIT_DEPRECATE_HARD - GIT_ASSERT(fe->filter->stream || fe->filter->apply); - - /* - * If necessary, create a stream that proxies the traditional - * application. - */ - if (!fe->filter->stream) { - /* Create a stream that proxies the one-shot apply */ - return git_filter_buffered_stream_new(out, - fe->filter, fe->filter->apply, filters->temp_buf, - &fe->payload, &filters->source, last_stream); - } -#endif - - GIT_ASSERT(fe->filter->stream); - return fe->filter->stream(out, fe->filter, - &fe->payload, &filters->source, last_stream); -} - -static int stream_list_init( - git_writestream **out, - git_vector *streams, - git_filter_list *filters, - git_writestream *target) -{ - git_writestream *last_stream = target; - size_t i; - int error = 0; - - *out = NULL; - - if (!filters) { - *out = target; - return 0; - } - - /* Create filters last to first to get the chaining direction */ - for (i = 0; i < git_array_size(filters->filters); ++i) { - size_t filter_idx = (filters->source.mode == GIT_FILTER_TO_WORKTREE) ? - git_array_size(filters->filters) - 1 - i : i; - - git_filter_entry *fe = git_array_get(filters->filters, filter_idx); - git_writestream *filter_stream; - - error = setup_stream(&filter_stream, fe, filters, last_stream); - - if (error < 0) - goto out; - - git_vector_insert(streams, filter_stream); - last_stream = filter_stream; - } - -out: - if (error) - last_stream->close(last_stream); - else - *out = last_stream; - - return error; -} - -static void filter_streams_free(git_vector *streams) -{ - git_writestream *stream; - size_t i; - - git_vector_foreach(streams, i, stream) - stream->free(stream); - git_vector_free(streams); -} - -int git_filter_list_stream_file( - git_filter_list *filters, - git_repository *repo, - const char *path, - git_writestream *target) -{ - char buf[FILTERIO_BUFSIZE]; - git_buf abspath = GIT_BUF_INIT; - const char *base = repo ? git_repository_workdir(repo) : NULL; - git_vector filter_streams = GIT_VECTOR_INIT; - git_writestream *stream_start; - ssize_t readlen; - int fd = -1, error, initialized = 0; - - if ((error = stream_list_init( - &stream_start, &filter_streams, filters, target)) < 0 || - (error = git_path_join_unrooted(&abspath, path, base, NULL)) < 0 || - (error = git_path_validate_workdir_buf(repo, &abspath)) < 0) - goto done; - - initialized = 1; - - if ((fd = git_futils_open_ro(abspath.ptr)) < 0) { - error = fd; - goto done; - } - - while ((readlen = p_read(fd, buf, sizeof(buf))) > 0) { - if ((error = stream_start->write(stream_start, buf, readlen)) < 0) - goto done; - } - - if (readlen < 0) - error = -1; - -done: - if (initialized) - error |= stream_start->close(stream_start); - - if (fd >= 0) - p_close(fd); - filter_streams_free(&filter_streams); - git_buf_dispose(&abspath); - return error; -} - -int git_filter_list_stream_buffer( - git_filter_list *filters, - const char *buffer, - size_t len, - git_writestream *target) -{ - git_vector filter_streams = GIT_VECTOR_INIT; - git_writestream *stream_start; - int error, initialized = 0; - - if ((error = stream_list_init(&stream_start, &filter_streams, filters, target)) < 0) - goto out; - initialized = 1; - - if ((error = stream_start->write(stream_start, buffer, len)) < 0) - goto out; - -out: - if (initialized) - error |= stream_start->close(stream_start); - - filter_streams_free(&filter_streams); - return error; -} - -int git_filter_list_stream_blob( - git_filter_list *filters, - git_blob *blob, - git_writestream *target) -{ - git_buf in = GIT_BUF_INIT; - - if (buf_from_blob(&in, blob) < 0) - return -1; - - if (filters) - git_oid_cpy(&filters->source.oid, git_blob_id(blob)); - - return git_filter_list_stream_buffer(filters, in.ptr, in.size, target); -} - -int git_filter_init(git_filter *filter, unsigned int version) -{ - GIT_INIT_STRUCTURE_FROM_TEMPLATE(filter, version, git_filter, GIT_FILTER_INIT); - return 0; -} - -#ifndef GIT_DEPRECATE_HARD - -int git_filter_list_stream_data( - git_filter_list *filters, - git_buf *data, - git_writestream *target) -{ - int error; - - if ((error = git_buf_sanitize(data)) < 0) - return error; - - return git_filter_list_stream_buffer(filters, data->ptr, data->size, target); -} - -int git_filter_list_apply_to_data( - git_buf *tgt, git_filter_list *filters, git_buf *src) -{ - int error; - - if ((error = git_buf_sanitize(src)) < 0) - return error; - - return git_filter_list_apply_to_buffer(tgt, filters, src->ptr, src->size); -} - -#endif |