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 #if defined(_WIN32) && !defined(__CYGWIN__)
237 && archive_entry_pathname_w(entry) == NULL
238 #endif
239 ) {
240 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
241 "Can't record entry in tar file without pathname");
242 return (ARCHIVE_FAILED);
243 }
244
245 /* Only regular files (not hardlinks) have data. */
246 if (archive_entry_hardlink(entry) != NULL ||
247 archive_entry_symlink(entry) != NULL ||
248 archive_entry_filetype(entry) != AE_IFREG)
249 archive_entry_set_size(entry, 0);
250
251 if (AE_IFDIR == archive_entry_filetype(entry)) {
252 const char *p;
253 size_t path_length;
254 /*
255 * Ensure a trailing '/'. Modify the entry so
256 * the client sees the change.
257 */
258 #if defined(_WIN32) && !defined(__CYGWIN__)
259 const wchar_t *wp;
260
261 wp = archive_entry_pathname_w(entry);
262 if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
263 struct archive_wstring ws;
264
265 archive_string_init(&ws);
266 path_length = wcslen(wp);
267 if (archive_wstring_ensure(&ws,
268 path_length + 2) == NULL) {
269 archive_set_error(&a->archive, ENOMEM,
270 "Can't allocate v7tar data");
271 archive_wstring_free(&ws);
272 return(ARCHIVE_FATAL);
273 }
274 /* Should we keep '\' ? */
275 if (wp[path_length -1] == L'\\')
276 path_length--;
277 archive_wstrncpy(&ws, wp, path_length);
278 archive_wstrappend_wchar(&ws, L'/');
279 archive_entry_copy_pathname_w(entry, ws.s);
280 archive_wstring_free(&ws);
281 p = NULL;
282 } else
283 #endif
284 p = archive_entry_pathname(entry);
285 /*
286 * On Windows, this is a backup operation just in
287 * case getting WCS failed. On POSIX, this is a
288 * normal operation.
289 */
290 if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
291 struct archive_string as;
292
293 archive_string_init(&as);
294 path_length = strlen(p);
295 if (archive_string_ensure(&as,
296 path_length + 2) == NULL) {
297 archive_set_error(&a->archive, ENOMEM,
298 "Can't allocate v7tar data");
299 archive_string_free(&as);
300 return(ARCHIVE_FATAL);
301 }
302 #if defined(_WIN32) && !defined(__CYGWIN__)
303 /* NOTE: This might break the pathname
304 * if the current code page is CP932 and
305 * the pathname includes a character '\'
306 * as a part of its multibyte pathname. */
307 if (p[strlen(p) -1] == '\\')
308 path_length--;
309 else
310 #endif
311 archive_strncpy(&as, p, path_length);
312 archive_strappend_char(&as, '/');
313 archive_entry_copy_pathname(entry, as.s);
314 archive_string_free(&as);
315 }
316 }
317
318 #if defined(_WIN32) && !defined(__CYGWIN__)
319 /* Make sure the path separators in pathname, hardlink and symlink
320 * are all slash '/', not the Windows path separator '\'. */
321 entry_main = __la_win_entry_in_posix_pathseparator(entry);
322 if (entry_main == NULL) {
323 archive_set_error(&a->archive, ENOMEM,
324 "Can't allocate v7tar data");
325 return(ARCHIVE_FATAL);
326 }
327 if (entry != entry_main)
328 entry = entry_main;
329 else
330 entry_main = NULL;
331 #else
332 entry_main = NULL;
333 #endif
334 ret = format_header_v7tar(a, buff, entry, 1, sconv);
335 if (ret < ARCHIVE_WARN) {
336 archive_entry_free(entry_main);
337 return (ret);
338 }
339 ret2 = __archive_write_output(a, buff, 512);
340 if (ret2 < ARCHIVE_WARN) {
341 archive_entry_free(entry_main);
342 return (ret2);
343 }
344 if (ret2 < ret)
345 ret = ret2;
346
347 v7tar->entry_bytes_remaining = archive_entry_size(entry);
348 v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
349 archive_entry_free(entry_main);
350 return (ret);
351 }
352
353 /*
354 * Format a basic 512-byte "v7tar" header.
355 *
356 * Returns -1 if format failed (due to field overflow).
357 * Note that this always formats as much of the header as possible.
358 * If "strict" is set to zero, it will extend numeric fields as
359 * necessary (overwriting terminators or using base-256 extensions).
360 *
361 */
362 static int
format_header_v7tar(struct archive_write * a,char h[512],struct archive_entry * entry,int strict,struct archive_string_conv * sconv)363 format_header_v7tar(struct archive_write *a, char h[512],
364 struct archive_entry *entry, int strict,
365 struct archive_string_conv *sconv)
366 {
367 unsigned int checksum;
368 int i, r, ret;
369 size_t copy_length;
370 const char *p, *pp;
371 int mytartype;
372
373 ret = 0;
374 mytartype = -1;
375 /*
376 * The "template header" already includes the "v7tar"
377 * signature, various end-of-field markers and other required
378 * elements.
379 */
380 memcpy(h, &template_header, 512);
381
382 /*
383 * Because the block is already null-filled, and strings
384 * are allowed to exactly fill their destination (without null),
385 * I use memcpy(dest, src, strlen()) here a lot to copy strings.
386 */
387 r = archive_entry_pathname_l(entry, &pp, ©_length, sconv);
388 if (r != 0) {
389 const char* p_mbs;
390 if (errno == ENOMEM) {
391 archive_set_error(&a->archive, ENOMEM,
392 "Can't allocate memory for Pathname");
393 return (ARCHIVE_FATAL);
394 }
395 p_mbs = archive_entry_pathname(entry);
396 if (p_mbs) {
397 /* We have a wrongly-encoded MBS pathname.
398 * Warn and use it. */
399 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
400 "Can't translate pathname '%s' to %s", p_mbs,
401 archive_string_conversion_charset_name(sconv));
402 ret = ARCHIVE_WARN;
403 } else {
404 /* We have no MBS pathname. Fail. */
405 archive_set_error(&a->archive,
406 ARCHIVE_ERRNO_FILE_FORMAT,
407 "Can't translate pathname to %s",
408 archive_string_conversion_charset_name(sconv));
409 return ARCHIVE_FAILED;
410 }
411 }
412 if (strict && copy_length < V7TAR_name_size)
413 memcpy(h + V7TAR_name_offset, pp, copy_length);
414 else if (!strict && copy_length <= V7TAR_name_size)
415 memcpy(h + V7TAR_name_offset, pp, copy_length);
416 else {
417 /* Prefix is too long. */
418 archive_set_error(&a->archive, ENAMETOOLONG,
419 "Pathname too long");
420 ret = ARCHIVE_FAILED;
421 }
422
423 r = archive_entry_hardlink_l(entry, &p, ©_length, sconv);
424 if (r != 0) {
425 if (errno == ENOMEM) {
426 archive_set_error(&a->archive, ENOMEM,
427 "Can't allocate memory for Linkname");
428 return (ARCHIVE_FATAL);
429 }
430 archive_set_error(&a->archive,
431 ARCHIVE_ERRNO_FILE_FORMAT,
432 "Can't translate linkname '%s' to %s",
433 p, archive_string_conversion_charset_name(sconv));
434 ret = ARCHIVE_WARN;
435 }
436 if (copy_length > 0)
437 mytartype = '1';
438 else {
439 r = archive_entry_symlink_l(entry, &p, ©_length, sconv);
440 if (r != 0) {
441 if (errno == ENOMEM) {
442 archive_set_error(&a->archive, ENOMEM,
443 "Can't allocate memory for Linkname");
444 return (ARCHIVE_FATAL);
445 }
446 archive_set_error(&a->archive,
447 ARCHIVE_ERRNO_FILE_FORMAT,
448 "Can't translate linkname '%s' to %s",
449 p, archive_string_conversion_charset_name(sconv));
450 ret = ARCHIVE_WARN;
451 }
452 }
453 if (copy_length > 0) {
454 if (copy_length >= V7TAR_linkname_size) {
455 archive_set_error(&a->archive, ENAMETOOLONG,
456 "Link contents too long");
457 ret = ARCHIVE_FAILED;
458 copy_length = V7TAR_linkname_size;
459 }
460 memcpy(h + V7TAR_linkname_offset, p, copy_length);
461 }
462
463 if (format_number(archive_entry_mode(entry) & 07777,
464 h + V7TAR_mode_offset, V7TAR_mode_size,
465 V7TAR_mode_max_size, strict)) {
466 archive_set_error(&a->archive, ERANGE,
467 "Numeric mode too large");
468 ret = ARCHIVE_FAILED;
469 }
470
471 if (format_number(archive_entry_uid(entry),
472 h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
473 archive_set_error(&a->archive, ERANGE,
474 "Numeric user ID too large");
475 ret = ARCHIVE_FAILED;
476 }
477
478 if (format_number(archive_entry_gid(entry),
479 h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
480 archive_set_error(&a->archive, ERANGE,
481 "Numeric group ID too large");
482 ret = ARCHIVE_FAILED;
483 }
484
485 if (format_number(archive_entry_size(entry),
486 h + V7TAR_size_offset, V7TAR_size_size,
487 V7TAR_size_max_size, strict)) {
488 archive_set_error(&a->archive, ERANGE,
489 "File size out of range");
490 ret = ARCHIVE_FAILED;
491 }
492
493 if (format_number(archive_entry_mtime(entry),
494 h + V7TAR_mtime_offset, V7TAR_mtime_size,
495 V7TAR_mtime_max_size, strict)) {
496 archive_set_error(&a->archive, ERANGE,
497 "File modification time too large");
498 ret = ARCHIVE_FAILED;
499 }
500
501 if (mytartype >= 0) {
502 h[V7TAR_typeflag_offset] = mytartype;
503 } else {
504 switch (archive_entry_filetype(entry)) {
505 case AE_IFREG: case AE_IFDIR:
506 break;
507 case AE_IFLNK:
508 h[V7TAR_typeflag_offset] = '2';
509 break;
510 default:
511 /* AE_IFBLK, AE_IFCHR, AE_IFIFO, AE_IFSOCK
512 * and unknown */
513 __archive_write_entry_filetype_unsupported(
514 &a->archive, entry, "v7tar");
515 ret = ARCHIVE_FAILED;
516 }
517 }
518
519 checksum = 0;
520 for (i = 0; i < 512; i++)
521 checksum += 255 & (unsigned int)h[i];
522 format_octal(checksum, h + V7TAR_checksum_offset, 6);
523 /* Can't be pre-set in the template. */
524 h[V7TAR_checksum_offset + 6] = '\0';
525 return (ret);
526 }
527
528 /*
529 * Format a number into a field, with some intelligence.
530 */
531 static int
format_number(int64_t v,char * p,int s,int maxsize,int strict)532 format_number(int64_t v, char *p, int s, int maxsize, int strict)
533 {
534 int64_t limit;
535
536 limit = ((int64_t)1 << (s*3));
537
538 /* "Strict" only permits octal values with proper termination. */
539 if (strict)
540 return (format_octal(v, p, s));
541
542 /*
543 * In non-strict mode, we allow the number to overwrite one or
544 * more bytes of the field termination. Even old tar
545 * implementations should be able to handle this with no
546 * problem.
547 */
548 if (v >= 0) {
549 while (s <= maxsize) {
550 if (v < limit)
551 return (format_octal(v, p, s));
552 s++;
553 limit <<= 3;
554 }
555 }
556
557 /* Base-256 can handle any number, positive or negative. */
558 return (format_256(v, p, maxsize));
559 }
560
561 /*
562 * Format a number into the specified field using base-256.
563 */
564 static int
format_256(int64_t v,char * p,int s)565 format_256(int64_t v, char *p, int s)
566 {
567 p += s;
568 while (s-- > 0) {
569 *--p = (char)(v & 0xff);
570 v >>= 8;
571 }
572 *p |= 0x80; /* Set the base-256 marker bit. */
573 return (0);
574 }
575
576 /*
577 * Format a number into the specified field.
578 */
579 static int
format_octal(int64_t v,char * p,int s)580 format_octal(int64_t v, char *p, int s)
581 {
582 int len;
583
584 len = s;
585
586 /* Octal values can't be negative, so use 0. */
587 if (v < 0) {
588 while (len-- > 0)
589 *p++ = '0';
590 return (-1);
591 }
592
593 p += s; /* Start at the end and work backwards. */
594 while (s-- > 0) {
595 *--p = (char)('0' + (v & 7));
596 v >>= 3;
597 }
598
599 if (v == 0)
600 return (0);
601
602 /* If it overflowed, fill field with max value. */
603 while (len-- > 0)
604 *p++ = '7';
605
606 return (-1);
607 }
608
609 static int
archive_write_v7tar_close(struct archive_write * a)610 archive_write_v7tar_close(struct archive_write *a)
611 {
612 return (__archive_write_nulls(a, 512*2));
613 }
614
615 static int
archive_write_v7tar_free(struct archive_write * a)616 archive_write_v7tar_free(struct archive_write *a)
617 {
618 struct v7tar *v7tar;
619
620 v7tar = (struct v7tar *)a->format_data;
621 free(v7tar);
622 a->format_data = NULL;
623 return (ARCHIVE_OK);
624 }
625
626 static int
archive_write_v7tar_finish_entry(struct archive_write * a)627 archive_write_v7tar_finish_entry(struct archive_write *a)
628 {
629 struct v7tar *v7tar;
630 int ret;
631
632 v7tar = (struct v7tar *)a->format_data;
633 ret = __archive_write_nulls(a,
634 (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
635 v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
636 return (ret);
637 }
638
639 static ssize_t
archive_write_v7tar_data(struct archive_write * a,const void * buff,size_t s)640 archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
641 {
642 struct v7tar *v7tar;
643 int ret;
644
645 v7tar = (struct v7tar *)a->format_data;
646 if (s > v7tar->entry_bytes_remaining)
647 s = (size_t)v7tar->entry_bytes_remaining;
648 ret = __archive_write_output(a, buff, s);
649 v7tar->entry_bytes_remaining -= s;
650 if (ret != ARCHIVE_OK)
651 return (ret);
652 return (s);
653 }
654