source src/filter.c
Line | Flow | Count | Block(s) | Source |
---|---|---|---|---|
1 | - | /* | ||
2 | - | * Copyright (C) the libgit2 contributors. All rights reserved. | ||
3 | - | * | ||
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. | ||
6 | - | */ | ||
7 | - | |||
8 | - | #include "filter.h" | ||
9 | - | |||
10 | - | #include "common.h" | ||
11 | - | #include "futils.h" | ||
12 | - | #include "hash.h" | ||
13 | - | #include "repository.h" | ||
14 | - | #include "global.h" | ||
15 | - | #include "git2/sys/filter.h" | ||
16 | - | #include "git2/config.h" | ||
17 | - | #include "blob.h" | ||
18 | - | #include "attr_file.h" | ||
19 | - | #include "array.h" | ||
20 | - | |||
21 | - | struct git_filter_source { | ||
22 | - | git_repository *repo; | ||
23 | - | const char *path; | ||
24 | - | git_oid oid; /* zero if unknown (which is likely) */ | ||
25 | - | uint16_t filemode; /* zero if unknown */ | ||
26 | - | git_filter_mode_t mode; | ||
27 | - | uint32_t flags; | ||
28 | - | }; | ||
29 | - | |||
30 | - | typedef struct { | ||
31 | - | const char *filter_name; | ||
32 | - | git_filter *filter; | ||
33 | - | void *payload; | ||
34 | - | } git_filter_entry; | ||
35 | - | |||
36 | - | struct git_filter_list { | ||
37 | - | git_array_t(git_filter_entry) filters; | ||
38 | - | git_filter_source source; | ||
39 | - | git_buf *temp_buf; | ||
40 | - | char path[GIT_FLEX_ARRAY]; | ||
41 | - | }; | ||
42 | - | |||
43 | - | typedef struct { | ||
44 | - | char *filter_name; | ||
45 | - | git_filter *filter; | ||
46 | - | int priority; | ||
47 | - | int initialized; | ||
48 | - | size_t nattrs, nmatches; | ||
49 | - | char *attrdata; | ||
50 | - | const char *attrs[GIT_FLEX_ARRAY]; | ||
51 | - | } git_filter_def; | ||
52 | - | |||
53 | 78 | 2 | static int filter_def_priority_cmp(const void *a, const void *b) | |
54 | - | { | ||
55 | 78 | 2 | int pa = ((const git_filter_def *)a)->priority; | |
56 | 78 | 2 | int pb = ((const git_filter_def *)b)->priority; | |
57 | 78 | 2 | return (pa < pb) ? -1 : (pa > pb) ? 1 : 0; | |
58 | - | } | ||
59 | - | |||
60 | - | struct git_filter_registry { | ||
61 | - | git_rwlock lock; | ||
62 | - | git_vector filters; | ||
63 | - | }; | ||
64 | - | |||
65 | - | static struct git_filter_registry filter_registry; | ||
66 | - | |||
67 | - | static void git_filter_global_shutdown(void); | ||
68 | - | |||
69 | - | |||
70 | 29 | 2 | static int filter_def_scan_attrs( | |
71 | - | git_buf *attrs, size_t *nattr, size_t *nmatch, const char *attr_str) | ||
72 | - | { | ||
73 | 29 | 2 | const char *start, *scan = attr_str; | |
74 | - | int has_eq; | ||
75 | - | |||
76 | 29 | 2 | *nattr = *nmatch = 0; | |
77 | - | |||
78 | 29 | 2 | if (!scan) | |
79 | 1 | 3 | return 0; | |
80 | - | |||
81 | 74 | 4,26 | while (*scan) { | |
82 | 64 | 5-8 | while (git__isspace(*scan)) scan++; | |
83 | - | |||
84 | 287 | 9,12-15 | for (start = scan, has_eq = 0; *scan && !git__isspace(*scan); ++scan) { | |
85 | 241 | 10 | if (*scan == '=') | |
86 | 3 | 11 | has_eq = 1; | |
87 | - | } | ||
88 | - | |||
89 | 46 | 16 | if (scan > start) { | |
90 | 46 | 17 | (*nattr)++; | |
91 | 46 | 17-20 | if (has_eq || *start == '-' || *start == '+' || *start == '!') | |
92 | 19 | 21 | (*nmatch)++; | |
93 | - | |||
94 | 46 | 22 | if (has_eq) | |
95 | 3 | 23 | git_buf_putc(attrs, '='); | |
96 | 46 | 24 | git_buf_put(attrs, start, scan - start); | |
97 | 46 | 25 | git_buf_putc(attrs, '\0'); | |
98 | - | } | ||
99 | - | } | ||
100 | - | |||
101 | 28 | 27 | return 0; | |
102 | - | } | ||
103 | - | |||
104 | 29 | 2 | static void filter_def_set_attrs(git_filter_def *fdef) | |
105 | - | { | ||
106 | 29 | 2 | char *scan = fdef->attrdata; | |
107 | - | size_t i; | ||
108 | - | |||
109 | 75 | 2,12,13 | for (i = 0; i < fdef->nattrs; ++i) { | |
110 | - | const char *name, *value; | ||
111 | - | |||
112 | 46 | 3 | switch (*scan) { | |
113 | - | case '=': | ||
114 | 3 | 4 | name = scan + 1; | |
115 | 21 | 4-6 | for (scan++; *scan != '='; scan++) /* find '=' */; | |
116 | 3 | 7 | *scan++ = '\0'; | |
117 | 3 | 7 | value = scan; | |
118 | 3 | 7 | break; | |
119 | - | case '-': | ||
120 | ##### | 8 | name = scan + 1; value = git_attr__false; break; | |
121 | - | case '+': | ||
122 | 16 | 9 | name = scan + 1; value = git_attr__true; break; | |
123 | - | case '!': | ||
124 | ##### | 10 | name = scan + 1; value = git_attr__unset; break; | |
125 | - | default: | ||
126 | 27 | 11 | name = scan; value = NULL; break; | |
127 | - | } | ||
128 | - | |||
129 | 46 | 12 | fdef->attrs[i] = name; | |
130 | 46 | 12 | fdef->attrs[i + fdef->nattrs] = value; | |
131 | - | |||
132 | 46 | 12 | scan += strlen(scan) + 1; | |
133 | - | } | ||
134 | 29 | 14 | } | |
135 | - | |||
136 | 115 | 2 | static int filter_def_name_key_check(const void *key, const void *fdef) | |
137 | - | { | ||
138 | 115 | 5 | const char *name = | |
139 | 115 | 2-4 | fdef ? ((const git_filter_def *)fdef)->filter_name : NULL; | |
140 | 115 | 5 | return name ? git__strcmp(key, name) : -1; | |
141 | - | } | ||
142 | - | |||
143 | 20 | 2 | static int filter_def_filter_key_check(const void *key, const void *fdef) | |
144 | - | { | ||
145 | 20 | 2-4 | const void *filter = fdef ? ((const git_filter_def *)fdef)->filter : NULL; | |
146 | 20 | 5 | return (key == filter) ? 0 : -1; | |
147 | - | } | ||
148 | - | |||
149 | - | /* Note: callers must lock the registry before calling this function */ | ||
150 | 29 | 2 | static int filter_registry_insert( | |
151 | - | const char *name, git_filter *filter, int priority) | ||
152 | - | { | ||
153 | - | git_filter_def *fdef; | ||
154 | 29 | 2 | size_t nattr = 0, nmatch = 0, alloc_len; | |
155 | 29 | 2 | git_buf attrs = GIT_BUF_INIT; | |
156 | - | |||
157 | 29 | 2,3 | if (filter_def_scan_attrs(&attrs, &nattr, &nmatch, filter->attributes) < 0) | |
158 | ##### | 4 | return -1; | |
159 | - | |||
160 | 29 | 5-11 | GIT_ERROR_CHECK_ALLOC_MULTIPLY(&alloc_len, nattr, 2); | |
161 | 29 | 12-18 | GIT_ERROR_CHECK_ALLOC_MULTIPLY(&alloc_len, alloc_len, sizeof(char *)); | |
162 | 29 | 19-25 | GIT_ERROR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, sizeof(git_filter_def)); | |
163 | - | |||
164 | 29 | 26 | fdef = git__calloc(1, alloc_len); | |
165 | 29 | 27,28 | GIT_ERROR_CHECK_ALLOC(fdef); | |
166 | - | |||
167 | 29 | 29 | fdef->filter_name = git__strdup(name); | |
168 | 29 | 30,31 | GIT_ERROR_CHECK_ALLOC(fdef->filter_name); | |
169 | - | |||
170 | 29 | 32 | fdef->filter = filter; | |
171 | 29 | 32 | fdef->priority = priority; | |
172 | 29 | 32 | fdef->nattrs = nattr; | |
173 | 29 | 32 | fdef->nmatches = nmatch; | |
174 | 29 | 32 | fdef->attrdata = git_buf_detach(&attrs); | |
175 | - | |||
176 | 29 | 33 | filter_def_set_attrs(fdef); | |
177 | - | |||
178 | 29 | 34,35 | if (git_vector_insert(&filter_registry.filters, fdef) < 0) { | |
179 | ##### | 36 | git__free(fdef->filter_name); | |
180 | ##### | 37 | git__free(fdef->attrdata); | |
181 | ##### | 38 | git__free(fdef); | |
182 | ##### | 39 | return -1; | |
183 | - | } | ||
184 | - | |||
185 | 29 | 40 | git_vector_sort(&filter_registry.filters); | |
186 | 29 | 41 | return 0; | |
187 | - | } | ||
188 | - | |||
189 | 9 | 2 | int git_filter_global_init(void) | |
190 | - | { | ||
191 | 9 | 2 | git_filter *crlf = NULL, *ident = NULL; | |
192 | 9 | 2 | int error = 0; | |
193 | - | |||
194 | 9 | 2,3 | if (git_rwlock_init(&filter_registry.lock) < 0) | |
195 | ##### | 4 | return -1; | |
196 | - | |||
197 | 9 | 5,6 | if ((error = git_vector_init(&filter_registry.filters, 2, | |
198 | - | filter_def_priority_cmp)) < 0) | ||
199 | ##### | 7 | goto done; | |
200 | - | |||
201 | 9 | 8,9,11 | if ((crlf = git_crlf_filter_new()) == NULL || | |
202 | 9 | 10 | filter_registry_insert( | |
203 | 9 | 12,13 | GIT_FILTER_CRLF, crlf, GIT_FILTER_CRLF_PRIORITY) < 0 || | |
204 | 9 | 15 | (ident = git_ident_filter_new()) == NULL || | |
205 | 9 | 14 | filter_registry_insert( | |
206 | - | GIT_FILTER_IDENT, ident, GIT_FILTER_IDENT_PRIORITY) < 0) | ||
207 | ##### | 16 | error = -1; | |
208 | - | |||
209 | 9 | 17 | git__on_shutdown(git_filter_global_shutdown); | |
210 | - | |||
211 | - | done: | ||
212 | 9 | 18 | if (error) { | |
213 | ##### | 19 | git_filter_free(crlf); | |
214 | ##### | 20 | git_filter_free(ident); | |
215 | - | } | ||
216 | - | |||
217 | 9 | 21 | return error; | |
218 | - | } | ||
219 | - | |||
220 | 9 | 2 | static void git_filter_global_shutdown(void) | |
221 | - | { | ||
222 | - | size_t pos; | ||
223 | - | git_filter_def *fdef; | ||
224 | - | |||
225 | 9 | 2,3 | if (git_rwlock_wrlock(&filter_registry.lock) < 0) | |
226 | 9 | 4,19 | return; | |
227 | - | |||
228 | 31 | 5,13-15 | git_vector_foreach(&filter_registry.filters, pos, fdef) { | |
229 | 22 | 6,7 | if (fdef->filter && fdef->filter->shutdown) { | |
230 | 22 | 8 | fdef->filter->shutdown(fdef->filter); | |
231 | 22 | 9 | fdef->initialized = false; | |
232 | - | } | ||
233 | - | |||
234 | 22 | 10 | git__free(fdef->filter_name); | |
235 | 22 | 11 | git__free(fdef->attrdata); | |
236 | 22 | 12 | git__free(fdef); | |
237 | - | } | ||
238 | - | |||
239 | 9 | 16 | git_vector_free(&filter_registry.filters); | |
240 | - | |||
241 | 9 | 17 | git_rwlock_wrunlock(&filter_registry.lock); | |
242 | 9 | 18 | git_rwlock_free(&filter_registry.lock); | |
243 | - | } | ||
244 | - | |||
245 | - | /* Note: callers must lock the registry before calling this function */ | ||
246 | 30 | 2 | static int filter_registry_find(size_t *pos, const char *name) | |
247 | - | { | ||
248 | 30 | 2 | return git_vector_search2( | |
249 | - | pos, &filter_registry.filters, filter_def_name_key_check, name); | ||
250 | - | } | ||
251 | - | |||
252 | - | /* Note: callers must lock the registry before calling this function */ | ||
253 | 18 | 2 | static git_filter_def *filter_registry_lookup(size_t *pos, const char *name) | |
254 | - | { | ||
255 | 18 | 2 | git_filter_def *fdef = NULL; | |
256 | - | |||
257 | 18 | 2,3 | if (!filter_registry_find(pos, name)) | |
258 | 17 | 4 | fdef = git_vector_get(&filter_registry.filters, *pos); | |
259 | - | |||
260 | 18 | 5 | return fdef; | |
261 | - | } | ||
262 | - | |||
263 | - | |||
264 | 12 | 2 | int git_filter_register( | |
265 | - | const char *name, git_filter *filter, int priority) | ||
266 | - | { | ||
267 | - | int error; | ||
268 | - | |||
269 | 12 | 2-4 | assert(name && filter); | |
270 | - | |||
271 | 12 | 5,6 | if (git_rwlock_wrlock(&filter_registry.lock) < 0) { | |
272 | ##### | 7 | git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); | |
273 | ##### | 8 | return -1; | |
274 | - | } | ||
275 | - | |||
276 | 12 | 9,10 | if (!filter_registry_find(NULL, name)) { | |
277 | 1 | 11 | git_error_set( | |
278 | - | GIT_ERROR_FILTER, "attempt to reregister existing filter '%s'", name); | ||
279 | 1 | 12 | error = GIT_EEXISTS; | |
280 | 1 | 12 | goto done; | |
281 | - | } | ||
282 | - | |||
283 | 11 | 13 | error = filter_registry_insert(name, filter, priority); | |
284 | - | |||
285 | - | done: | ||
286 | 12 | 14 | git_rwlock_wrunlock(&filter_registry.lock); | |
287 | 12 | 15 | return error; | |
288 | - | } | ||
289 | - | |||
290 | 10 | 2 | int git_filter_unregister(const char *name) | |
291 | - | { | ||
292 | - | size_t pos; | ||
293 | - | git_filter_def *fdef; | ||
294 | 10 | 2 | int error = 0; | |
295 | - | |||
296 | 10 | 2,3 | assert(name); | |
297 | - | |||
298 | - | /* cannot unregister default filters */ | ||
299 | 10 | 4,5 | if (!strcmp(GIT_FILTER_CRLF, name) || !strcmp(GIT_FILTER_IDENT, name)) { | |
300 | 2 | 6 | git_error_set(GIT_ERROR_FILTER, "cannot unregister filter '%s'", name); | |
301 | 2 | 7 | return -1; | |
302 | - | } | ||
303 | - | |||
304 | 8 | 8,9 | if (git_rwlock_wrlock(&filter_registry.lock) < 0) { | |
305 | ##### | 10 | git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); | |
306 | ##### | 11 | return -1; | |
307 | - | } | ||
308 | - | |||
309 | 8 | 12,13 | if ((fdef = filter_registry_lookup(&pos, name)) == NULL) { | |
310 | 1 | 14 | git_error_set(GIT_ERROR_FILTER, "cannot find filter '%s' to unregister", name); | |
311 | 1 | 15 | error = GIT_ENOTFOUND; | |
312 | 1 | 15 | goto done; | |
313 | - | } | ||
314 | - | |||
315 | 7 | 16 | git_vector_remove(&filter_registry.filters, pos); | |
316 | - | |||
317 | 7 | 17-19 | if (fdef->initialized && fdef->filter && fdef->filter->shutdown) { | |
318 | 3 | 20 | fdef->filter->shutdown(fdef->filter); | |
319 | 3 | 21 | fdef->initialized = false; | |
320 | - | } | ||
321 | - | |||
322 | 7 | 22 | git__free(fdef->filter_name); | |
323 | 7 | 23 | git__free(fdef->attrdata); | |
324 | 7 | 24 | git__free(fdef); | |
325 | - | |||
326 | - | done: | ||
327 | 8 | 25 | git_rwlock_wrunlock(&filter_registry.lock); | |
328 | 8 | 26 | return error; | |
329 | - | } | ||
330 | - | |||
331 | 17 | 2 | static int filter_initialize(git_filter_def *fdef) | |
332 | - | { | ||
333 | 17 | 2 | int error = 0; | |
334 | - | |||
335 | 17 | 2-4 | if (!fdef->initialized && fdef->filter && fdef->filter->initialize) { | |
336 | ##### | 5,6 | if ((error = fdef->filter->initialize(fdef->filter)) < 0) | |
337 | ##### | 7 | return error; | |
338 | - | } | ||
339 | - | |||
340 | 17 | 8 | fdef->initialized = true; | |
341 | 17 | 8 | return 0; | |
342 | - | } | ||
343 | - | |||
344 | 10 | 2 | git_filter *git_filter_lookup(const char *name) | |
345 | - | { | ||
346 | - | size_t pos; | ||
347 | - | git_filter_def *fdef; | ||
348 | 10 | 2 | git_filter *filter = NULL; | |
349 | - | |||
350 | 10 | 2,3 | if (git_rwlock_rdlock(&filter_registry.lock) < 0) { | |
351 | ##### | 4 | git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); | |
352 | ##### | 5 | return NULL; | |
353 | - | } | ||
354 | - | |||
355 | 10 | 6-8 | if ((fdef = filter_registry_lookup(&pos, name)) == NULL || | |
356 | 10 | 8-10 | (!fdef->initialized && filter_initialize(fdef) < 0)) | |
357 | - | goto done; | ||
358 | - | |||
359 | 10 | 11 | filter = fdef->filter; | |
360 | - | |||
361 | - | done: | ||
362 | 10 | 12 | git_rwlock_rdunlock(&filter_registry.lock); | |
363 | 10 | 13 | return filter; | |
364 | - | } | ||
365 | - | |||
366 | 18 | 2 | void git_filter_free(git_filter *filter) | |
367 | - | { | ||
368 | 18 | 2 | git__free(filter); | |
369 | 18 | 3 | } | |
370 | - | |||
371 | 36298 | 2 | git_repository *git_filter_source_repo(const git_filter_source *src) | |
372 | - | { | ||
373 | 36298 | 2 | return src->repo; | |
374 | - | } | ||
375 | - | |||
376 | 1984 | 2 | const char *git_filter_source_path(const git_filter_source *src) | |
377 | - | { | ||
378 | 1984 | 2 | return src->path; | |
379 | - | } | ||
380 | - | |||
381 | ##### | 2 | uint16_t git_filter_source_filemode(const git_filter_source *src) | |
382 | - | { | ||
383 | ##### | 2 | return src->filemode; | |
384 | - | } | ||
385 | - | |||
386 | 40 | 2 | const git_oid *git_filter_source_id(const git_filter_source *src) | |
387 | - | { | ||
388 | 40 | 2 | return git_oid_is_zero(&src->oid) ? NULL : &src->oid; | |
389 | - | } | ||
390 | - | |||
391 | 2725 | 2 | git_filter_mode_t git_filter_source_mode(const git_filter_source *src) | |
392 | - | { | ||
393 | 2725 | 2 | return src->mode; | |
394 | - | } | ||
395 | - | |||
396 | 11937 | 2 | uint32_t git_filter_source_flags(const git_filter_source *src) | |
397 | - | { | ||
398 | 11937 | 2 | return src->flags; | |
399 | - | } | ||
400 | - | |||
401 | 2680 | 2 | static int filter_list_new( | |
402 | - | git_filter_list **out, const git_filter_source *src) | ||
403 | - | { | ||
404 | 2680 | 2 | git_filter_list *fl = NULL; | |
405 | 2680 | 2-4 | size_t pathlen = src->path ? strlen(src->path) : 0, alloclen; | |
406 | - | |||
407 | 2680 | 5-11 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_filter_list), pathlen); | |
408 | 2680 | 12-18 | GIT_ERROR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1); | |
409 | - | |||
410 | 2680 | 19 | fl = git__calloc(1, alloclen); | |
411 | 2680 | 20,21 | GIT_ERROR_CHECK_ALLOC(fl); | |
412 | - | |||
413 | 2680 | 22 | if (src->path) | |
414 | 2670 | 23 | memcpy(fl->path, src->path, pathlen); | |
415 | 2680 | 24 | fl->source.repo = src->repo; | |
416 | 2680 | 24 | fl->source.path = fl->path; | |
417 | 2680 | 24 | fl->source.mode = src->mode; | |
418 | 2680 | 24 | fl->source.flags = src->flags; | |
419 | - | |||
420 | 2680 | 24 | *out = fl; | |
421 | 2680 | 24 | return 0; | |
422 | - | } | ||
423 | - | |||
424 | 56540 | 2 | static int filter_list_check_attributes( | |
425 | - | const char ***out, | ||
426 | - | git_repository *repo, | ||
427 | - | git_attr_session *attr_session, | ||
428 | - | git_filter_def *fdef, | ||
429 | - | const git_filter_source *src) | ||
430 | - | { | ||
431 | 56540 | 2 | const char **strs = git__calloc(fdef->nattrs, sizeof(const char *)); | |
432 | 56546 | 3 | uint32_t flags = 0; | |
433 | - | size_t i; | ||
434 | - | int error; | ||
435 | - | |||
436 | 56546 | 3,4 | GIT_ERROR_CHECK_ALLOC(strs); | |
437 | - | |||
438 | 56546 | 5 | if ((src->flags & GIT_FILTER_NO_SYSTEM_ATTRIBUTES) != 0) | |
439 | 44 | 6 | flags |= GIT_ATTR_CHECK_NO_SYSTEM; | |
440 | - | |||
441 | 56546 | 7 | if ((src->flags & GIT_FILTER_ATTRIBUTES_FROM_HEAD) != 0) | |
442 | 26 | 8 | flags |= GIT_ATTR_CHECK_INCLUDE_HEAD; | |
443 | - | |||
444 | 56546 | 9 | error = git_attr_get_many_with_session( | |
445 | 56546 | 9 | strs, repo, attr_session, flags, src->path, fdef->nattrs, fdef->attrs); | |
446 | - | |||
447 | - | /* if no values were found but no matches are needed, it's okay! */ | ||
448 | 56566 | 10,11 | if (error == GIT_ENOTFOUND && !fdef->nmatches) { | |
449 | ##### | 12 | git_error_clear(); | |
450 | ##### | 13 | git__free((void *)strs); | |
451 | ##### | 14 | return 0; | |
452 | - | } | ||
453 | - | |||
454 | 136929 | 15,26-28 | for (i = 0; !error && i < fdef->nattrs; ++i) { | |
455 | 80393 | 16 | const char *want = fdef->attrs[fdef->nattrs + i]; | |
456 | - | git_attr_value_t want_type, found_type; | ||
457 | - | |||
458 | 80393 | 16 | if (!want) | |
459 | 35757 | 17 | continue; | |
460 | - | |||
461 | 44636 | 18 | want_type = git_attr_value(want); | |
462 | 44607 | 19 | found_type = git_attr_value(strs[i]); | |
463 | - | |||
464 | 44606 | 20 | if (want_type != found_type) | |
465 | 44557 | 21 | error = GIT_ENOTFOUND; | |
466 | 49 | 22,23 | else if (want_type == GIT_ATTR_VALUE_STRING && | |
467 | 3 | 23,24 | strcmp(want, strs[i]) && | |
468 | 3 | 24 | strcmp(want, "*")) | |
469 | ##### | 25 | error = GIT_ENOTFOUND; | |
470 | - | } | ||
471 | - | |||
472 | 56536 | 29 | if (error) | |
473 | 44558 | 30 | git__free((void *)strs); | |
474 | - | else | ||
475 | 11978 | 31 | *out = strs; | |
476 | - | |||
477 | 56546 | 32 | return error; | |
478 | - | } | ||
479 | - | |||
480 | 10 | 2 | int git_filter_list_new( | |
481 | - | git_filter_list **out, | ||
482 | - | git_repository *repo, | ||
483 | - | git_filter_mode_t mode, | ||
484 | - | uint32_t flags) | ||
485 | - | { | ||
486 | 10 | 2 | git_filter_source src = { 0 }; | |
487 | 10 | 2 | src.repo = repo; | |
488 | 10 | 2 | src.path = NULL; | |
489 | 10 | 2 | src.mode = mode; | |
490 | 10 | 2 | src.flags = flags; | |
491 | 10 | 2 | return filter_list_new(out, &src); | |
492 | - | } | ||
493 | - | |||
494 | 11929 | 2 | int git_filter_list__load_ext( | |
495 | - | git_filter_list **filters, | ||
496 | - | git_repository *repo, | ||
497 | - | git_blob *blob, /* can be NULL */ | ||
498 | - | const char *path, | ||
499 | - | git_filter_mode_t mode, | ||
500 | - | git_filter_options *filter_opts) | ||
501 | - | { | ||
502 | 11929 | 2 | int error = 0; | |
503 | 11929 | 2 | git_filter_list *fl = NULL; | |
504 | 11929 | 2 | git_filter_source src = { 0 }; | |
505 | - | git_filter_entry *fe; | ||
506 | - | size_t idx; | ||
507 | - | git_filter_def *fdef; | ||
508 | - | |||
509 | 11929 | 2,3 | if (git_rwlock_rdlock(&filter_registry.lock) < 0) { | |
510 | ##### | 4 | git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); | |
511 | ##### | 5 | return -1; | |
512 | - | } | ||
513 | - | |||
514 | 11929 | 6 | src.repo = repo; | |
515 | 11929 | 6 | src.path = path; | |
516 | 11929 | 6 | src.mode = mode; | |
517 | 11929 | 6 | src.flags = filter_opts->flags; | |
518 | - | |||
519 | 11929 | 6 | if (blob) | |
520 | 2747 | 7,8 | git_oid_cpy(&src.oid, git_blob_id(blob)); | |
521 | - | |||
522 | 68471 | 9,47-49 | git_vector_foreach(&filter_registry.filters, idx, fdef) { | |
523 | 56547 | 10 | const char **values = NULL; | |
524 | 56547 | 10 | void *payload = NULL; | |
525 | - | |||
526 | 56547 | 10,11 | if (!fdef || !fdef->filter) | |
527 | 44564 | 12,45 | continue; | |
528 | - | |||
529 | 56545 | 13 | if (fdef->nattrs > 0) { | |
530 | 56543 | 14 | error = filter_list_check_attributes( | |
531 | - | &values, repo, filter_opts->attr_session, fdef, &src); | ||
532 | - | |||
533 | 56540 | 15 | if (error == GIT_ENOTFOUND) { | |
534 | 44562 | 16 | error = 0; | |
535 | 44562 | 16 | continue; | |
536 | 11978 | 17 | } else if (error < 0) | |
537 | ##### | 18,46 | break; | |
538 | - | } | ||
539 | - | |||
540 | 11980 | 19-21 | if (!fdef->initialized && (error = filter_initialize(fdef)) < 0) | |
541 | ##### | 22 | break; | |
542 | - | |||
543 | 11980 | 23 | if (fdef->filter->check) | |
544 | 11932 | 24 | error = fdef->filter->check( | |
545 | - | fdef->filter, &payload, &src, values); | ||
546 | - | |||
547 | 11979 | 25 | git__free((void *)values); | |
548 | - | |||
549 | 11978 | 26 | if (error == GIT_PASSTHROUGH) | |
550 | 9269 | 27 | error = 0; | |
551 | 2709 | 28 | else if (error < 0) | |
552 | ##### | 29 | break; | |
553 | - | else { | ||
554 | 2709 | 30 | if (!fl) { | |
555 | 2670 | 31,32 | if ((error = filter_list_new(&fl, &src)) < 0) | |
556 | ##### | 33 | break; | |
557 | - | |||
558 | 2670 | 34 | fl->temp_buf = filter_opts->temp_buf; | |
559 | - | } | ||
560 | - | |||
561 | 2709 | 35-40 | fe = git_array_alloc(fl->filters); | |
562 | 2709 | 41,42 | GIT_ERROR_CHECK_ALLOC(fe); | |
563 | - | |||
564 | 2709 | 43 | fe->filter = fdef->filter; | |
565 | 2709 | 43 | fe->filter_name = fdef->filter_name; | |
566 | 11978 | 43,44 | fe->payload = payload; | |
567 | - | } | ||
568 | - | } | ||
569 | - | |||
570 | 11924 | 50 | git_rwlock_rdunlock(&filter_registry.lock); | |
571 | - | |||
572 | 11929 | 51,52 | if (error && fl != NULL) { | |
573 | ##### | 53 | git_array_clear(fl->filters); | |
574 | ##### | 54 | git__free(fl); | |
575 | ##### | 55 | fl = NULL; | |
576 | - | } | ||
577 | - | |||
578 | 11929 | 56 | *filters = fl; | |
579 | 11929 | 56 | return error; | |
580 | - | } | ||
581 | - | |||
582 | 9102 | 2 | int git_filter_list_load( | |
583 | - | git_filter_list **filters, | ||
584 | - | git_repository *repo, | ||
585 | - | git_blob *blob, /* can be NULL */ | ||
586 | - | const char *path, | ||
587 | - | git_filter_mode_t mode, | ||
588 | - | uint32_t flags) | ||
589 | - | { | ||
590 | 9102 | 2 | git_filter_options filter_opts = GIT_FILTER_OPTIONS_INIT; | |
591 | - | |||
592 | 9102 | 2 | filter_opts.flags = flags; | |
593 | - | |||
594 | 9102 | 2 | return git_filter_list__load_ext( | |
595 | - | filters, repo, blob, path, mode, &filter_opts); | ||
596 | - | } | ||
597 | - | |||
598 | 9903 | 2 | void git_filter_list_free(git_filter_list *fl) | |
599 | - | { | ||
600 | - | uint32_t i; | ||
601 | - | |||
602 | 9903 | 2 | if (!fl) | |
603 | 9903 | 3,14 | return; | |
604 | - | |||
605 | 5399 | 4,10,11 | for (i = 0; i < git_array_size(fl->filters); ++i) { | |
606 | 2719 | 5-7 | git_filter_entry *fe = git_array_get(fl->filters, i); | |
607 | 2719 | 8 | if (fe->filter->cleanup) | |
608 | 2668 | 9 | fe->filter->cleanup(fe->filter, fe->payload); | |
609 | - | } | ||
610 | - | |||
611 | 2680 | 12 | git_array_clear(fl->filters); | |
612 | 2680 | 13 | git__free(fl); | |
613 | - | } | ||
614 | - | |||
615 | 22 | 2 | int git_filter_list_contains( | |
616 | - | git_filter_list *fl, | ||
617 | - | const char *name) | ||
618 | - | { | ||
619 | - | size_t i; | ||
620 | - | |||
621 | 22 | 2,3 | assert(name); | |
622 | - | |||
623 | 22 | 4 | if (!fl) | |
624 | 4 | 5 | return 0; | |
625 | - | |||
626 | 27 | 6,9,10 | for (i = 0; i < fl->filters.size; i++) { | |
627 | 24 | 7 | if (strcmp(fl->filters.ptr[i].filter_name, name) == 0) | |
628 | 15 | 8 | return 1; | |
629 | - | } | ||
630 | - | |||
631 | 3 | 11 | return 0; | |
632 | - | } | ||
633 | - | |||
634 | 10 | 2 | int git_filter_list_push( | |
635 | - | git_filter_list *fl, git_filter *filter, void *payload) | ||
636 | - | { | ||
637 | 10 | 2 | int error = 0; | |
638 | - | size_t pos; | ||
639 | 10 | 2 | git_filter_def *fdef = NULL; | |
640 | - | git_filter_entry *fe; | ||
641 | - | |||
642 | 10 | 2-4 | assert(fl && filter); | |
643 | - | |||
644 | 10 | 5,6 | if (git_rwlock_rdlock(&filter_registry.lock) < 0) { | |
645 | ##### | 7 | git_error_set(GIT_ERROR_OS, "failed to lock filter registry"); | |
646 | ##### | 8 | return -1; | |
647 | - | } | ||
648 | - | |||
649 | 10 | 9,10 | if (git_vector_search2( | |
650 | - | &pos, &filter_registry.filters, | ||
651 | - | filter_def_filter_key_check, filter) == 0) | ||
652 | 10 | 11 | fdef = git_vector_get(&filter_registry.filters, pos); | |
653 | - | |||
654 | 10 | 12 | git_rwlock_rdunlock(&filter_registry.lock); | |
655 | - | |||
656 | 10 | 13 | if (fdef == NULL) { | |
657 | ##### | 14 | git_error_set(GIT_ERROR_FILTER, "cannot use an unregistered filter"); | |
658 | ##### | 15 | return -1; | |
659 | - | } | ||
660 | - | |||
661 | 10 | 16-18 | if (!fdef->initialized && (error = filter_initialize(fdef)) < 0) | |
662 | ##### | 19 | return error; | |
663 | - | |||
664 | 10 | 20-25 | fe = git_array_alloc(fl->filters); | |
665 | 10 | 26,27 | GIT_ERROR_CHECK_ALLOC(fe); | |
666 | 10 | 28 | fe->filter = filter; | |
667 | 10 | 28 | fe->payload = payload; | |
668 | - | |||
669 | 10 | 28 | return 0; | |
670 | - | } | ||
671 | - | |||
672 | 5 | 2 | size_t git_filter_list_length(const git_filter_list *fl) | |
673 | - | { | ||
674 | 5 | 2 | return fl ? git_array_size(fl->filters) : 0; | |
675 | - | } | ||
676 | - | |||
677 | - | struct buf_stream { | ||
678 | - | git_writestream parent; | ||
679 | - | git_buf *target; | ||
680 | - | bool complete; | ||
681 | - | }; | ||
682 | - | |||
683 | 1697 | 2 | static int buf_stream_write( | |
684 | - | git_writestream *s, const char *buffer, size_t len) | ||
685 | - | { | ||
686 | 1697 | 2 | struct buf_stream *buf_stream = (struct buf_stream *)s; | |
687 | 1697 | 2,3 | assert(buf_stream); | |
688 | - | |||
689 | 1697 | 4,5 | assert(buf_stream->complete == 0); | |
690 | - | |||
691 | 1697 | 6 | return git_buf_put(buf_stream->target, buffer, len); | |
692 | - | } | ||
693 | - | |||
694 | 1968 | 2 | static int buf_stream_close(git_writestream *s) | |
695 | - | { | ||
696 | 1968 | 2 | struct buf_stream *buf_stream = (struct buf_stream *)s; | |
697 | 1968 | 2,3 | assert(buf_stream); | |
698 | - | |||
699 | 1968 | 4,5 | assert(buf_stream->complete == 0); | |
700 | 1968 | 6 | buf_stream->complete = 1; | |
701 | - | |||
702 | 1968 | 6 | return 0; | |
703 | - | } | ||
704 | - | |||
705 | ##### | 2 | static void buf_stream_free(git_writestream *s) | |
706 | - | { | ||
707 | - | GIT_UNUSED(s); | ||
708 | ##### | 2 | } | |
709 | - | |||
710 | 1968 | 2 | static void buf_stream_init(struct buf_stream *writer, git_buf *target) | |
711 | - | { | ||
712 | 1968 | 2 | memset(writer, 0, sizeof(struct buf_stream)); | |
713 | - | |||
714 | 1968 | 2 | writer->parent.write = buf_stream_write; | |
715 | 1968 | 2 | writer->parent.close = buf_stream_close; | |
716 | 1968 | 2 | writer->parent.free = buf_stream_free; | |
717 | 1968 | 2 | writer->target = target; | |
718 | - | |||
719 | 1968 | 2 | git_buf_clear(target); | |
720 | 1968 | 3 | } | |
721 | - | |||
722 | 399 | 2 | int git_filter_list_apply_to_data( | |
723 | - | git_buf *tgt, git_filter_list *filters, git_buf *src) | ||
724 | - | { | ||
725 | - | struct buf_stream writer; | ||
726 | - | int error; | ||
727 | - | |||
728 | 399 | 2 | git_buf_sanitize(tgt); | |
729 | 399 | 3 | git_buf_sanitize(src); | |
730 | - | |||
731 | 399 | 4 | if (!filters) { | |
732 | 84 | 5 | git_buf_attach_notowned(tgt, src->ptr, src->size); | |
733 | 84 | 6 | return 0; | |
734 | - | } | ||
735 | - | |||
736 | 315 | 7 | buf_stream_init(&writer, tgt); | |
737 | - | |||
738 | 315 | 8,9 | if ((error = git_filter_list_stream_data(filters, src, | |
739 | - | &writer.parent)) < 0) | ||
740 | 3 | 10 | return error; | |
741 | - | |||
742 | 312 | 11,12 | assert(writer.complete); | |
743 | 312 | 13 | return error; | |
744 | - | } | ||
745 | - | |||
746 | 1572 | 2 | int git_filter_list_apply_to_file( | |
747 | - | git_buf *out, | ||
748 | - | git_filter_list *filters, | ||
749 | - | git_repository *repo, | ||
750 | - | const char *path) | ||
751 | - | { | ||
752 | - | struct buf_stream writer; | ||
753 | - | int error; | ||
754 | - | |||
755 | 1572 | 2 | buf_stream_init(&writer, out); | |
756 | - | |||
757 | 1572 | 3,4 | if ((error = git_filter_list_stream_file( | |
758 | - | filters, repo, path, &writer.parent)) < 0) | ||
759 | 272 | 5 | return error; | |
760 | - | |||
761 | 1300 | 6,7 | assert(writer.complete); | |
762 | 1300 | 8 | return error; | |
763 | - | } | ||
764 | - | |||
765 | 2796 | 2 | static int buf_from_blob(git_buf *out, git_blob *blob) | |
766 | - | { | ||
767 | 2796 | 2 | git_object_size_t rawsize = git_blob_rawsize(blob); | |
768 | - | |||
769 | 2796 | 3,4 | if (!git__is_sizet(rawsize)) { | |
770 | ##### | 5 | git_error_set(GIT_ERROR_OS, "blob is too large to filter"); | |
771 | ##### | 6 | return -1; | |
772 | - | } | ||
773 | - | |||
774 | 2796 | 7,8 | git_buf_attach_notowned(out, git_blob_rawcontent(blob), (size_t)rawsize); | |
775 | 2796 | 9 | return 0; | |
776 | - | } | ||
777 | - | |||
778 | 81 | 2 | int git_filter_list_apply_to_blob( | |
779 | - | git_buf *out, | ||
780 | - | git_filter_list *filters, | ||
781 | - | git_blob *blob) | ||
782 | - | { | ||
783 | - | struct buf_stream writer; | ||
784 | - | int error; | ||
785 | - | |||
786 | 81 | 2 | buf_stream_init(&writer, out); | |
787 | - | |||
788 | 81 | 3,4 | if ((error = git_filter_list_stream_blob( | |
789 | - | filters, blob, &writer.parent)) < 0) | ||
790 | ##### | 5 | return error; | |
791 | - | |||
792 | 81 | 6,7 | assert(writer.complete); | |
793 | 81 | 8 | return error; | |
794 | - | } | ||
795 | - | |||
796 | - | struct proxy_stream { | ||
797 | - | git_writestream parent; | ||
798 | - | git_filter *filter; | ||
799 | - | const git_filter_source *source; | ||
800 | - | void **payload; | ||
801 | - | git_buf input; | ||
802 | - | git_buf temp_buf; | ||
803 | - | git_buf *output; | ||
804 | - | git_writestream *target; | ||
805 | - | }; | ||
806 | - | |||
807 | 2655 | 2 | static int proxy_stream_write( | |
808 | - | git_writestream *s, const char *buffer, size_t len) | ||
809 | - | { | ||
810 | 2655 | 2 | struct proxy_stream *proxy_stream = (struct proxy_stream *)s; | |
811 | 2655 | 2,3 | assert(proxy_stream); | |
812 | - | |||
813 | 2655 | 4 | return git_buf_put(&proxy_stream->input, buffer, len); | |
814 | - | } | ||
815 | - | |||
816 | 2733 | 2 | static int proxy_stream_close(git_writestream *s) | |
817 | - | { | ||
818 | 2733 | 2 | struct proxy_stream *proxy_stream = (struct proxy_stream *)s; | |
819 | - | git_buf *writebuf; | ||
820 | 2733 | 2 | git_error_state error_state = {0}; | |
821 | - | int error; | ||
822 | - | |||
823 | 2733 | 2,3 | assert(proxy_stream); | |
824 | - | |||
825 | 2733 | 4,4 | error = proxy_stream->filter->apply( | |
826 | - | proxy_stream->filter, | ||
827 | - | proxy_stream->payload, | ||
828 | - | proxy_stream->output, | ||
829 | 2733 | 4 | &proxy_stream->input, | |
830 | - | proxy_stream->source); | ||
831 | - | |||
832 | 2733 | 5 | if (error == GIT_PASSTHROUGH) { | |
833 | 1670 | 6 | writebuf = &proxy_stream->input; | |
834 | 1063 | 7 | } else if (error == 0) { | |
835 | 789 | 8 | git_buf_sanitize(proxy_stream->output); | |
836 | 789 | 9 | writebuf = proxy_stream->output; | |
837 | - | } else { | ||
838 | - | /* close stream before erroring out taking care | ||
839 | - | * to preserve the original error */ | ||
840 | 274 | 10 | git_error_state_capture(&error_state, error); | |
841 | 274 | 11 | proxy_stream->target->close(proxy_stream->target); | |
842 | 274 | 12 | git_error_state_restore(&error_state); | |
843 | 274 | 13 | return error; | |
844 | - | } | ||
845 | - | |||
846 | 2459 | 14,14,15 | if ((error = proxy_stream->target->write( | |
847 | 2459 | 14 | proxy_stream->target, writebuf->ptr, writebuf->size)) == 0) | |
848 | 2459 | 16 | error = proxy_stream->target->close(proxy_stream->target); | |
849 | - | |||
850 | 2459 | 17 | return error; | |
851 | - | } | ||
852 | - | |||
853 | 2733 | 2 | static void proxy_stream_free(git_writestream *s) | |
854 | - | { | ||
855 | 2733 | 2 | struct proxy_stream *proxy_stream = (struct proxy_stream *)s; | |
856 | 2733 | 2,3 | assert(proxy_stream); | |
857 | - | |||
858 | 2733 | 4 | git_buf_dispose(&proxy_stream->input); | |
859 | 2733 | 5 | git_buf_dispose(&proxy_stream->temp_buf); | |
860 | 2733 | 6 | git__free(proxy_stream); | |
861 | 2733 | 7 | } | |
862 | - | |||
863 | 2733 | 2 | static int proxy_stream_init( | |
864 | - | git_writestream **out, | ||
865 | - | git_filter *filter, | ||
866 | - | git_buf *temp_buf, | ||
867 | - | void **payload, | ||
868 | - | const git_filter_source *source, | ||
869 | - | git_writestream *target) | ||
870 | - | { | ||
871 | 2733 | 2 | struct proxy_stream *proxy_stream = git__calloc(1, sizeof(struct proxy_stream)); | |
872 | 2733 | 3,4 | GIT_ERROR_CHECK_ALLOC(proxy_stream); | |
873 | - | |||
874 | 2733 | 5 | proxy_stream->parent.write = proxy_stream_write; | |
875 | 2733 | 5 | proxy_stream->parent.close = proxy_stream_close; | |
876 | 2733 | 5 | proxy_stream->parent.free = proxy_stream_free; | |
877 | 2733 | 5 | proxy_stream->filter = filter; | |
878 | 2733 | 5 | proxy_stream->payload = payload; | |
879 | 2733 | 5 | proxy_stream->source = source; | |
880 | 2733 | 5 | proxy_stream->target = target; | |
881 | 2733 | 5-7 | proxy_stream->output = temp_buf ? temp_buf : &proxy_stream->temp_buf; | |
882 | - | |||
883 | 2733 | 8 | if (temp_buf) | |
884 | 845 | 9 | git_buf_clear(temp_buf); | |
885 | - | |||
886 | 2733 | 10 | *out = (git_writestream *)proxy_stream; | |
887 | 2733 | 10 | return 0; | |
888 | - | } | ||
889 | - | |||
890 | 4684 | 2 | static int stream_list_init( | |
891 | - | git_writestream **out, | ||
892 | - | git_vector *streams, | ||
893 | - | git_filter_list *filters, | ||
894 | - | git_writestream *target) | ||
895 | - | { | ||
896 | 4684 | 2 | git_writestream *last_stream = target; | |
897 | - | size_t i; | ||
898 | 4684 | 2 | int error = 0; | |
899 | - | |||
900 | 4684 | 2 | *out = NULL; | |
901 | - | |||
902 | 4684 | 2 | if (!filters) { | |
903 | 1972 | 3 | *out = target; | |
904 | 1972 | 3 | return 0; | |
905 | - | } | ||
906 | - | |||
907 | - | /* Create filters last to first to get the chaining direction */ | ||
908 | 5447 | 4,20,21 | for (i = 0; i < git_array_size(filters->filters); ++i) { | |
909 | 2736 | 5,8 | size_t filter_idx = (filters->source.mode == GIT_FILTER_TO_WORKTREE) ? | |
910 | 2736 | 5-7 | git_array_size(filters->filters) - 1 - i : i; | |
911 | 2736 | 8-10 | git_filter_entry *fe = git_array_get(filters->filters, filter_idx); | |
912 | - | git_writestream *filter_stream; | ||
913 | - | |||
914 | 2736 | 11-13 | assert(fe->filter->stream || fe->filter->apply); | |
915 | - | |||
916 | - | /* If necessary, create a stream that proxies the traditional | ||
917 | - | * application. | ||
918 | - | */ | ||
919 | 2736 | 14 | if (fe->filter->stream) | |
920 | 3 | 15,15 | error = fe->filter->stream(&filter_stream, fe->filter, | |
921 | 3 | 15 | &fe->payload, &filters->source, last_stream); | |
922 | - | else | ||
923 | - | /* Create a stream that proxies the one-shot apply */ | ||
924 | 2733 | 16 | error = proxy_stream_init(&filter_stream, fe->filter, | |
925 | 2733 | 16 | filters->temp_buf, &fe->payload, &filters->source, | |
926 | - | last_stream); | ||
927 | - | |||
928 | 2736 | 17 | if (error < 0) | |
929 | 1 | 18 | goto out; | |
930 | - | |||
931 | 2735 | 19 | git_vector_insert(streams, filter_stream); | |
932 | 2735 | 20 | last_stream = filter_stream; | |
933 | - | } | ||
934 | - | |||
935 | - | out: | ||
936 | 2712 | 22 | if (error) | |
937 | 1 | 23 | last_stream->close(last_stream); | |
938 | - | else | ||
939 | 2711 | 24 | *out = last_stream; | |
940 | - | |||
941 | 2712 | 25 | return error; | |
942 | - | } | ||
943 | - | |||
944 | 4684 | 2 | static void filter_streams_free(git_vector *streams) | |
945 | - | { | ||
946 | - | git_writestream *stream; | ||
947 | - | size_t i; | ||
948 | - | |||
949 | 7419 | 2,4-6 | git_vector_foreach(streams, i, stream) | |
950 | 2735 | 3 | stream->free(stream); | |
951 | 4684 | 7 | git_vector_free(streams); | |
952 | 4684 | 8 | } | |
953 | - | |||
954 | 1573 | 2 | int git_filter_list_stream_file( | |
955 | - | git_filter_list *filters, | ||
956 | - | git_repository *repo, | ||
957 | - | const char *path, | ||
958 | - | git_writestream *target) | ||
959 | - | { | ||
960 | - | char buf[FILTERIO_BUFSIZE]; | ||
961 | 1573 | 2 | git_buf abspath = GIT_BUF_INIT; | |
962 | 1573 | 2-4 | const char *base = repo ? git_repository_workdir(repo) : NULL; | |
963 | 1573 | 5 | git_vector filter_streams = GIT_VECTOR_INIT; | |
964 | - | git_writestream *stream_start; | ||
965 | - | ssize_t readlen; | ||
966 | 1573 | 5 | int fd = -1, error, initialized = 0; | |
967 | - | |||
968 | 1573 | 5,6 | if ((error = stream_list_init( | |
969 | 1573 | 7,8 | &stream_start, &filter_streams, filters, target)) < 0 || | |
970 | - | (error = git_path_join_unrooted(&abspath, path, base, NULL)) < 0) | ||
971 | - | goto done; | ||
972 | 1573 | 9 | initialized = 1; | |
973 | - | |||
974 | 1573 | 9,10 | if ((fd = git_futils_open_ro(abspath.ptr)) < 0) { | |
975 | ##### | 11 | error = fd; | |
976 | ##### | 11 | goto done; | |
977 | - | } | ||
978 | - | |||
979 | 3068 | 12,16,17 | while ((readlen = p_read(fd, buf, sizeof(buf))) > 0) { | |
980 | 1495 | 13,14 | if ((error = stream_start->write(stream_start, buf, readlen)) < 0) | |
981 | ##### | 15 | goto done; | |
982 | - | } | ||
983 | - | |||
984 | 1573 | 18 | if (readlen < 0) | |
985 | ##### | 19 | error = -1; | |
986 | - | |||
987 | - | done: | ||
988 | 1573 | 20 | if (initialized) | |
989 | 1573 | 21,22 | error |= stream_start->close(stream_start); | |
990 | - | |||
991 | 1573 | 23 | if (fd >= 0) | |
992 | 1573 | 24 | p_close(fd); | |
993 | 1573 | 25 | filter_streams_free(&filter_streams); | |
994 | 1573 | 26 | git_buf_dispose(&abspath); | |
995 | 1573 | 27 | return error; | |
996 | - | } | ||
997 | - | |||
998 | 3111 | 2 | int git_filter_list_stream_data( | |
999 | - | git_filter_list *filters, | ||
1000 | - | git_buf *data, | ||
1001 | - | git_writestream *target) | ||
1002 | - | { | ||
1003 | 3111 | 2 | git_vector filter_streams = GIT_VECTOR_INIT; | |
1004 | - | git_writestream *stream_start; | ||
1005 | 3111 | 2 | int error, initialized = 0; | |
1006 | - | |||
1007 | 3111 | 2 | git_buf_sanitize(data); | |
1008 | - | |||
1009 | 3111 | 3,4 | if ((error = stream_list_init(&stream_start, &filter_streams, filters, target)) < 0) | |
1010 | 1 | 5 | goto out; | |
1011 | 3110 | 6 | initialized = 1; | |
1012 | - | |||
1013 | 3110 | 6,6,7 | if ((error = stream_start->write( | |
1014 | 3110 | 6 | stream_start, data->ptr, data->size)) < 0) | |
1015 | ##### | 8 | goto out; | |
1016 | - | |||
1017 | - | out: | ||
1018 | 3111 | 9 | if (initialized) | |
1019 | 3110 | 10,11 | error |= stream_start->close(stream_start); | |
1020 | - | |||
1021 | 3111 | 12 | filter_streams_free(&filter_streams); | |
1022 | 3111 | 13 | return error; | |
1023 | - | } | ||
1024 | - | |||
1025 | 2796 | 2 | int git_filter_list_stream_blob( | |
1026 | - | git_filter_list *filters, | ||
1027 | - | git_blob *blob, | ||
1028 | - | git_writestream *target) | ||
1029 | - | { | ||
1030 | 2796 | 2 | git_buf in = GIT_BUF_INIT; | |
1031 | - | |||
1032 | 2796 | 2,3 | if (buf_from_blob(&in, blob) < 0) | |
1033 | ##### | 4 | return -1; | |
1034 | - | |||
1035 | 2796 | 5 | if (filters) | |
1036 | 879 | 6,7 | git_oid_cpy(&filters->source.oid, git_blob_id(blob)); | |
1037 | - | |||
1038 | 2796 | 8 | return git_filter_list_stream_data(filters, &in, target); | |
1039 | - | } | ||
1040 | - | |||
1041 | 1 | 2 | int git_filter_init(git_filter *filter, unsigned int version) | |
1042 | - | { | ||
1043 | 1 | 2-4 | GIT_INIT_STRUCTURE_FROM_TEMPLATE(filter, version, git_filter, GIT_FILTER_INIT); | |
1044 | 1 | 5 | return 0; | |
1045 | - | } |