2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
13 #include "repository.h"
15 #include "git2/sys/filter.h"
16 #include "git2/config.h"
18 #include "attr_file.h"
21 struct git_filter_source
{
24 git_oid oid
; /* zero if unknown (which is likely) */
25 uint16_t filemode
; /* zero if unknown */
26 git_filter_mode_t mode
;
31 const char *filter_name
;
36 struct git_filter_list
{
37 git_array_t(git_filter_entry
) filters
;
38 git_filter_source source
;
40 char path
[GIT_FLEX_ARRAY
];
48 size_t nattrs
, nmatches
;
50 const char *attrs
[GIT_FLEX_ARRAY
];
53 static int filter_def_priority_cmp(const void *a
, const void *b
)
55 int pa
= ((const git_filter_def
*)a
)->priority
;
56 int pb
= ((const git_filter_def
*)b
)->priority
;
57 return (pa
< pb
) ? -1 : (pa
> pb
) ? 1 : 0;
60 struct git_filter_registry
{
65 static struct git_filter_registry filter_registry
;
67 static void git_filter_global_shutdown(void);
70 static int filter_def_scan_attrs(
71 git_buf
*attrs
, size_t *nattr
, size_t *nmatch
, const char *attr_str
)
73 const char *start
, *scan
= attr_str
;
82 while (git__isspace(*scan
)) scan
++;
84 for (start
= scan
, has_eq
= 0; *scan
&& !git__isspace(*scan
); ++scan
) {
91 if (has_eq
|| *start
== '-' || *start
== '+' || *start
== '!')
95 git_buf_putc(attrs
, '=');
96 git_buf_put(attrs
, start
, scan
- start
);
97 git_buf_putc(attrs
, '\0');
104 static void filter_def_set_attrs(git_filter_def
*fdef
)
106 char *scan
= fdef
->attrdata
;
109 for (i
= 0; i
< fdef
->nattrs
; ++i
) {
110 const char *name
, *value
;
115 for (scan
++; *scan
!= '='; scan
++) /* find '=' */;
120 name
= scan
+ 1; value
= git_attr__false
; break;
122 name
= scan
+ 1; value
= git_attr__true
; break;
124 name
= scan
+ 1; value
= git_attr__unset
; break;
126 name
= scan
; value
= NULL
; break;
129 fdef
->attrs
[i
] = name
;
130 fdef
->attrs
[i
+ fdef
->nattrs
] = value
;
132 scan
+= strlen(scan
) + 1;
136 static int filter_def_name_key_check(const void *key
, const void *fdef
)
139 fdef
? ((const git_filter_def
*)fdef
)->filter_name
: NULL
;
140 return name
? git__strcmp(key
, name
) : -1;
143 static int filter_def_filter_key_check(const void *key
, const void *fdef
)
145 const void *filter
= fdef
? ((const git_filter_def
*)fdef
)->filter
: NULL
;
146 return (key
== filter
) ? 0 : -1;
149 /* Note: callers must lock the registry before calling this function */
150 static int filter_registry_insert(
151 const char *name
, git_filter
*filter
, int priority
)
153 git_filter_def
*fdef
;
154 size_t nattr
= 0, nmatch
= 0, alloc_len
;
155 git_buf attrs
= GIT_BUF_INIT
;
157 if (filter_def_scan_attrs(&attrs
, &nattr
, &nmatch
, filter
->attributes
) < 0)
160 GIT_ERROR_CHECK_ALLOC_MULTIPLY(&alloc_len
, nattr
, 2);
161 GIT_ERROR_CHECK_ALLOC_MULTIPLY(&alloc_len
, alloc_len
, sizeof(char *));
162 GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len
, alloc_len
, sizeof(git_filter_def
));
164 fdef
= git__calloc(1, alloc_len
);
165 GIT_ERROR_CHECK_ALLOC(fdef
);
167 fdef
->filter_name
= git__strdup(name
);
168 GIT_ERROR_CHECK_ALLOC(fdef
->filter_name
);
170 fdef
->filter
= filter
;
171 fdef
->priority
= priority
;
172 fdef
->nattrs
= nattr
;
173 fdef
->nmatches
= nmatch
;
174 fdef
->attrdata
= git_buf_detach(&attrs
);
176 filter_def_set_attrs(fdef
);
178 if (git_vector_insert(&filter_registry
.filters
, fdef
) < 0) {
179 git__free(fdef
->filter_name
);
180 git__free(fdef
->attrdata
);
185 git_vector_sort(&filter_registry
.filters
);
189 int git_filter_global_init(void)
191 git_filter
*crlf
= NULL
, *ident
= NULL
;
194 if (git_rwlock_init(&filter_registry
.lock
) < 0)
197 if ((error
= git_vector_init(&filter_registry
.filters
, 2,
198 filter_def_priority_cmp
)) < 0)
201 if ((crlf
= git_crlf_filter_new()) == NULL
||
202 filter_registry_insert(
203 GIT_FILTER_CRLF
, crlf
, GIT_FILTER_CRLF_PRIORITY
) < 0 ||
204 (ident
= git_ident_filter_new()) == NULL
||
205 filter_registry_insert(
206 GIT_FILTER_IDENT
, ident
, GIT_FILTER_IDENT_PRIORITY
) < 0)
209 git__on_shutdown(git_filter_global_shutdown
);
213 git_filter_free(crlf
);
214 git_filter_free(ident
);
220 static void git_filter_global_shutdown(void)
223 git_filter_def
*fdef
;
225 if (git_rwlock_wrlock(&filter_registry
.lock
) < 0)
228 git_vector_foreach(&filter_registry
.filters
, pos
, fdef
) {
229 if (fdef
->filter
&& fdef
->filter
->shutdown
) {
230 fdef
->filter
->shutdown(fdef
->filter
);
231 fdef
->initialized
= false;
234 git__free(fdef
->filter_name
);
235 git__free(fdef
->attrdata
);
239 git_vector_free(&filter_registry
.filters
);
241 git_rwlock_wrunlock(&filter_registry
.lock
);
242 git_rwlock_free(&filter_registry
.lock
);
245 /* Note: callers must lock the registry before calling this function */
246 static int filter_registry_find(size_t *pos
, const char *name
)
248 return git_vector_search2(
249 pos
, &filter_registry
.filters
, filter_def_name_key_check
, name
);
252 /* Note: callers must lock the registry before calling this function */
253 static git_filter_def
*filter_registry_lookup(size_t *pos
, const char *name
)
255 git_filter_def
*fdef
= NULL
;
257 if (!filter_registry_find(pos
, name
))
258 fdef
= git_vector_get(&filter_registry
.filters
, *pos
);
264 int git_filter_register(
265 const char *name
, git_filter
*filter
, int priority
)
269 assert(name
&& filter
);
271 if (git_rwlock_wrlock(&filter_registry
.lock
) < 0) {
272 git_error_set(GIT_ERROR_OS
, "failed to lock filter registry");
276 if (!filter_registry_find(NULL
, name
)) {
278 GIT_ERROR_FILTER
, "attempt to reregister existing filter '%s'", name
);
283 error
= filter_registry_insert(name
, filter
, priority
);
286 git_rwlock_wrunlock(&filter_registry
.lock
);
290 int git_filter_unregister(const char *name
)
293 git_filter_def
*fdef
;
298 /* cannot unregister default filters */
299 if (!strcmp(GIT_FILTER_CRLF
, name
) || !strcmp(GIT_FILTER_IDENT
, name
)) {
300 git_error_set(GIT_ERROR_FILTER
, "cannot unregister filter '%s'", name
);
304 if (git_rwlock_wrlock(&filter_registry
.lock
) < 0) {
305 git_error_set(GIT_ERROR_OS
, "failed to lock filter registry");
309 if ((fdef
= filter_registry_lookup(&pos
, name
)) == NULL
) {
310 git_error_set(GIT_ERROR_FILTER
, "cannot find filter '%s' to unregister", name
);
311 error
= GIT_ENOTFOUND
;
315 git_vector_remove(&filter_registry
.filters
, pos
);
317 if (fdef
->initialized
&& fdef
->filter
&& fdef
->filter
->shutdown
) {
318 fdef
->filter
->shutdown(fdef
->filter
);
319 fdef
->initialized
= false;
322 git__free(fdef
->filter_name
);
323 git__free(fdef
->attrdata
);
327 git_rwlock_wrunlock(&filter_registry
.lock
);
331 static int filter_initialize(git_filter_def
*fdef
)
335 if (!fdef
->initialized
&& fdef
->filter
&& fdef
->filter
->initialize
) {
336 if ((error
= fdef
->filter
->initialize(fdef
->filter
)) < 0)
340 fdef
->initialized
= true;
344 git_filter
*git_filter_lookup(const char *name
)
347 git_filter_def
*fdef
;
348 git_filter
*filter
= NULL
;
350 if (git_rwlock_rdlock(&filter_registry
.lock
) < 0) {
351 git_error_set(GIT_ERROR_OS
, "failed to lock filter registry");
355 if ((fdef
= filter_registry_lookup(&pos
, name
)) == NULL
||
356 (!fdef
->initialized
&& filter_initialize(fdef
) < 0))
359 filter
= fdef
->filter
;
362 git_rwlock_rdunlock(&filter_registry
.lock
);
366 void git_filter_free(git_filter
*filter
)
371 git_repository
*git_filter_source_repo(const git_filter_source
*src
)
376 const char *git_filter_source_path(const git_filter_source
*src
)
381 uint16_t git_filter_source_filemode(const git_filter_source
*src
)
383 return src
->filemode
;
386 const git_oid
*git_filter_source_id(const git_filter_source
*src
)
388 return git_oid_is_zero(&src
->oid
) ? NULL
: &src
->oid
;
391 git_filter_mode_t
git_filter_source_mode(const git_filter_source
*src
)
396 uint32_t git_filter_source_flags(const git_filter_source
*src
)
401 static int filter_list_new(
402 git_filter_list
**out
, const git_filter_source
*src
)
404 git_filter_list
*fl
= NULL
;
405 size_t pathlen
= src
->path
? strlen(src
->path
) : 0, alloclen
;
407 GIT_ERROR_CHECK_ALLOC_ADD(&alloclen
, sizeof(git_filter_list
), pathlen
);
408 GIT_ERROR_CHECK_ALLOC_ADD(&alloclen
, alloclen
, 1);
410 fl
= git__calloc(1, alloclen
);
411 GIT_ERROR_CHECK_ALLOC(fl
);
414 memcpy(fl
->path
, src
->path
, pathlen
);
415 fl
->source
.repo
= src
->repo
;
416 fl
->source
.path
= fl
->path
;
417 fl
->source
.mode
= src
->mode
;
418 fl
->source
.flags
= src
->flags
;
424 static int filter_list_check_attributes(
426 git_repository
*repo
,
427 git_attr_session
*attr_session
,
428 git_filter_def
*fdef
,
429 const git_filter_source
*src
)
431 const char **strs
= git__calloc(fdef
->nattrs
, sizeof(const char *));
436 GIT_ERROR_CHECK_ALLOC(strs
);
438 if ((src
->flags
& GIT_FILTER_NO_SYSTEM_ATTRIBUTES
) != 0)
439 flags
|= GIT_ATTR_CHECK_NO_SYSTEM
;
441 if ((src
->flags
& GIT_FILTER_ATTRIBUTES_FROM_HEAD
) != 0)
442 flags
|= GIT_ATTR_CHECK_INCLUDE_HEAD
;
444 error
= git_attr_get_many_with_session(
445 strs
, repo
, attr_session
, flags
, src
->path
, fdef
->nattrs
, fdef
->attrs
);
447 /* if no values were found but no matches are needed, it's okay! */
448 if (error
== GIT_ENOTFOUND
&& !fdef
->nmatches
) {
450 git__free((void *)strs
);
454 for (i
= 0; !error
&& i
< fdef
->nattrs
; ++i
) {
455 const char *want
= fdef
->attrs
[fdef
->nattrs
+ i
];
456 git_attr_value_t want_type
, found_type
;
461 want_type
= git_attr_value(want
);
462 found_type
= git_attr_value(strs
[i
]);
464 if (want_type
!= found_type
)
465 error
= GIT_ENOTFOUND
;
466 else if (want_type
== GIT_ATTR_VALUE_STRING
&&
467 strcmp(want
, strs
[i
]) &&
469 error
= GIT_ENOTFOUND
;
473 git__free((void *)strs
);
480 int git_filter_list_new(
481 git_filter_list
**out
,
482 git_repository
*repo
,
483 git_filter_mode_t mode
,
486 git_filter_source src
= { 0 };
491 return filter_list_new(out
, &src
);
494 int git_filter_list__load_ext(
495 git_filter_list
**filters
,
496 git_repository
*repo
,
497 git_blob
*blob
, /* can be NULL */
499 git_filter_mode_t mode
,
500 git_filter_options
*filter_opts
)
503 git_filter_list
*fl
= NULL
;
504 git_filter_source src
= { 0 };
505 git_filter_entry
*fe
;
507 git_filter_def
*fdef
;
509 if (git_rwlock_rdlock(&filter_registry
.lock
) < 0) {
510 git_error_set(GIT_ERROR_OS
, "failed to lock filter registry");
517 src
.flags
= filter_opts
->flags
;
520 git_oid_cpy(&src
.oid
, git_blob_id(blob
));
522 git_vector_foreach(&filter_registry
.filters
, idx
, fdef
) {
523 const char **values
= NULL
;
524 void *payload
= NULL
;
526 if (!fdef
|| !fdef
->filter
)
529 if (fdef
->nattrs
> 0) {
530 error
= filter_list_check_attributes(
531 &values
, repo
, filter_opts
->attr_session
, fdef
, &src
);
533 if (error
== GIT_ENOTFOUND
) {
536 } else if (error
< 0)
540 if (!fdef
->initialized
&& (error
= filter_initialize(fdef
)) < 0)
543 if (fdef
->filter
->check
)
544 error
= fdef
->filter
->check(
545 fdef
->filter
, &payload
, &src
, values
);
547 git__free((void *)values
);
549 if (error
== GIT_PASSTHROUGH
)
555 if ((error
= filter_list_new(&fl
, &src
)) < 0)
558 fl
->temp_buf
= filter_opts
->temp_buf
;
561 fe
= git_array_alloc(fl
->filters
);
562 GIT_ERROR_CHECK_ALLOC(fe
);
564 fe
->filter
= fdef
->filter
;
565 fe
->filter_name
= fdef
->filter_name
;
566 fe
->payload
= payload
;
570 git_rwlock_rdunlock(&filter_registry
.lock
);
572 if (error
&& fl
!= NULL
) {
573 git_array_clear(fl
->filters
);
582 int git_filter_list_load(
583 git_filter_list
**filters
,
584 git_repository
*repo
,
585 git_blob
*blob
, /* can be NULL */
587 git_filter_mode_t mode
,
590 git_filter_options filter_opts
= GIT_FILTER_OPTIONS_INIT
;
592 filter_opts
.flags
= flags
;
594 return git_filter_list__load_ext(
595 filters
, repo
, blob
, path
, mode
, &filter_opts
);
598 void git_filter_list_free(git_filter_list
*fl
)
605 for (i
= 0; i
< git_array_size(fl
->filters
); ++i
) {
606 git_filter_entry
*fe
= git_array_get(fl
->filters
, i
);
607 if (fe
->filter
->cleanup
)
608 fe
->filter
->cleanup(fe
->filter
, fe
->payload
);
611 git_array_clear(fl
->filters
);
615 int git_filter_list_contains(
626 for (i
= 0; i
< fl
->filters
.size
; i
++) {
627 if (strcmp(fl
->filters
.ptr
[i
].filter_name
, name
) == 0)
634 int git_filter_list_push(
635 git_filter_list
*fl
, git_filter
*filter
, void *payload
)
639 git_filter_def
*fdef
= NULL
;
640 git_filter_entry
*fe
;
642 assert(fl
&& filter
);
644 if (git_rwlock_rdlock(&filter_registry
.lock
) < 0) {
645 git_error_set(GIT_ERROR_OS
, "failed to lock filter registry");
649 if (git_vector_search2(
650 &pos
, &filter_registry
.filters
,
651 filter_def_filter_key_check
, filter
) == 0)
652 fdef
= git_vector_get(&filter_registry
.filters
, pos
);
654 git_rwlock_rdunlock(&filter_registry
.lock
);
657 git_error_set(GIT_ERROR_FILTER
, "cannot use an unregistered filter");
661 if (!fdef
->initialized
&& (error
= filter_initialize(fdef
)) < 0)
664 fe
= git_array_alloc(fl
->filters
);
665 GIT_ERROR_CHECK_ALLOC(fe
);
667 fe
->payload
= payload
;
672 size_t git_filter_list_length(const git_filter_list
*fl
)
674 return fl
? git_array_size(fl
->filters
) : 0;
678 git_writestream parent
;
683 static int buf_stream_write(
684 git_writestream
*s
, const char *buffer
, size_t len
)
686 struct buf_stream
*buf_stream
= (struct buf_stream
*)s
;
689 assert(buf_stream
->complete
== 0);
691 return git_buf_put(buf_stream
->target
, buffer
, len
);
694 static int buf_stream_close(git_writestream
*s
)
696 struct buf_stream
*buf_stream
= (struct buf_stream
*)s
;
699 assert(buf_stream
->complete
== 0);
700 buf_stream
->complete
= 1;
705 static void buf_stream_free(git_writestream
*s
)
710 static void buf_stream_init(struct buf_stream
*writer
, git_buf
*target
)
712 memset(writer
, 0, sizeof(struct buf_stream
));
714 writer
->parent
.write
= buf_stream_write
;
715 writer
->parent
.close
= buf_stream_close
;
716 writer
->parent
.free
= buf_stream_free
;
717 writer
->target
= target
;
719 git_buf_clear(target
);
722 int git_filter_list_apply_to_data(
723 git_buf
*tgt
, git_filter_list
*filters
, git_buf
*src
)
725 struct buf_stream writer
;
728 git_buf_sanitize(tgt
);
729 git_buf_sanitize(src
);
732 git_buf_attach_notowned(tgt
, src
->ptr
, src
->size
);
736 buf_stream_init(&writer
, tgt
);
738 if ((error
= git_filter_list_stream_data(filters
, src
,
739 &writer
.parent
)) < 0)
742 assert(writer
.complete
);
746 int git_filter_list_apply_to_file(
748 git_filter_list
*filters
,
749 git_repository
*repo
,
752 struct buf_stream writer
;
755 buf_stream_init(&writer
, out
);
757 if ((error
= git_filter_list_stream_file(
758 filters
, repo
, path
, &writer
.parent
)) < 0)
761 assert(writer
.complete
);
765 static int buf_from_blob(git_buf
*out
, git_blob
*blob
)
767 git_object_size_t rawsize
= git_blob_rawsize(blob
);
769 if (!git__is_sizet(rawsize
)) {
770 git_error_set(GIT_ERROR_OS
, "blob is too large to filter");
774 git_buf_attach_notowned(out
, git_blob_rawcontent(blob
), (size_t)rawsize
);
778 int git_filter_list_apply_to_blob(
780 git_filter_list
*filters
,
783 struct buf_stream writer
;
786 buf_stream_init(&writer
, out
);
788 if ((error
= git_filter_list_stream_blob(
789 filters
, blob
, &writer
.parent
)) < 0)
792 assert(writer
.complete
);
796 struct proxy_stream
{
797 git_writestream parent
;
799 const git_filter_source
*source
;
804 git_writestream
*target
;
807 static int proxy_stream_write(
808 git_writestream
*s
, const char *buffer
, size_t len
)
810 struct proxy_stream
*proxy_stream
= (struct proxy_stream
*)s
;
811 assert(proxy_stream
);
813 return git_buf_put(&proxy_stream
->input
, buffer
, len
);
816 static int proxy_stream_close(git_writestream
*s
)
818 struct proxy_stream
*proxy_stream
= (struct proxy_stream
*)s
;
820 git_error_state error_state
= {0};
823 assert(proxy_stream
);
825 error
= proxy_stream
->filter
->apply(
826 proxy_stream
->filter
,
827 proxy_stream
->payload
,
828 proxy_stream
->output
,
829 &proxy_stream
->input
,
830 proxy_stream
->source
);
832 if (error
== GIT_PASSTHROUGH
) {
833 writebuf
= &proxy_stream
->input
;
834 } else if (error
== 0) {
835 git_buf_sanitize(proxy_stream
->output
);
836 writebuf
= proxy_stream
->output
;
838 /* close stream before erroring out taking care
839 * to preserve the original error */
840 git_error_state_capture(&error_state
, error
);
841 proxy_stream
->target
->close(proxy_stream
->target
);
842 git_error_state_restore(&error_state
);
846 if ((error
= proxy_stream
->target
->write(
847 proxy_stream
->target
, writebuf
->ptr
, writebuf
->size
)) == 0)
848 error
= proxy_stream
->target
->close(proxy_stream
->target
);
853 static void proxy_stream_free(git_writestream
*s
)
855 struct proxy_stream
*proxy_stream
= (struct proxy_stream
*)s
;
856 assert(proxy_stream
);
858 git_buf_dispose(&proxy_stream
->input
);
859 git_buf_dispose(&proxy_stream
->temp_buf
);
860 git__free(proxy_stream
);
863 static int proxy_stream_init(
864 git_writestream
**out
,
868 const git_filter_source
*source
,
869 git_writestream
*target
)
871 struct proxy_stream
*proxy_stream
= git__calloc(1, sizeof(struct proxy_stream
));
872 GIT_ERROR_CHECK_ALLOC(proxy_stream
);
874 proxy_stream
->parent
.write
= proxy_stream_write
;
875 proxy_stream
->parent
.close
= proxy_stream_close
;
876 proxy_stream
->parent
.free
= proxy_stream_free
;
877 proxy_stream
->filter
= filter
;
878 proxy_stream
->payload
= payload
;
879 proxy_stream
->source
= source
;
880 proxy_stream
->target
= target
;
881 proxy_stream
->output
= temp_buf
? temp_buf
: &proxy_stream
->temp_buf
;
884 git_buf_clear(temp_buf
);
886 *out
= (git_writestream
*)proxy_stream
;
890 static int stream_list_init(
891 git_writestream
**out
,
893 git_filter_list
*filters
,
894 git_writestream
*target
)
896 git_writestream
*last_stream
= target
;
907 /* Create filters last to first to get the chaining direction */
908 for (i
= 0; i
< git_array_size(filters
->filters
); ++i
) {
909 size_t filter_idx
= (filters
->source
.mode
== GIT_FILTER_TO_WORKTREE
) ?
910 git_array_size(filters
->filters
) - 1 - i
: i
;
911 git_filter_entry
*fe
= git_array_get(filters
->filters
, filter_idx
);
912 git_writestream
*filter_stream
;
914 assert(fe
->filter
->stream
|| fe
->filter
->apply
);
916 /* If necessary, create a stream that proxies the traditional
919 if (fe
->filter
->stream
)
920 error
= fe
->filter
->stream(&filter_stream
, fe
->filter
,
921 &fe
->payload
, &filters
->source
, last_stream
);
923 /* Create a stream that proxies the one-shot apply */
924 error
= proxy_stream_init(&filter_stream
, fe
->filter
,
925 filters
->temp_buf
, &fe
->payload
, &filters
->source
,
931 git_vector_insert(streams
, filter_stream
);
932 last_stream
= filter_stream
;
937 last_stream
->close(last_stream
);
944 static void filter_streams_free(git_vector
*streams
)
946 git_writestream
*stream
;
949 git_vector_foreach(streams
, i
, stream
)
950 stream
->free(stream
);
951 git_vector_free(streams
);
954 int git_filter_list_stream_file(
955 git_filter_list
*filters
,
956 git_repository
*repo
,
958 git_writestream
*target
)
960 char buf
[FILTERIO_BUFSIZE
];
961 git_buf abspath
= GIT_BUF_INIT
;
962 const char *base
= repo
? git_repository_workdir(repo
) : NULL
;
963 git_vector filter_streams
= GIT_VECTOR_INIT
;
964 git_writestream
*stream_start
;
966 int fd
= -1, error
, initialized
= 0;
968 if ((error
= stream_list_init(
969 &stream_start
, &filter_streams
, filters
, target
)) < 0 ||
970 (error
= git_path_join_unrooted(&abspath
, path
, base
, NULL
)) < 0)
974 if ((fd
= git_futils_open_ro(abspath
.ptr
)) < 0) {
979 while ((readlen
= p_read(fd
, buf
, sizeof(buf
))) > 0) {
980 if ((error
= stream_start
->write(stream_start
, buf
, readlen
)) < 0)
989 error
|= stream_start
->close(stream_start
);
993 filter_streams_free(&filter_streams
);
994 git_buf_dispose(&abspath
);
998 int git_filter_list_stream_data(
999 git_filter_list
*filters
,
1001 git_writestream
*target
)
1003 git_vector filter_streams
= GIT_VECTOR_INIT
;
1004 git_writestream
*stream_start
;
1005 int error
, initialized
= 0;
1007 git_buf_sanitize(data
);
1009 if ((error
= stream_list_init(&stream_start
, &filter_streams
, filters
, target
)) < 0)
1013 if ((error
= stream_start
->write(
1014 stream_start
, data
->ptr
, data
->size
)) < 0)
1019 error
|= stream_start
->close(stream_start
);
1021 filter_streams_free(&filter_streams
);
1025 int git_filter_list_stream_blob(
1026 git_filter_list
*filters
,
1028 git_writestream
*target
)
1030 git_buf in
= GIT_BUF_INIT
;
1032 if (buf_from_blob(&in
, blob
) < 0)
1036 git_oid_cpy(&filters
->source
.oid
, git_blob_id(blob
));
1038 return git_filter_list_stream_data(filters
, &in
, target
);
1041 int git_filter_init(git_filter
*filter
, unsigned int version
)
1043 GIT_INIT_STRUCTURE_FROM_TEMPLATE(filter
, version
, git_filter
, GIT_FILTER_INIT
);