File Coverage

src/Builder.xs
Criterion Covered Total %
statement 137 164 83.5
branch 89 184 48.3
condition n/a
subroutine n/a
pod n/a
total 226 348 64.9


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 7069           static int user_lookup(SV *cache, uid_t uid, gid_t gid, b_string **user, b_string **group) {
26 7069           dSP;
27             I32 retc;
28              
29 7069           ENTER;
30 7069           SAVETMPS;
31              
32             /*
33             * Prepare the stack for $cache->getpwuid()
34             */
35 7069 50         PUSHMARK(SP);
36 7069 50         XPUSHs(cache);
37 7069 50         XPUSHs(sv_2mortal(newSViv(uid)));
38 7069 50         XPUSHs(sv_2mortal(newSViv(gid)));
39 7069           PUTBACK;
40              
41 7069           retc = call_method("lookup", G_ARRAY);
42              
43 7069           SPAGAIN;
44              
45 7069 50         if (retc < 2) {
46 0           goto error_lookup;
47             }
48              
49 7069 50         if (retc == 2) {
50 7069           size_t len = 0;
51             SV *item;
52             char *tmp;
53              
54 7069 50         if ((item = POPs) != NULL && SvOK(item)) {
    50          
    0          
    0          
55 7069 50         tmp = SvPV(item, len);
56              
57 7069 50         if ((*group = b_string_new_len(tmp, len)) == NULL) {
58 0           goto error_string_new_group;
59             }
60             }
61              
62 7069 50         if ((item = POPs) != NULL && SvOK(item)) {
    50          
    0          
    0          
63 7069 50         tmp = SvPV(item, len);
64              
65 7069 50         if ((*user = b_string_new_len(tmp, len)) == NULL) {
66 7069           goto error_string_new_user;
67             }
68             }
69             }
70              
71 7069           PUTBACK;
72              
73 7069 50         FREETMPS;
74 7069           LEAVE;
75              
76 7069           return 0;
77              
78             error_string_new_user:
79 0           b_string_free(*group);
80              
81             error_string_new_group:
82              
83             error_lookup:
84 0           PUTBACK;
85              
86 0 0         FREETMPS;
87 0           LEAVE;
88              
89 0           return -1;
90             }
91              
92 404           static b_string *hardlink_lookup(SV *cache, dev_t dev, ino_t ino, b_string *path) {
93 404           dSP;
94             I32 retc;
95              
96 404           size_t len = 0;
97             SV *item;
98             char *tmp;
99              
100 404           ENTER;
101 404           SAVETMPS;
102              
103             /*
104             * Prepare the stack for $cache->lookup()
105             */
106 404 50         PUSHMARK(SP);
107 404 50         XPUSHs(cache);
108 404 50         XPUSHs(sv_2mortal(newSViv(dev)));
109 404 50         XPUSHs(sv_2mortal(newSViv(ino)));
110 404 50         XPUSHs(sv_2mortal(newSVpv(path->str, path->len)));
111 404           PUTBACK;
112              
113 404           path = NULL;
114 404           retc = call_method("lookup", G_ARRAY);
115              
116 404           SPAGAIN;
117              
118 404 100         if (retc != 1) {
119 202           goto leave;
120             }
121              
122 202 50         if ((item = POPs) != NULL && SvOK(item)) {
    50          
    0          
    0          
123 202 50         tmp = SvPV(item, len);
124              
125 202 50         if ((path = b_string_new_len(tmp, len)) == NULL) {
126 0           goto leave;
127             }
128             }
129              
130             leave:
131 404           PUTBACK;
132              
133 404 50         FREETMPS;
134 404           LEAVE;
135              
136 404           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 6588           static int find_flags(enum b_builder_options options) {
146 6588           int flags = 0;
147              
148 6588 50         if (options & B_BUILDER_FOLLOW_SYMLINKS) {
149 0           flags |= B_FIND_FOLLOW_SYMLINKS;
150             }
151              
152 6588 100         if (options & B_BUILDER_IGNORE_SOCKETS) {
153 1           flags |= B_FIND_IGNORE_SOCKETS;
154             }
155              
156 6588           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 92           SV *cache = NULL;
169             I32 i, retc;
170 92           enum b_builder_options options = B_BUILDER_NONE;
171 92           size_t block_factor = B_BUFFER_DEFAULT_FACTOR;
172              
173 92 50         if ((items - 1) % 2 != 0) {
174 0           croak("Uneven number of arguments passed; must be in 'key' => 'value' format");
175             }
176              
177 178 100         for (i=1; i
178 86 50         char *key = SvPV_nolen(ST(i));
179 86           SV *value = ST(i+1);
180              
181 86 100         if (strcmp(key, "quiet") == 0 && SvIV(value)) options |= B_BUILDER_QUIET;
    50          
    50          
182 86 50         if (strcmp(key, "ignore_errors") == 0 && SvIV(value)) options |= B_BUILDER_IGNORE_ERRORS;
    0          
    0          
183 86 50         if (strcmp(key, "follow_symlinks") == 0 && SvIV(value)) options |= B_BUILDER_FOLLOW_SYMLINKS;
    0          
    0          
184 86 100         if (strcmp(key, "preserve_hardlinks") == 0 && SvIV(value)) options |= B_BUILDER_PRESERVE_HARDLINKS;
    50          
    50          
185 86 100         if (strcmp(key, "gnu_extensions") == 0 && SvIV(value)) options |= B_BUILDER_GNU_EXTENSIONS;
    50          
    50          
186 86 100         if (strcmp(key, "posix_extensions") == 0 && SvIV(value)) options |= B_BUILDER_PAX_EXTENSIONS;
    50          
    50          
187 86 100         if (strcmp(key, "ignore_sockets") == 0 && SvIV(value)) options |= B_BUILDER_IGNORE_SOCKETS;
    50          
    50          
188 86 50         if (strcmp(key, "block_factor") == 0 && SvIV(value)) block_factor = SvIV(value);
    0          
    0          
    0          
189             }
190              
191 92 50         if ((builder = b_builder_new(block_factor)) == NULL) {
192 0           croak("%s: %s", "b_builder_new()", strerror(errno));
193             }
194              
195 92           b_builder_set_options(builder, options);
196              
197 92           err = b_builder_get_error(builder);
198              
199 92 100         if (!(options & B_BUILDER_QUIET)) {
200 66           b_error_set_callback(err, B_ERROR_CALLBACK(builder_warn));
201             }
202              
203             /*
204             * Call Archive::Tar::Builder::UserCache->new()
205             */
206 92           ENTER;
207 92           SAVETMPS;
208              
209 92 50         PUSHMARK(SP);
210 92 50         XPUSHs(sv_2mortal(newSVpvf("Archive::Tar::Builder::UserCache")));
211 92           PUTBACK;
212              
213 92           retc = call_method("new", G_SCALAR);
214              
215 92           SPAGAIN;
216              
217 92 50         if (retc == 1) {
218 92           cache = POPs;
219 92           SvREFCNT_inc(cache);
220             }
221              
222 92           PUTBACK;
223 92 50         FREETMPS;
224 92           LEAVE;
225              
226 92           b_builder_set_user_lookup(builder, B_USER_LOOKUP(user_lookup), cache);
227              
228 92 100         if (builder->options & B_BUILDER_PRESERVE_HARDLINKS) {
229             /*
230             * Call Archive::Tar::Builder::HardlinkCache->new()
231             */
232 10           ENTER;
233 10           SAVETMPS;
234              
235 10 50         PUSHMARK(SP);
236 10 50         XPUSHs(sv_2mortal(newSVpvf("Archive::Tar::Builder::HardlinkCache")));
237 10           PUTBACK;
238              
239 10           retc = call_method("new", G_SCALAR);
240              
241 10           SPAGAIN;
242              
243 10 50         if (retc == 1) {
244 10           cache = POPs;
245 10           SvREFCNT_inc(cache);
246             }
247              
248 10           PUTBACK;
249 10 50         FREETMPS;
250 10           LEAVE;
251              
252 10           b_builder_set_hardlink_cache(builder, B_HARDLINK_LOOKUP(hardlink_lookup), cache);
253             }
254              
255 92           RETVAL = builder;
256              
257             OUTPUT:
258             RETVAL
259              
260             void
261             builder_DESTROY(builder)
262             Archive::Tar::Builder builder
263              
264             CODE:
265 92           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 51           b_buffer *buf = b_builder_get_buffer(builder);;
325              
326 51           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 6602           enum b_builder_options options = b_builder_get_options(builder);
334 6602           b_buffer *buf = b_builder_get_buffer(builder);
335              
336             size_t i;
337              
338 6602 50         if ((items - 1) % 2 != 0) {
339 0           croak("Uneven number of arguments passed; must be in 'path' => 'member_name' format");
340             }
341              
342 6602 100         if (b_buffer_get_fd(buf) == 0) {
343 14           croak("No file handle set");
344             }
345              
346 13168 100         for (i=1; i
347 6588           int flags = find_flags(options);
348              
349 6588 50         b_string *path = b_string_new(SvPV_nolen(ST(i)));
350 6588 50         b_string *member_name = b_string_new(SvPV_nolen(ST(i+1)));
351              
352 6588 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 6580           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           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           RETVAL = ret;
418              
419             OUTPUT:
420             RETVAL