File Coverage

src/Builder.xs
Criterion Covered Total %
statement 122 150 81.3
branch 83 180 46.1
condition n/a
subroutine n/a
pod n/a
total 205 330 62.1


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