File Coverage

src/Builder.xs
Criterion Covered Total %
statement 136 168 80.9
branch 79 148 53.3
condition n/a
subroutine n/a
pod n/a
total 215 316 68.0


line stmt bran cond sub pod time code
1             /*
2             * Copyright (c) 2019, cPanel, L.L.C.
3             * All rights reserved.
4             * http://cpanel.net/
5             *
6             * This is free software; you can redistribute it and/or modify it under the
7             * same terms as Perl itself. See the Perl manual section 'perlartistic' for
8             * further information.
9             */
10              
11             #include "EXTERN.h"
12             #include "perl.h"
13             #include "XSUB.h"
14             #include "ppport.h"
15              
16             #include
17             #include
18             #include "b_string.h"
19             #include "b_find.h"
20             #include "b_error.h"
21             #include "b_builder.h"
22              
23             typedef b_builder * Archive__Tar__Builder;
24              
25 6670           static int user_lookup(SV *cache, uid_t uid, gid_t gid, b_string **user, b_string **group) {
26 6670           dSP;
27             I32 retc;
28              
29 6670           ENTER;
30 6670           SAVETMPS;
31              
32             /*
33             * Prepare the stack for $cache->getpwuid()
34             */
35 6670 50         PUSHMARK(SP);
36 6670 50         XPUSHs(cache);
37 6670 50         XPUSHs(sv_2mortal(newSViv(uid)));
38 6670 50         XPUSHs(sv_2mortal(newSViv(gid)));
39 6670           PUTBACK;
40              
41 6670           retc = call_method("lookup", G_ARRAY);
42              
43 6670           SPAGAIN;
44              
45 6670 50         if (retc < 2) {
46 0           goto error_lookup;
47             }
48              
49 6670 50         if (retc == 2) {
50 6670           size_t len = 0;
51             SV *item;
52             char *tmp;
53              
54 6670 50         if ((item = POPs) != NULL && SvOK(item)) {
    50          
55 6670           tmp = SvPV(item, len);
56              
57 6670 50         if ((*group = b_string_new_len(tmp, len)) == NULL) {
58 0           goto error_string_new_group;
59             }
60             }
61              
62 6670 50         if ((item = POPs) != NULL && SvOK(item)) {
    50          
63 6670           tmp = SvPV(item, len);
64              
65 6670 50         if ((*user = b_string_new_len(tmp, len)) == NULL) {
66 0           goto error_string_new_user;
67             }
68             }
69             }
70              
71 6670           PUTBACK;
72              
73 6670 50         FREETMPS;
74 6670           LEAVE;
75              
76 6670           return 0;
77              
78 0           error_string_new_user:
79 0           b_string_free(*group);
80              
81 0           error_string_new_group:
82              
83 0           error_lookup:
84 0           PUTBACK;
85              
86 0 0         FREETMPS;
87 0           LEAVE;
88              
89 0           return -1;
90             }
91              
92 6           static b_string *hardlink_lookup(SV *cache, dev_t dev, ino_t ino, b_string *path) {
93 6           dSP;
94             I32 retc;
95              
96 6           size_t len = 0;
97             SV *item;
98             char *tmp;
99              
100 6           ENTER;
101 6           SAVETMPS;
102              
103             /*
104             * Prepare the stack for $cache->lookup()
105             */
106 6 50         PUSHMARK(SP);
107 6 50         XPUSHs(cache);
108 6 50         XPUSHs(sv_2mortal(newSViv(dev)));
109 6 50         XPUSHs(sv_2mortal(newSViv(ino)));
110 6 50         XPUSHs(sv_2mortal(newSVpv(path->str, path->len)));
111 6           PUTBACK;
112              
113 6           path = NULL;
114 6           retc = call_method("lookup", G_ARRAY);
115              
116 6           SPAGAIN;
117              
118 6 100         if (retc != 1) {
119 3           goto leave;
120             }
121              
122 3 50         if ((item = POPs) != NULL && SvOK(item)) {
    50          
123 3           tmp = SvPV(item, len);
124              
125 3 50         if ((path = b_string_new_len(tmp, len)) == NULL) {
126 0           goto leave;
127             }
128             }
129              
130 3           leave:
131 6           PUTBACK;
132              
133 6 50         FREETMPS;
134 6           LEAVE;
135              
136 6           return path;
137             }
138              
139 0           static void builder_warn(b_error *err) {
140 0 0         if (err == NULL) return;
141              
142 0           warn("%s: %s: %s", b_error_path(err)->str, b_error_message(err)->str, strerror(b_error_errno(err)));
143             }
144              
145 6587           static int find_flags(enum b_builder_options options) {
146 6587           int flags = 0;
147              
148 6587 50         if (options & B_BUILDER_FOLLOW_SYMLINKS) {
149 0           flags |= B_FIND_FOLLOW_SYMLINKS;
150             }
151              
152 6587 50         if (options & B_BUILDER_IGNORE_SOCKETS) {
153 0           flags |= B_FIND_IGNORE_SOCKETS;
154             }
155              
156 6587           return flags;
157             }
158              
159             MODULE = Archive::Tar::Builder PACKAGE = Archive::Tar::Builder PREFIX = builder_
160              
161             Archive::Tar::Builder
162             builder_new(klass, ...)
163             char *klass
164              
165             CODE:
166             b_builder *builder;
167             b_error *err;
168 91           SV *cache = NULL;
169             I32 i, retc;
170 91           enum b_builder_options options = B_BUILDER_NONE;
171 91           size_t block_factor = B_BUFFER_DEFAULT_FACTOR;
172              
173 91 50         if ((items - 1) % 2 != 0) {
174 0           croak("Uneven number of arguments passed; must be in 'key' => 'value' format");
175             }
176              
177 174 100         for (i=1; i
178 83           char *key = SvPV_nolen(ST(i));
179 83           SV *value = ST(i+1);
180              
181 83 100         if (strcmp(key, "quiet") == 0 && SvIV(value)) options |= B_BUILDER_QUIET;
    50          
182 83 50         if (strcmp(key, "ignore_errors") == 0 && SvIV(value)) options |= B_BUILDER_IGNORE_ERRORS;
    0          
183 83 50         if (strcmp(key, "follow_symlinks") == 0 && SvIV(value)) options |= B_BUILDER_FOLLOW_SYMLINKS;
    0          
184 83 100         if (strcmp(key, "preserve_hardlinks") == 0 && SvIV(value)) options |= B_BUILDER_PRESERVE_HARDLINKS;
    50          
185 83 100         if (strcmp(key, "gnu_extensions") == 0 && SvIV(value)) options |= B_BUILDER_GNU_EXTENSIONS;
    50          
186 83 100         if (strcmp(key, "posix_extensions") == 0 && SvIV(value)) options |= B_BUILDER_PAX_EXTENSIONS;
    50          
187 83 50         if (strcmp(key, "ignore_sockets") == 0 && SvIV(value)) options |= B_BUILDER_IGNORE_SOCKETS;
    0          
188 83 50         if (strcmp(key, "block_factor") == 0 && SvIV(value)) block_factor = SvIV(value);
    0          
189             }
190              
191 91 50         if ((builder = b_builder_new(block_factor)) == NULL) {
192 0           croak("%s: %s", "b_builder_new()", strerror(errno));
193             }
194              
195 91           b_builder_set_options(builder, options);
196              
197 91           err = b_builder_get_error(builder);
198              
199 91 100         if (!(options & B_BUILDER_QUIET)) {
200 65           b_error_set_callback(err, B_ERROR_CALLBACK(builder_warn));
201             }
202              
203             /*
204             * Call Archive::Tar::Builder::UserCache->new()
205             */
206 91           ENTER;
207 91           SAVETMPS;
208              
209 91 50         PUSHMARK(SP);
210 91 50         XPUSHs(sv_2mortal(newSVpvf("Archive::Tar::Builder::UserCache")));
211 91           PUTBACK;
212              
213 91           retc = call_method("new", G_SCALAR);
214              
215 91           SPAGAIN;
216              
217 91 50         if (retc == 1) {
218 91           cache = POPs;
219 91           SvREFCNT_inc(cache);
220             }
221              
222 91           PUTBACK;
223 91 50         FREETMPS;
224 91           LEAVE;
225              
226 91           b_builder_set_user_lookup(builder, B_USER_LOOKUP(user_lookup), cache);
227              
228 91 100         if (builder->options & B_BUILDER_PRESERVE_HARDLINKS) {
229             /*
230             * Call Archive::Tar::Builder::HardlinkCache->new()
231             */
232 9           ENTER;
233 9           SAVETMPS;
234              
235 9 50         PUSHMARK(SP);
236 9 50         XPUSHs(sv_2mortal(newSVpvf("Archive::Tar::Builder::HardlinkCache")));
237 9           PUTBACK;
238              
239 9           retc = call_method("new", G_SCALAR);
240              
241 9           SPAGAIN;
242              
243 9 50         if (retc == 1) {
244 9           cache = POPs;
245 9           SvREFCNT_inc(cache);
246             }
247              
248 9           PUTBACK;
249 9 50         FREETMPS;
250 9           LEAVE;
251              
252 9           b_builder_set_hardlink_cache(builder, B_HARDLINK_LOOKUP(hardlink_lookup), cache);
253             }
254              
255 91           RETVAL = builder;
256              
257             OUTPUT:
258             RETVAL
259              
260             void
261             builder_DESTROY(builder)
262             Archive::Tar::Builder builder
263              
264             CODE:
265 91           b_builder_destroy(builder);
266              
267             void
268             builder_include(builder, pattern)
269             Archive::Tar::Builder builder
270             const char *pattern
271              
272             CODE:
273 14 50         if (b_builder_include(builder, pattern) < 0) {
274 0           croak("Cananot add inclusion pattern '%s' to list of inclusions: %s", pattern, strerror(errno));
275             }
276              
277             void
278             builder_include_from_file(builder, file)
279             Archive::Tar::Builder builder
280             const char *file
281              
282             CODE:
283 21 100         if (b_builder_include_from_file(builder, file) < 0) {
284 7           croak("Cannot add items to inclusion list from file %s: %s", file, strerror(errno));
285             }
286              
287             void
288             builder_exclude(builder, pattern)
289             Archive::Tar::Builder builder
290             const char *pattern
291              
292             CODE:
293 14 50         if (b_builder_exclude(builder, pattern) < 0) {
294 0           croak("Cannot add exclusion pattern '%s' to list of exclusions: %s", pattern, strerror(errno));
295             }
296              
297             void
298             builder_exclude_from_file(builder, file)
299             Archive::Tar::Builder builder
300             const char *file
301              
302             CODE:
303 21 100         if (b_builder_exclude_from_file(builder, file) < 0) {
304 7           croak("Cannot add items to exclusion list from file %s: %s", file, strerror(errno));
305             }
306              
307             int
308             builder_is_excluded(builder, path)
309             Archive::Tar::Builder builder
310             const char *path
311              
312             CODE:
313 203           RETVAL = b_builder_is_excluded(builder, path);
314              
315             OUTPUT:
316             RETVAL
317              
318             void
319             builder_set_handle(builder, fh)
320             Archive::Tar::Builder builder
321             PerlIO *fh
322              
323             CODE:
324 50           b_buffer *buf = b_builder_get_buffer(builder);;
325              
326 50           b_buffer_set_fd(buf, PerlIO_fileno(fh));
327              
328             size_t
329             builder_archive_as(builder, ...)
330             Archive::Tar::Builder builder
331              
332             CODE:
333 6601           enum b_builder_options options = b_builder_get_options(builder);
334 6601           b_buffer *buf = b_builder_get_buffer(builder);
335              
336             size_t i;
337              
338 6601 50         if ((items - 1) % 2 != 0) {
339 0           croak("Uneven number of arguments passed; must be in 'path' => 'member_name' format");
340             }
341              
342 6601 100         if (b_buffer_get_fd(buf) == 0) {
343 14           croak("No file handle set");
344             }
345              
346 13166 100         for (i=1; i
347 6587           int flags = find_flags(options);
348              
349 6587           b_string *path = b_string_new(SvPV_nolen(ST(i)));
350 6587           b_string *member_name = b_string_new(SvPV_nolen(ST(i+1)));
351              
352 6587 100         if (b_find(builder, path, member_name, B_FIND_CALLBACK(b_builder_write_file), flags) < 0) {
353 8           b_error * err = b_builder_get_error(builder);
354 8           b_string * error_path = b_error_path(err);
355            
356 8 50         if (error_path == NULL) {
357 0           error_path = path;
358             }
359              
360 8           croak("%s: %s: %s\n", "b_find()", error_path->str, strerror(errno));
361             }
362             }
363              
364 6579 100         RETVAL = builder->total;
365              
366             OUTPUT:
367             RETVAL
368              
369             ssize_t
370             builder_flush(builder)
371             Archive::Tar::Builder builder
372              
373             CODE:
374             ssize_t ret;
375              
376 0           b_buffer *buf = b_builder_get_buffer(builder);
377              
378 0 0         if (b_buffer_get_fd(buf) == 0) {
379 0           croak("No file handle set");
380             }
381              
382 0 0         if ((ret = b_buffer_flush(buf)) < 0) {
383 0           croak("%s: %s", "b_buffer_flush()", strerror(errno));
384             }
385              
386 0 0         RETVAL = ret;
387              
388             OUTPUT:
389             RETVAL
390              
391             ssize_t
392             builder_finish(builder)
393             Archive::Tar::Builder builder
394              
395             CODE:
396             ssize_t ret;
397              
398 27           b_buffer *buf = b_builder_get_buffer(builder);
399 27           b_error *err = b_builder_get_error(builder);
400              
401 27           enum b_builder_options options = b_builder_get_options(builder);
402              
403 27 50         if (b_buffer_get_fd(buf) == 0) {
404 0           croak("No file handle set");
405             }
406              
407 27 50         if ((ret = b_buffer_flush(buf)) < 0) {
408 0           croak("%s: %s", "b_buffer_flush()", strerror(errno));
409             }
410              
411 27 50         if (b_error_warn(err) && !(options & B_BUILDER_IGNORE_ERRORS)) {
    0          
412 0           croak("Delayed nonzero exit status");
413             }
414              
415 27           b_error_reset(err);
416              
417 27 100         RETVAL = ret;
418              
419             OUTPUT:
420             RETVAL