File Coverage

src/b_builder.c
Criterion Covered Total %
statement 178 241 73.8
branch 93 158 58.8
condition n/a
subroutine n/a
pod n/a
total 271 399 67.9


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4             #include
5             #ifdef __GLIBC__
6             #include
7             #endif /* __GLIBC__ */
8             #include
9             #include
10             #include "match_engine.h"
11             #include "b_util.h"
12             #include "b_file.h"
13             #include "b_path.h"
14             #include "b_string.h"
15             #include "b_header.h"
16             #include "b_stack.h"
17             #include "b_buffer.h"
18             #include "b_builder.h"
19              
20             struct path_data {
21             b_string * prefix;
22             b_string * suffix;
23             int truncated;
24             };
25              
26             /*
27             * Given the value of st->st_mode & S_IFMT, return the corresponding tar header
28             * type identifier character. The hardlink type is not accounted for here as
29             * it is supplied below by header_for_file() when hardlinks are detected.
30             */
31 6670           static inline char inode_linktype(struct stat *st) {
32             /*
33             * The values in this jump table are sorted roughly in order of commonality
34             * of each inode type.
35             */
36 6670           switch (st->st_mode & S_IFMT) {
37 6583           case S_IFREG: return '0';
38 87           case S_IFDIR: return '5';
39 0           case S_IFLNK: return '2';
40 0           case S_IFIFO: return '6';
41 0           case S_IFCHR: return '3';
42 0           case S_IFBLK: return '4';
43             }
44              
45 0           return '0';
46             }
47              
48 91           b_builder *b_builder_new(size_t block_factor) {
49             b_builder *builder;
50              
51 91 50         if ((builder = malloc(sizeof(*builder))) == NULL) {
52 0           goto error_malloc;
53             }
54              
55 91 50         if ((builder->buf = b_buffer_new(block_factor? block_factor: B_BUFFER_DEFAULT_FACTOR)) == NULL) {
    50          
56 0           goto error_buffer_new;
57             }
58              
59 91 50         if ((builder->err = b_error_new()) == NULL) {
60 0           goto error_error_new;
61             }
62              
63 91           builder->total = 0;
64 91           builder->match = NULL;
65 91           builder->options = B_BUILDER_NONE;
66 91           builder->user_lookup = NULL;
67 91           builder->user_cache = NULL;
68 91           builder->hardlink_lookup = NULL;
69 91           builder->hardlink_cache = NULL;
70 91           builder->data = NULL;
71              
72 91           return builder;
73              
74             error_error_new:
75 0           b_buffer_destroy(builder->buf);
76              
77             error_buffer_new:
78 0           free(builder);
79              
80             error_malloc:
81 0           return NULL;
82             }
83              
84 6628           enum b_builder_options b_builder_get_options(b_builder *builder) {
85 6628 50         if (builder == NULL) return B_BUILDER_NONE;
86              
87 6628           return builder->options;
88             }
89              
90 91           void b_builder_set_options(b_builder *builder, enum b_builder_options options) {
91 91           builder->options = options;
92 91           }
93              
94 6713           b_error *b_builder_get_error(b_builder *builder) {
95 6713 50         if (builder == NULL) return NULL;
96              
97 6713           return builder->err;
98             }
99              
100 6678           b_buffer *b_builder_get_buffer(b_builder *builder) {
101 6678 50         if (builder == NULL) return NULL;
102              
103 6678           return builder->buf;
104             }
105              
106 0           void b_builder_set_data(b_builder *builder, void *data) {
107 0 0         if (builder == NULL) return;
108              
109 0           builder->data = data;
110             }
111              
112             /*
113             * The caller should assume responsibility for initializing and destroying the
114             * user lookup service as appropriate.
115             */
116 91           void b_builder_set_user_lookup(b_builder *builder, b_user_lookup service, void *ctx) {
117 91           builder->user_lookup = service;
118 91           builder->user_cache = ctx;
119 91           }
120              
121 9           void b_builder_set_hardlink_cache(b_builder *builder, b_hardlink_lookup lookup, void *cache) {
122 9           builder->hardlink_lookup = lookup;
123 9           builder->hardlink_cache = cache;
124 9           }
125              
126 203           int b_builder_is_excluded(b_builder *builder, const char *path) {
127 203           return lafe_excluded(builder->match, path);
128             }
129              
130 14           int b_builder_include(b_builder *builder, const char *pattern) {
131 14           return lafe_include(&builder->match, pattern);
132             }
133              
134 21           int b_builder_include_from_file(b_builder *builder, const char *file) {
135 21           return lafe_include_from_file(&builder->match, file, 0);
136             }
137              
138 14           int b_builder_exclude(b_builder *builder, const char *pattern) {
139 14           return lafe_exclude(&builder->match, pattern);
140             }
141              
142 21           int b_builder_exclude_from_file(b_builder *builder, const char *file) {
143 21           return lafe_exclude_from_file(&builder->match, file);
144             }
145              
146 5834           static int encode_longlink(b_builder *builder, b_header_block *block, b_string *path, int type, off_t *wrlen) {
147 5834           b_buffer *buf = builder->buf;
148 5834           b_error *err = builder->err;
149              
150 5834 50         if (path == NULL) {
151 0           return 0;
152             }
153              
154 5834 50         if (b_header_encode_longlink_block(block, path, type) == NULL) {
155 0           return -1;
156             }
157              
158 5834           builder->total += *wrlen;
159              
160 5834 50         if ((*wrlen = b_file_write_path_blocks(buf, path)) < 0) {
161 0 0         if (err) {
162 0           b_error_set(err, B_ERROR_FATAL, errno, "Cannot write long filename header", path);
163             }
164              
165 0           return -1;
166             }
167              
168 5834           builder->total += *wrlen;
169              
170 5834           return 0;
171             }
172              
173 6670           static struct path_data *path_split(b_string *path, struct stat *st) {
174             struct path_data *data;
175              
176             b_stack *prefix_items, *suffix_items;
177 6670           size_t prefix_size = 0, suffix_size = 0;
178 6670           int add_to_prefix = 0;
179              
180             b_stack *parts;
181             b_string *item;
182              
183 6670 50         if ((data = malloc(sizeof(*data))) == NULL) {
184 0           goto error_data_malloc;
185             }
186              
187 6670 50         if ((parts = b_path_new(path)) == NULL) {
188 0           goto error_path_new;
189             }
190              
191 6670 50         if ((prefix_items = b_stack_new(0)) == NULL) {
192 0           goto error_prefix_items;
193             }
194              
195 6670 50         if ((suffix_items = b_stack_new(0)) == NULL) {
196 0           goto error_suffix_items;
197             }
198              
199 6670           b_stack_set_destructor(parts, B_STACK_DESTRUCTOR(b_string_free));
200 6670           b_stack_set_destructor(prefix_items, B_STACK_DESTRUCTOR(b_string_free));
201 6670           b_stack_set_destructor(suffix_items, B_STACK_DESTRUCTOR(b_string_free));
202              
203 6670           data->truncated = 0;
204              
205 6670 50         if (b_stack_count(parts) == 0) {
206 0           goto error_empty_stack;
207             }
208              
209             /*
210             * Strip the leading / from the path, if present.
211             */
212 6670 100         if (b_string_len(b_stack_item_at(parts, 0)) == 0) {
213 14           b_string *leading = b_stack_shift(parts);
214              
215 14           b_string_free(leading);
216             }
217              
218 13458 100         while ((item = b_stack_pop(parts)) != NULL) {
219 6788 100         if (suffix_size && suffix_size + item->len >= B_HEADER_SUFFIX_SIZE) {
    100          
220 7           add_to_prefix = 1;
221             }
222              
223             /* directory will have a / added to the end */
224 6788 100         if ( ( (st->st_mode & S_IFMT) == S_IFDIR ) && ( suffix_size + item->len + 1 >= B_HEADER_SUFFIX_SIZE ) ) {
    100          
225 7           add_to_prefix = 1;
226             }
227              
228 6788 100         if (add_to_prefix) {
229 7 50         if (prefix_size) prefix_size++; /* Add 1 to make room for path separator */
230 7           prefix_size += item->len;
231             } else {
232 6781 100         if (suffix_size) suffix_size++; /* ^-- Ditto */
233 6781           suffix_size += item->len;
234             }
235              
236 6788 100         if (b_stack_push(add_to_prefix? prefix_items: suffix_items, item) == NULL) {
    50          
237 0           goto error_item;
238             }
239             }
240              
241 6670           b_stack_destroy(parts);
242              
243             /*
244             * Assemble the prefix and suffix strings.
245             */
246 6670 50         if ((data->prefix = b_string_join("/", b_stack_reverse(prefix_items))) == NULL) {
247 0           goto error_prefix;
248             }
249              
250 6670 50         if ((data->suffix = b_string_join("/", b_stack_reverse(suffix_items))) == NULL) {
251 0           goto error_suffix;
252             }
253              
254             /*
255             * If the item we are dealing with is a directory, then always consider the
256             * trailing slash in its representation.
257             */
258 6670 100         if ((st->st_mode & S_IFMT) == S_IFDIR) {
259 87           suffix_size++;
260 87           b_string_append_str(data->suffix, "/");
261             }
262              
263             /*
264             * If either of these cases are true, then in normal circumstances the path
265             * prefix or suffix MUST be truncated to fix into a tar header's corresponding
266             * fields.
267             *
268             * Note that this calculation MUST happen after any other path suffix or prefix
269             * size calculations are complete.
270             */
271 6670 100         if (suffix_size > B_HEADER_SUFFIX_SIZE || prefix_size > B_HEADER_PREFIX_SIZE) {
    50          
272 5842           data->truncated = 1;
273             }
274              
275 6670           b_stack_destroy(prefix_items);
276 6670           b_stack_destroy(suffix_items);
277              
278 6670           return data;
279              
280             error_suffix:
281 0           b_string_free(data->prefix);
282              
283             error_prefix:
284             error_item:
285             error_empty_stack:
286 0           b_stack_destroy(suffix_items);
287              
288             error_suffix_items:
289 0           b_stack_destroy(prefix_items);
290              
291             error_prefix_items:
292 0           b_stack_destroy(parts);
293              
294             error_path_new:
295 0           free(data);
296              
297             error_data_malloc:
298 0           return NULL;
299             }
300              
301 6670           static inline int is_hardlink(struct stat *st) {
302 6670 100         return (st->st_mode & S_IFMT) == S_IFREG && st->st_nlink > 1;
    100          
303             }
304              
305 6670           static b_header *header_for_file(b_builder *builder, b_string *path, b_string *member_name, struct stat *st) {
306             b_header *ret;
307              
308             struct path_data *path_data;
309              
310 6670 50         if ((ret = malloc(sizeof(*ret))) == NULL) {
311 0           goto error_malloc;
312             }
313              
314 6670 50         if ((path_data = path_split(member_name, st)) == NULL) {
315 0           goto error_path_data;
316             }
317              
318 6670           ret->truncated = path_data->truncated;
319 6670           ret->prefix = path_data->prefix;
320 6670           ret->suffix = path_data->suffix;
321 6670           ret->mode = st->st_mode;
322 6670           ret->uid = st->st_uid;
323 6670           ret->gid = st->st_gid;
324 6670 100         ret->size = (st->st_mode & S_IFMT) == S_IFREG? st->st_size: 0;
325 6670           ret->mtime = st->st_mtime;
326 6670           ret->major = major(st->st_dev);
327 6670           ret->minor = minor(st->st_dev);
328 6670           ret->linktype = inode_linktype(st);
329 6670           ret->linkdest = NULL;
330 6670           ret->user = NULL;
331 6670           ret->group = NULL;
332              
333 6670           ret->truncated_link = 0;
334              
335 6670 50         if ((st->st_mode & S_IFMT) == S_IFLNK) {
336 0 0         if ((ret->linkdest = b_readlink(path, st)) == NULL) {
337 0           goto error_readlink;
338             }
339 6670 100         } else if (is_hardlink(st) && builder->hardlink_lookup) {
    50          
340             b_string *linkdest;
341              
342 6 100         if (linkdest = builder->hardlink_lookup(builder->hardlink_cache, st->st_dev, st->st_ino, member_name)) {
343 3           ret->linktype = '0' + S_IF_HARDLINK;
344 3           ret->linkdest = linkdest;
345             }
346             }
347              
348 6670 100         if (ret->linkdest && b_string_len(ret->linkdest) > B_HEADER_LINKDEST_SIZE) {
    50          
349 0           ret->truncated_link = 1;
350             }
351              
352             /*
353             * free() path_data, but keep its prefix and suffix with us, as we will free() those
354             * ourselves b_header_destroy()
355             */
356 6670           free(path_data);
357              
358 6670           return ret;
359              
360             error_readlink:
361 0           b_string_free(path_data->prefix);
362 0           b_string_free(path_data->suffix);
363              
364 0           free(path_data);
365              
366             error_path_data:
367 0           free(ret);
368              
369             error_malloc:
370 0           return NULL;
371             }
372              
373 6670           int b_builder_write_file(b_builder *builder, b_string *path, b_string *member_name, struct stat *st, int fd) {
374 6670           b_buffer *buf = builder->buf;
375 6670           b_error *err = builder->err;
376              
377 6670           off_t wrlen = 0;
378              
379             b_header *header;
380             b_header_block *block;
381              
382 6670 50         if (buf == NULL) {
383 0           errno = EINVAL;
384 0           return -1;
385             }
386              
387 6670 50         if (err) {
388 6670           b_error_clear(err);
389             }
390              
391 6670 50         if ((header = header_for_file(builder, path, member_name, st)) == NULL) {
392 0 0         if (err) {
393 0           b_error_set(err, B_ERROR_FATAL, errno, "Cannot build header for file", path);
394             }
395              
396 0           goto error_header_for_file;
397             }
398              
399             /*
400             * If there is a user lookup service installed, then resolve the user and
401             * group of the current filesystem object and supply them within the
402             * b_header object.
403             */
404 6670 50         if (builder->user_lookup != NULL) {
405 6670           b_string *user = NULL, *group = NULL;
406              
407 6670 50         if (builder->user_lookup(builder->user_cache, st->st_uid, st->st_gid, &user, &group) < 0) {
408 0 0         if (err) {
409 0           b_error_set(err, B_ERROR_WARN, errno, "Cannot lookup user and group for file", path);
410             }
411              
412 0           goto error_lookup;
413             }
414              
415 6670 50         if (b_header_set_usernames(header, user, group) < 0) {
416 6670           goto error_lookup;
417             }
418             }
419              
420             /*
421             * If the header is marked to contain truncated paths, then write a GNU
422             * longlink header, followed by the blocks containing the path name to be
423             * assigned.
424             */
425 6670 100         if (header->truncated || header->truncated_link) {
    50          
426             b_string *longlink_path;
427              
428             /*
429             * GNU extensions must be explicitly enabled to encode GNU LongLink
430             * headers.
431             */
432 5842 100         if (!(builder->options & B_BUILDER_EXTENSIONS_MASK)) {
433 4           errno = ENAMETOOLONG;
434              
435 4 50         if (err) {
436 4           b_error_set(err, B_ERROR_WARN, errno, "File name too long", member_name);
437             }
438              
439 4           goto error_path_toolong;
440             }
441              
442 5838 50         if ((block = b_buffer_get_block(buf, B_HEADER_SIZE, &wrlen)) == NULL) {
443 0           goto error_get_header_block;
444             }
445              
446 5838 50         if ((longlink_path = b_string_dup(member_name)) == NULL) {
447 0           goto error_longlink_path_dup;
448             }
449              
450 5838 50         if ((st->st_mode & S_IFMT) == S_IFDIR) {
451 0 0         if ((b_string_append_str(longlink_path, "/")) == NULL) {
452 0           goto error_longlink_path_append;
453             }
454             }
455              
456 5838 100         if (builder->options & B_BUILDER_GNU_EXTENSIONS) {
457 5834 50         if (header->truncated && encode_longlink(builder, block, longlink_path, B_HEADER_LONGLINK_TYPE, &wrlen) < 0) {
    50          
458 0           goto error_header_encode;
459             }
460              
461 5834 50         if (header->truncated_link && encode_longlink(builder, block, header->linkdest, B_HEADER_LONGDEST_TYPE, &wrlen) < 0) {
    0          
462 0           goto error_header_encode;
463             }
464 4 50         } else if (builder->options & B_BUILDER_PAX_EXTENSIONS) {
465 4 50         if (b_header_encode_pax_block(block, header, longlink_path) == NULL) {
466 0           goto error_header_encode;
467             }
468              
469 4           builder->total += wrlen;
470              
471 4 50         if ((wrlen = b_file_write_pax_path_blocks(buf, longlink_path, header->linkdest)) < 0) {
472 0 0         if (err) {
473 0           b_error_set(err, B_ERROR_FATAL, errno, "Cannot write long filename header", member_name);
474             }
475              
476 0           goto error_write;
477             }
478              
479 4           builder->total += wrlen;
480             }
481             }
482              
483             /*
484             * Then, of course, encode and write the real file header block.
485             */
486 6666 50         if ((block = b_buffer_get_block(buf, B_HEADER_SIZE, &wrlen)) == NULL) {
487 0           goto error_write;
488             }
489              
490 6666 50         if (b_header_encode_block(block, header) == NULL) {
491 0           goto error_header_encode;
492             }
493              
494 6666           builder->total += wrlen;
495              
496             /*
497             * Finally, end by writing the file contents.
498             */
499 6666 100         if (B_HEADER_IS_IFREG(header) && fd > 0) {
    50          
500 6576 100         if ((wrlen = b_file_write_contents(buf, fd, header->size)) < 0) {
501 4 50         if (err) {
502 4           b_error_set(err, B_ERROR_WARN, errno, "Cannot write file to archive", path);
503             }
504              
505 4           goto error_write;
506             }
507              
508 6572           builder->total += wrlen;
509             }
510              
511 6662           b_header_destroy(header);
512              
513 6662           return 1;
514              
515             error_write:
516             error_longlink_path_append:
517             error_longlink_path_dup:
518             error_get_header_block:
519             error_path_toolong:
520             error_header_encode:
521             error_lookup:
522 8           b_header_destroy(header);
523              
524             error_header_for_file:
525 6670           return -1;
526             }
527              
528 91           void b_builder_destroy(b_builder *builder) {
529 91 50         if (builder == NULL) return;
530              
531 91 50         if (builder->buf) {
532 91           b_buffer_destroy(builder->buf);
533 91           builder->buf = NULL;
534             }
535              
536 91 50         if (builder->err) {
537 91           b_error_destroy(builder->err);
538 91           builder->err = NULL;
539             }
540              
541 91           builder->options = B_BUILDER_NONE;
542 91           builder->total = 0;
543 91           builder->data = NULL;
544              
545 91           lafe_cleanup_exclusions(&builder->match);
546              
547 91           builder->match = NULL;
548              
549 91           free(builder);
550             }