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