1 /*-
2 * Copyright (c) 2003-2007 Tim Kientzle
3 * Copyright (c) 2011-2012 Michihiro NAKAJIMA
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "archive_platform.h"
28
29 #ifdef HAVE_ERRNO_H
30 #include <errno.h>
31 #endif
32 #include <stdio.h>
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
39
40 #include "archive.h"
41 #include "archive_entry.h"
42 #include "archive_entry_locale.h"
43 #include "archive_private.h"
44 #include "archive_write_private.h"
45 #include "archive_write_set_format_private.h"
46
47 struct v7tar {
48 uint64_t entry_bytes_remaining;
49 uint64_t entry_padding;
50
51 struct archive_string_conv *opt_sconv;
52 struct archive_string_conv *sconv_default;
53 int init_default_conversion;
54 };
55
56 /*
57 * Define structure of POSIX 'v7tar' tar header.
58 */
59 #define V7TAR_name_offset 0
60 #define V7TAR_name_size 100
61 #define V7TAR_mode_offset 100
62 #define V7TAR_mode_size 6
63 #define V7TAR_mode_max_size 8
64 #define V7TAR_uid_offset 108
65 #define V7TAR_uid_size 6
66 #define V7TAR_uid_max_size 8
67 #define V7TAR_gid_offset 116
68 #define V7TAR_gid_size 6
69 #define V7TAR_gid_max_size 8
70 #define V7TAR_size_offset 124
71 #define V7TAR_size_size 11
72 #define V7TAR_size_max_size 12
73 #define V7TAR_mtime_offset 136
74 #define V7TAR_mtime_size 11
75 #define V7TAR_mtime_max_size 12
76 #define V7TAR_checksum_offset 148
77 #define V7TAR_checksum_size 8
78 #define V7TAR_typeflag_offset 156
79 #define V7TAR_typeflag_size 1
80 #define V7TAR_linkname_offset 157
81 #define V7TAR_linkname_size 100
82 #define V7TAR_padding_offset 257
83 #define V7TAR_padding_size 255
84
85 /*
86 * A filled-in copy of the header for initialization.
87 */
88 static const char template_header[] = {
89 /* name: 100 bytes */
90 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
91 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
92 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
93 0,0,0,0,
94 /* Mode, space-null termination: 8 bytes */
95 '0','0','0','0','0','0', ' ','\0',
96 /* uid, space-null termination: 8 bytes */
97 '0','0','0','0','0','0', ' ','\0',
98 /* gid, space-null termination: 8 bytes */
99 '0','0','0','0','0','0', ' ','\0',
100 /* size, space termination: 12 bytes */
101 '0','0','0','0','0','0','0','0','0','0','0', ' ',
102 /* mtime, space termination: 12 bytes */
103 '0','0','0','0','0','0','0','0','0','0','0', ' ',
104 /* Initial checksum value: 8 spaces */
105 ' ',' ',' ',' ',' ',' ',' ',' ',
106 /* Typeflag: 1 byte */
107 0,
108 /* Linkname: 100 bytes */
109 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
110 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
111 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
112 0,0,0,0,
113 /* Padding: 255 bytes */
114 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
115 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
116 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
117 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
118 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
119 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
120 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
121 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0
122 };
123
124 static ssize_t archive_write_v7tar_data(struct archive_write *a, const void *buff,
125 size_t s);
126 static int archive_write_v7tar_free(struct archive_write *);
127 static int archive_write_v7tar_close(struct archive_write *);
128 static int archive_write_v7tar_finish_entry(struct archive_write *);
129 static int archive_write_v7tar_header(struct archive_write *,
130 struct archive_entry *entry);
131 static int archive_write_v7tar_options(struct archive_write *,
132 const char *, const char *);
133 static int format_256(int64_t, char *, int);
134 static int format_number(int64_t, char *, int size, int max, int strict);
135 static int format_octal(int64_t, char *, int);
136 static int format_header_v7tar(struct archive_write *, char h[512],
137 struct archive_entry *, int, struct archive_string_conv *);
138
139 /*
140 * Set output format to 'v7tar' format.
141 */
142 int
archive_write_set_format_v7tar(struct archive * _a)143 archive_write_set_format_v7tar(struct archive *_a)
144 {
145 struct archive_write *a = (struct archive_write *)_a;
146 struct v7tar *v7tar;
147
148 archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
149 ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar");
150
151 /* If someone else was already registered, unregister them. */
152 if (a->format_free != NULL)
153 (a->format_free)(a);
154
155 /* Basic internal sanity test. */
156 if (sizeof(template_header) != 512) {
157 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
158 "Internal: template_header wrong size: %zu should be 512",
159 sizeof(template_header));
160 return (ARCHIVE_FATAL);
161 }
162
163 v7tar = calloc(1, sizeof(*v7tar));
164 if (v7tar == NULL) {
165 archive_set_error(&a->archive, ENOMEM,
166 "Can't allocate v7tar data");
167 return (ARCHIVE_FATAL);
168 }
169 a->format_data = v7tar;
170 a->format_name = "tar (non-POSIX)";
171 a->format_options = archive_write_v7tar_options;
172 a->format_write_header = archive_write_v7tar_header;
173 a->format_write_data = archive_write_v7tar_data;
174 a->format_close = archive_write_v7tar_close;
175 a->format_free = archive_write_v7tar_free;
176 a->format_finish_entry = archive_write_v7tar_finish_entry;
177 a->archive.archive_format = ARCHIVE_FORMAT_TAR;
178 a->archive.archive_format_name = "tar (non-POSIX)";
179 return (ARCHIVE_OK);
180 }
181
182 static int
archive_write_v7tar_options(struct archive_write * a,const char * key,const char * val)183 archive_write_v7tar_options(struct archive_write *a, const char *key,
184 const char *val)
185 {
186 struct v7tar *v7tar = (struct v7tar *)a->format_data;
187 int ret = ARCHIVE_FAILED;
188
189 if (strcmp(key, "hdrcharset") == 0) {
190 if (val == NULL || val[0] == 0)
191 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
192 "%s: hdrcharset option needs a character-set name",
193 a->format_name);
194 else {
195 v7tar->opt_sconv = archive_string_conversion_to_charset(
196 &a->archive, val, 0);
197 if (v7tar->opt_sconv != NULL)
198 ret = ARCHIVE_OK;
199 else
200 ret = ARCHIVE_FATAL;
201 }
202 return (ret);
203 }
204
205 /* Note: The "warn" return is just to inform the options
206 * supervisor that we didn't handle it. It will generate
207 * a suitable error if no one used this option. */
208 return (ARCHIVE_WARN);
209 }
210
211 static int
archive_write_v7tar_header(struct archive_write * a,struct archive_entry * entry)212 archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
213 {
214 char buff[512];
215 int ret, ret2;
216 struct v7tar *v7tar;
217 struct archive_entry *entry_main;
218 struct archive_string_conv *sconv;
219
220 v7tar = (struct v7tar *)a->format_data;
221
222 /* Setup default string conversion. */
223 if (v7tar->opt_sconv == NULL) {
224 if (!v7tar->init_default_conversion) {
225 v7tar->sconv_default =
226 archive_string_default_conversion_for_write(
227 &(a->archive));
228 v7tar->init_default_conversion = 1;
229 }
230 sconv = v7tar->sconv_default;
231 } else
232 sconv = v7tar->opt_sconv;
233
234 /* Sanity check. */
235 if (archive_entry_pathname(entry) == NULL) {
236 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
237 "Can't record entry in tar file without pathname");
238 return (ARCHIVE_FAILED);
239 }
240
241 /* Only regular files (not hardlinks) have data. */
242 if (archive_entry_hardlink(entry) != NULL ||
243 archive_entry_symlink(entry) != NULL ||
244 archive_entry_filetype(entry) != AE_IFREG)
245 archive_entry_set_size(entry, 0);
246
247 if (AE_IFDIR == archive_entry_filetype(entry)) {
248 const char *p;
249 size_t path_length;
250 /*
251 * Ensure a trailing '/'. Modify the entry so
252 * the client sees the change.
253 */
254 #if defined(_WIN32) && !defined(__CYGWIN__)
255 const wchar_t *wp;
256
257 wp = archive_entry_pathname_w(entry);
258 if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
259 struct archive_wstring ws;
260
261 archive_string_init(&ws);
262 path_length = wcslen(wp);
263 if (archive_wstring_ensure(&ws,
264 path_length + 2) == NULL) {
265 archive_set_error(&a->archive, ENOMEM,
266 "Can't allocate v7tar data");
267 archive_wstring_free(&ws);
268 return(ARCHIVE_FATAL);
269 }
270 /* Should we keep '\' ? */
271 if (wp[path_length -1] == L'\\')
272 path_length--;
273 archive_wstrncpy(&ws, wp, path_length);
274 archive_wstrappend_wchar(&ws, L'/');
275 archive_entry_copy_pathname_w(entry, ws.s);
276 archive_wstring_free(&ws);
277 p = NULL;
278 } else
279 #endif
280 p = archive_entry_pathname(entry);
281 /*
282 * On Windows, this is a backup operation just in
283 * case getting WCS failed. On POSIX, this is a
284 * normal operation.
285 */
286 if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
287 struct archive_string as;
288
289 archive_string_init(&as);
290 path_length = strlen(p);
291 if (archive_string_ensure(&as,
292 path_length + 2) == NULL) {
293 archive_set_error(&a->archive, ENOMEM,
294 "Can't allocate v7tar data");
295 archive_string_free(&as);
296 return(ARCHIVE_FATAL);
297 }
298 #if defined(_WIN32) && !defined(__CYGWIN__)
299 /* NOTE: This might break the pathname
300 * if the current code page is CP932 and
301 * the pathname includes a character '\'
302 * as a part of its multibyte pathname. */
303 if (p[strlen(p) -1] == '\\')
304 path_length--;
305 else
306 #endif
307 archive_strncpy(&as, p, path_length);
308 archive_strappend_char(&as, '/');
309 archive_entry_copy_pathname(entry, as.s);
310 archive_string_free(&as);
311 }
312 }
313
314 #if defined(_WIN32) && !defined(__CYGWIN__)
315 /* Make sure the path separators in pathname, hardlink and symlink
316 * are all slash '/', not the Windows path separator '\'. */
317 entry_main = __la_win_entry_in_posix_pathseparator(entry);
318 if (entry_main == NULL) {
319 archive_set_error(&a->archive, ENOMEM,
320 "Can't allocate v7tar data");
321 return(ARCHIVE_FATAL);
322 }
323 if (entry != entry_main)
324 entry = entry_main;
325 else
326 entry_main = NULL;
327 #else
328 entry_main = NULL;
329 #endif
330 ret = format_header_v7tar(a, buff, entry, 1, sconv);
331 if (ret < ARCHIVE_WARN) {
332 archive_entry_free(entry_main);
333 return (ret);
334 }
335 ret2 = __archive_write_output(a, buff, 512);
336 if (ret2 < ARCHIVE_WARN) {
337 archive_entry_free(entry_main);
338 return (ret2);
339 }
340 if (ret2 < ret)
341 ret = ret2;
342
343 v7tar->entry_bytes_remaining = archive_entry_size(entry);
344 v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
345 archive_entry_free(entry_main);
346 return (ret);
347 }
348
349 /*
350 * Format a basic 512-byte "v7tar" header.
351 *
352 * Returns -1 if format failed (due to field overflow).
353 * Note that this always formats as much of the header as possible.
354 * If "strict" is set to zero, it will extend numeric fields as
355 * necessary (overwriting terminators or using base-256 extensions).
356 *
357 */
358 static int
format_header_v7tar(struct archive_write * a,char h[512],struct archive_entry * entry,int strict,struct archive_string_conv * sconv)359 format_header_v7tar(struct archive_write *a, char h[512],
360 struct archive_entry *entry, int strict,
361 struct archive_string_conv *sconv)
362 {
363 unsigned int checksum;
364 int i, r, ret;
365 size_t copy_length;
366 const char *p, *pp;
367 int mytartype;
368
369 ret = 0;
370 mytartype = -1;
371 /*
372 * The "template header" already includes the "v7tar"
373 * signature, various end-of-field markers and other required
374 * elements.
375 */
376 memcpy(h, &template_header, 512);
377
378 /*
379 * Because the block is already null-filled, and strings
380 * are allowed to exactly fill their destination (without null),
381 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
382 */
383 r = archive_entry_pathname_l(entry, &pp, ©_length, sconv);
384 if (r != 0) {
385 if (errno == ENOMEM) {
386 archive_set_error(&a->archive, ENOMEM,
387 "Can't allocate memory for Pathname");
388 return (ARCHIVE_FATAL);
389 }
390 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
391 "Can't translate pathname '%s' to %s",
392 pp, archive_string_conversion_charset_name(sconv));
393 ret = ARCHIVE_WARN;
394 }
395 if (strict && copy_length < V7TAR_name_size)
396 memcpy(h + V7TAR_name_offset, pp, copy_length);
397 else if (!strict && copy_length <= V7TAR_name_size)
398 memcpy(h + V7TAR_name_offset, pp, copy_length);
399 else {
400 /* Prefix is too long. */
401 archive_set_error(&a->archive, ENAMETOOLONG,
402 "Pathname too long");
403 ret = ARCHIVE_FAILED;
404 }
405
406 r = archive_entry_hardlink_l(entry, &p, ©_length, sconv);
407 if (r != 0) {
408 if (errno == ENOMEM) {
409 archive_set_error(&a->archive, ENOMEM,
410 "Can't allocate memory for Linkname");
411 return (ARCHIVE_FATAL);
412 }
413 archive_set_error(&a->archive,
414 ARCHIVE_ERRNO_FILE_FORMAT,
415 "Can't translate linkname '%s' to %s",
416 p, archive_string_conversion_charset_name(sconv));
417 ret = ARCHIVE_WARN;
418 }
419 if (copy_length > 0)
420 mytartype = '1';
421 else {
422 r = archive_entry_symlink_l(entry, &p, ©_length, sconv);
423 if (r != 0) {
424 if (errno == ENOMEM) {
425 archive_set_error(&a->archive, ENOMEM,
426 "Can't allocate memory for Linkname");
427 return (ARCHIVE_FATAL);
428 }
429 archive_set_error(&a->archive,
430 ARCHIVE_ERRNO_FILE_FORMAT,
431 "Can't translate linkname '%s' to %s",
432 p, archive_string_conversion_charset_name(sconv));
433 ret = ARCHIVE_WARN;
434 }
435 }
436 if (copy_length > 0) {
437 if (copy_length >= V7TAR_linkname_size) {
438 archive_set_error(&a->archive, ENAMETOOLONG,
439 "Link contents too long");
440 ret = ARCHIVE_FAILED;
441 copy_length = V7TAR_linkname_size;
442 }
443 memcpy(h + V7TAR_linkname_offset, p, copy_length);
444 }
445
446 if (format_number(archive_entry_mode(entry) & 07777,
447 h + V7TAR_mode_offset, V7TAR_mode_size,
448 V7TAR_mode_max_size, strict)) {
449 archive_set_error(&a->archive, ERANGE,
450 "Numeric mode too large");
451 ret = ARCHIVE_FAILED;
452 }
453
454 if (format_number(archive_entry_uid(entry),
455 h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
456 archive_set_error(&a->archive, ERANGE,
457 "Numeric user ID too large");
458 ret = ARCHIVE_FAILED;
459 }
460
461 if (format_number(archive_entry_gid(entry),
462 h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
463 archive_set_error(&a->archive, ERANGE,
464 "Numeric group ID too large");
465 ret = ARCHIVE_FAILED;
466 }
467
468 if (format_number(archive_entry_size(entry),
469 h + V7TAR_size_offset, V7TAR_size_size,
470 V7TAR_size_max_size, strict)) {
471 archive_set_error(&a->archive, ERANGE,
472 "File size out of range");
473 ret = ARCHIVE_FAILED;
474 }
475
476 if (format_number(archive_entry_mtime(entry),
477 h + V7TAR_mtime_offset, V7TAR_mtime_size,
478 V7TAR_mtime_max_size, strict)) {
479 archive_set_error(&a->archive, ERANGE,
480 "File modification time too large");
481 ret = ARCHIVE_FAILED;
482 }
483
484 if (mytartype >= 0) {
485 h[V7TAR_typeflag_offset] = mytartype;
486 } else {
487 switch (archive_entry_filetype(entry)) {
488 case AE_IFREG: case AE_IFDIR:
489 break;
490 case AE_IFLNK:
491 h[V7TAR_typeflag_offset] = '2';
492 break;
493 default:
494 /* AE_IFBLK, AE_IFCHR, AE_IFIFO, AE_IFSOCK
495 * and unknown */
496 __archive_write_entry_filetype_unsupported(
497 &a->archive, entry, "v7tar");
498 ret = ARCHIVE_FAILED;
499 }
500 }
501
502 checksum = 0;
503 for (i = 0; i < 512; i++)
504 checksum += 255 & (unsigned int)h[i];
505 format_octal(checksum, h + V7TAR_checksum_offset, 6);
506 /* Can't be pre-set in the template. */
507 h[V7TAR_checksum_offset + 6] = '\0';
508 return (ret);
509 }
510
511 /*
512 * Format a number into a field, with some intelligence.
513 */
514 static int
format_number(int64_t v,char * p,int s,int maxsize,int strict)515 format_number(int64_t v, char *p, int s, int maxsize, int strict)
516 {
517 int64_t limit;
518
519 limit = ((int64_t)1 << (s*3));
520
521 /* "Strict" only permits octal values with proper termination. */
522 if (strict)
523 return (format_octal(v, p, s));
524
525 /*
526 * In non-strict mode, we allow the number to overwrite one or
527 * more bytes of the field termination. Even old tar
528 * implementations should be able to handle this with no
529 * problem.
530 */
531 if (v >= 0) {
532 while (s <= maxsize) {
533 if (v < limit)
534 return (format_octal(v, p, s));
535 s++;
536 limit <<= 3;
537 }
538 }
539
540 /* Base-256 can handle any number, positive or negative. */
541 return (format_256(v, p, maxsize));
542 }
543
544 /*
545 * Format a number into the specified field using base-256.
546 */
547 static int
format_256(int64_t v,char * p,int s)548 format_256(int64_t v, char *p, int s)
549 {
550 p += s;
551 while (s-- > 0) {
552 *--p = (char)(v & 0xff);
553 v >>= 8;
554 }
555 *p |= 0x80; /* Set the base-256 marker bit. */
556 return (0);
557 }
558
559 /*
560 * Format a number into the specified field.
561 */
562 static int
format_octal(int64_t v,char * p,int s)563 format_octal(int64_t v, char *p, int s)
564 {
565 int len;
566
567 len = s;
568
569 /* Octal values can't be negative, so use 0. */
570 if (v < 0) {
571 while (len-- > 0)
572 *p++ = '0';
573 return (-1);
574 }
575
576 p += s; /* Start at the end and work backwards. */
577 while (s-- > 0) {
578 *--p = (char)('0' + (v & 7));
579 v >>= 3;
580 }
581
582 if (v == 0)
583 return (0);
584
585 /* If it overflowed, fill field with max value. */
586 while (len-- > 0)
587 *p++ = '7';
588
589 return (-1);
590 }
591
592 static int
archive_write_v7tar_close(struct archive_write * a)593 archive_write_v7tar_close(struct archive_write *a)
594 {
595 return (__archive_write_nulls(a, 512*2));
596 }
597
598 static int
archive_write_v7tar_free(struct archive_write * a)599 archive_write_v7tar_free(struct archive_write *a)
600 {
601 struct v7tar *v7tar;
602
603 v7tar = (struct v7tar *)a->format_data;
604 free(v7tar);
605 a->format_data = NULL;
606 return (ARCHIVE_OK);
607 }
608
609 static int
archive_write_v7tar_finish_entry(struct archive_write * a)610 archive_write_v7tar_finish_entry(struct archive_write *a)
611 {
612 struct v7tar *v7tar;
613 int ret;
614
615 v7tar = (struct v7tar *)a->format_data;
616 ret = __archive_write_nulls(a,
617 (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
618 v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
619 return (ret);
620 }
621
622 static ssize_t
archive_write_v7tar_data(struct archive_write * a,const void * buff,size_t s)623 archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
624 {
625 struct v7tar *v7tar;
626 int ret;
627
628 v7tar = (struct v7tar *)a->format_data;
629 if (s > v7tar->entry_bytes_remaining)
630 s = (size_t)v7tar->entry_bytes_remaining;
631 ret = __archive_write_output(a, buff, s);
632 v7tar->entry_bytes_remaining -= s;
633 if (ret != ARCHIVE_OK)
634 return (ret);
635 return (s);
636 }
637