Import libarchive-3.1.2.
[dragonfly.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 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
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
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
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
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, &copy_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, &copy_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, &copy_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
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
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
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
618 archive_write_v7tar_close(struct archive_write *a)
619 {
620         return (__archive_write_nulls(a, 512*2));
621 }
622
623 static int
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
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
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 }