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