]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_write_set_format_v7tar.c
MFC r339746,339751,339794,340866,340939,342042:
[FreeBSD/stable/10.git] / contrib / libarchive / 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                 if (entry_main)
334                         archive_entry_free(entry_main);
335                 return (ret);
336         }
337         ret2 = __archive_write_output(a, buff, 512);
338         if (ret2 < ARCHIVE_WARN) {
339                 if (entry_main)
340                         archive_entry_free(entry_main);
341                 return (ret2);
342         }
343         if (ret2 < ret)
344                 ret = ret2;
345
346         v7tar->entry_bytes_remaining = archive_entry_size(entry);
347         v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
348         if (entry_main)
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
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, &copy_length, sconv);
388         if (r != 0) {
389                 if (errno == ENOMEM) {
390                         archive_set_error(&a->archive, ENOMEM,
391                             "Can't allocate memory for Pathname");
392                         return (ARCHIVE_FATAL);
393                 }
394                 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
395                     "Can't translate pathname '%s' to %s",
396                     pp, archive_string_conversion_charset_name(sconv));
397                 ret = ARCHIVE_WARN;
398         }
399         if (strict && copy_length < V7TAR_name_size)
400                 memcpy(h + V7TAR_name_offset, pp, copy_length);
401         else if (!strict && copy_length <= V7TAR_name_size)
402                 memcpy(h + V7TAR_name_offset, pp, copy_length);
403         else {
404                 /* Prefix is too long. */
405                 archive_set_error(&a->archive, ENAMETOOLONG,
406                     "Pathname too long");
407                 ret = ARCHIVE_FAILED;
408         }
409
410         r = archive_entry_hardlink_l(entry, &p, &copy_length, sconv);
411         if (r != 0) {
412                 if (errno == ENOMEM) {
413                         archive_set_error(&a->archive, ENOMEM,
414                             "Can't allocate memory for Linkname");
415                         return (ARCHIVE_FATAL);
416                 }
417                 archive_set_error(&a->archive,
418                     ARCHIVE_ERRNO_FILE_FORMAT,
419                     "Can't translate linkname '%s' to %s",
420                     p, archive_string_conversion_charset_name(sconv));
421                 ret = ARCHIVE_WARN;
422         }
423         if (copy_length > 0)
424                 mytartype = '1';
425         else {
426                 r = archive_entry_symlink_l(entry, &p, &copy_length, sconv);
427                 if (r != 0) {
428                         if (errno == ENOMEM) {
429                                 archive_set_error(&a->archive, ENOMEM,
430                                     "Can't allocate memory for Linkname");
431                                 return (ARCHIVE_FATAL);
432                         }
433                         archive_set_error(&a->archive,
434                             ARCHIVE_ERRNO_FILE_FORMAT,
435                             "Can't translate linkname '%s' to %s",
436                             p, archive_string_conversion_charset_name(sconv));
437                         ret = ARCHIVE_WARN;
438                 }
439         }
440         if (copy_length > 0) {
441                 if (copy_length >= V7TAR_linkname_size) {
442                         archive_set_error(&a->archive, ENAMETOOLONG,
443                             "Link contents too long");
444                         ret = ARCHIVE_FAILED;
445                         copy_length = V7TAR_linkname_size;
446                 }
447                 memcpy(h + V7TAR_linkname_offset, p, copy_length);
448         }
449
450         if (format_number(archive_entry_mode(entry) & 07777,
451             h + V7TAR_mode_offset, V7TAR_mode_size,
452             V7TAR_mode_max_size, strict)) {
453                 archive_set_error(&a->archive, ERANGE,
454                     "Numeric mode too large");
455                 ret = ARCHIVE_FAILED;
456         }
457
458         if (format_number(archive_entry_uid(entry),
459             h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) {
460                 archive_set_error(&a->archive, ERANGE,
461                     "Numeric user ID too large");
462                 ret = ARCHIVE_FAILED;
463         }
464
465         if (format_number(archive_entry_gid(entry),
466             h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) {
467                 archive_set_error(&a->archive, ERANGE,
468                     "Numeric group ID too large");
469                 ret = ARCHIVE_FAILED;
470         }
471
472         if (format_number(archive_entry_size(entry),
473             h + V7TAR_size_offset, V7TAR_size_size,
474             V7TAR_size_max_size, strict)) {
475                 archive_set_error(&a->archive, ERANGE,
476                     "File size out of range");
477                 ret = ARCHIVE_FAILED;
478         }
479
480         if (format_number(archive_entry_mtime(entry),
481             h + V7TAR_mtime_offset, V7TAR_mtime_size,
482             V7TAR_mtime_max_size, strict)) {
483                 archive_set_error(&a->archive, ERANGE,
484                     "File modification time too large");
485                 ret = ARCHIVE_FAILED;
486         }
487
488         if (mytartype >= 0) {
489                 h[V7TAR_typeflag_offset] = mytartype;
490         } else {
491                 switch (archive_entry_filetype(entry)) {
492                 case AE_IFREG: case AE_IFDIR:
493                         break;
494                 case AE_IFLNK:
495                         h[V7TAR_typeflag_offset] = '2';
496                         break;
497                 case AE_IFCHR:
498                         archive_set_error(&a->archive,
499                             ARCHIVE_ERRNO_FILE_FORMAT,
500                             "tar format cannot archive character device");
501                         return (ARCHIVE_FAILED);
502                 case AE_IFBLK:
503                         archive_set_error(&a->archive,
504                             ARCHIVE_ERRNO_FILE_FORMAT,
505                             "tar format cannot archive block device");
506                         return (ARCHIVE_FAILED);
507                 case AE_IFIFO:
508                         archive_set_error(&a->archive,
509                             ARCHIVE_ERRNO_FILE_FORMAT,
510                             "tar format cannot archive fifo");
511                         return (ARCHIVE_FAILED);
512                 case AE_IFSOCK:
513                         archive_set_error(&a->archive,
514                             ARCHIVE_ERRNO_FILE_FORMAT,
515                             "tar format cannot archive socket");
516                         return (ARCHIVE_FAILED);
517                 default:
518                         archive_set_error(&a->archive,
519                             ARCHIVE_ERRNO_FILE_FORMAT,
520                             "tar format cannot archive this (mode=0%lo)",
521                             (unsigned long)archive_entry_mode(entry));
522                         ret = ARCHIVE_FAILED;
523                 }
524         }
525
526         checksum = 0;
527         for (i = 0; i < 512; i++)
528                 checksum += 255 & (unsigned int)h[i];
529         format_octal(checksum, h + V7TAR_checksum_offset, 6);
530         /* Can't be pre-set in the template. */
531         h[V7TAR_checksum_offset + 6] = '\0';
532         return (ret);
533 }
534
535 /*
536  * Format a number into a field, with some intelligence.
537  */
538 static int
539 format_number(int64_t v, char *p, int s, int maxsize, int strict)
540 {
541         int64_t limit;
542
543         limit = ((int64_t)1 << (s*3));
544
545         /* "Strict" only permits octal values with proper termination. */
546         if (strict)
547                 return (format_octal(v, p, s));
548
549         /*
550          * In non-strict mode, we allow the number to overwrite one or
551          * more bytes of the field termination.  Even old tar
552          * implementations should be able to handle this with no
553          * problem.
554          */
555         if (v >= 0) {
556                 while (s <= maxsize) {
557                         if (v < limit)
558                                 return (format_octal(v, p, s));
559                         s++;
560                         limit <<= 3;
561                 }
562         }
563
564         /* Base-256 can handle any number, positive or negative. */
565         return (format_256(v, p, maxsize));
566 }
567
568 /*
569  * Format a number into the specified field using base-256.
570  */
571 static int
572 format_256(int64_t v, char *p, int s)
573 {
574         p += s;
575         while (s-- > 0) {
576                 *--p = (char)(v & 0xff);
577                 v >>= 8;
578         }
579         *p |= 0x80; /* Set the base-256 marker bit. */
580         return (0);
581 }
582
583 /*
584  * Format a number into the specified field.
585  */
586 static int
587 format_octal(int64_t v, char *p, int s)
588 {
589         int len;
590
591         len = s;
592
593         /* Octal values can't be negative, so use 0. */
594         if (v < 0) {
595                 while (len-- > 0)
596                         *p++ = '0';
597                 return (-1);
598         }
599
600         p += s;         /* Start at the end and work backwards. */
601         while (s-- > 0) {
602                 *--p = (char)('0' + (v & 7));
603                 v >>= 3;
604         }
605
606         if (v == 0)
607                 return (0);
608
609         /* If it overflowed, fill field with max value. */
610         while (len-- > 0)
611                 *p++ = '7';
612
613         return (-1);
614 }
615
616 static int
617 archive_write_v7tar_close(struct archive_write *a)
618 {
619         return (__archive_write_nulls(a, 512*2));
620 }
621
622 static int
623 archive_write_v7tar_free(struct archive_write *a)
624 {
625         struct v7tar *v7tar;
626
627         v7tar = (struct v7tar *)a->format_data;
628         free(v7tar);
629         a->format_data = NULL;
630         return (ARCHIVE_OK);
631 }
632
633 static int
634 archive_write_v7tar_finish_entry(struct archive_write *a)
635 {
636         struct v7tar *v7tar;
637         int ret;
638
639         v7tar = (struct v7tar *)a->format_data;
640         ret = __archive_write_nulls(a,
641             (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding));
642         v7tar->entry_bytes_remaining = v7tar->entry_padding = 0;
643         return (ret);
644 }
645
646 static ssize_t
647 archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
648 {
649         struct v7tar *v7tar;
650         int ret;
651
652         v7tar = (struct v7tar *)a->format_data;
653         if (s > v7tar->entry_bytes_remaining)
654                 s = (size_t)v7tar->entry_bytes_remaining;
655         ret = __archive_write_output(a, buff, s);
656         v7tar->entry_bytes_remaining -= s;
657         if (ret != ARCHIVE_OK)
658                 return (ret);
659         return (s);
660 }