]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/archive_write_set_format_gnutar.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / contrib / libarchive / libarchive / archive_write_set_format_gnutar.c
1 /*-
2  * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
3  * Author: Jonas Gastal <jgastal@profusion.mobi>
4  * Copyright (c) 2011-2012 Michihiro NAKAJIMA
5  *
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "archive_platform.h"
30 __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_gnu_tar.c 191579 2009-04-27 18:35:03Z gastal $");
31
32
33 #ifdef HAVE_ERRNO_H
34 #include <errno.h>
35 #endif
36 #include <stdio.h>
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43
44 #include "archive.h"
45 #include "archive_entry.h"
46 #include "archive_entry_locale.h"
47 #include "archive_private.h"
48 #include "archive_write_private.h"
49 #include "archive_write_set_format_private.h"
50
51 struct gnutar {
52         uint64_t        entry_bytes_remaining;
53         uint64_t        entry_padding;
54         const char *    linkname;
55         size_t          linkname_length;
56         const char *    pathname;
57         size_t          pathname_length;
58         const char *    uname;
59         size_t          uname_length;
60         const char *    gname;
61         size_t          gname_length;
62         struct archive_string_conv *opt_sconv;
63         struct archive_string_conv *sconv_default;
64         int init_default_conversion;
65 };
66
67 /*
68  * Define structure of GNU tar header.
69  */
70 #define GNUTAR_name_offset 0
71 #define GNUTAR_name_size 100
72 #define GNUTAR_mode_offset 100
73 #define GNUTAR_mode_size 7
74 #define GNUTAR_mode_max_size 8
75 #define GNUTAR_uid_offset 108
76 #define GNUTAR_uid_size 7
77 #define GNUTAR_uid_max_size 8
78 #define GNUTAR_gid_offset 116
79 #define GNUTAR_gid_size 7
80 #define GNUTAR_gid_max_size 8
81 #define GNUTAR_size_offset 124
82 #define GNUTAR_size_size 11
83 #define GNUTAR_size_max_size 12
84 #define GNUTAR_mtime_offset 136
85 #define GNUTAR_mtime_size 11
86 #define GNUTAR_mtime_max_size 11
87 #define GNUTAR_checksum_offset 148
88 #define GNUTAR_checksum_size 8
89 #define GNUTAR_typeflag_offset 156
90 #define GNUTAR_typeflag_size 1
91 #define GNUTAR_linkname_offset 157
92 #define GNUTAR_linkname_size 100
93 #define GNUTAR_magic_offset 257
94 #define GNUTAR_magic_size 6
95 #define GNUTAR_version_offset 263
96 #define GNUTAR_version_size 2
97 #define GNUTAR_uname_offset 265
98 #define GNUTAR_uname_size 32
99 #define GNUTAR_gname_offset 297
100 #define GNUTAR_gname_size 32
101 #define GNUTAR_rdevmajor_offset 329
102 #define GNUTAR_rdevmajor_size 6
103 #define GNUTAR_rdevmajor_max_size 8
104 #define GNUTAR_rdevminor_offset 337
105 #define GNUTAR_rdevminor_size 6
106 #define GNUTAR_rdevminor_max_size 8
107
108 /*
109  * A filled-in copy of the header for initialization.
110  */
111 static const char template_header[] = {
112         /* name: 100 bytes */
113         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
114         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
115         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
116         0,0,0,0,
117         /* Mode, null termination: 8 bytes */
118         '0','0','0','0','0','0', '0','\0',
119         /* uid, null termination: 8 bytes */
120         '0','0','0','0','0','0', '0','\0',
121         /* gid, null termination: 8 bytes */
122         '0','0','0','0','0','0', '0','\0',
123         /* size, space termination: 12 bytes */
124         '0','0','0','0','0','0','0','0','0','0','0', '\0',
125         /* mtime, space termination: 12 bytes */
126         '0','0','0','0','0','0','0','0','0','0','0', '\0',
127         /* Initial checksum value: 8 spaces */
128         ' ',' ',' ',' ',' ',' ',' ',' ',
129         /* Typeflag: 1 byte */
130         '0',                    /* '0' = regular file */
131         /* Linkname: 100 bytes */
132         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
133         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
134         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
135         0,0,0,0,
136         /* Magic: 8 bytes */
137         'u','s','t','a','r',' ', ' ','\0',
138         /* Uname: 32 bytes */
139         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
140         /* Gname: 32 bytes */
141         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
142         /* rdevmajor + null padding: 8 bytes */
143         '\0','\0','\0','\0','\0','\0', '\0','\0',
144         /* rdevminor + null padding: 8 bytes */
145         '\0','\0','\0','\0','\0','\0', '\0','\0',
146         /* Padding: 167 bytes */
147         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
148         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
149         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
150         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
151         0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
152         0,0,0,0,0,0,0
153 };
154
155 static int      archive_write_gnutar_options(struct archive_write *,
156                     const char *, const char *);
157 static int      archive_format_gnutar_header(struct archive_write *, char h[512],
158                     struct archive_entry *, int tartype);
159 static int      archive_write_gnutar_header(struct archive_write *,
160                     struct archive_entry *entry);
161 static ssize_t  archive_write_gnutar_data(struct archive_write *a, const void *buff,
162                     size_t s);
163 static int      archive_write_gnutar_free(struct archive_write *);
164 static int      archive_write_gnutar_close(struct archive_write *);
165 static int      archive_write_gnutar_finish_entry(struct archive_write *);
166 static int      format_256(int64_t, char *, int);
167 static int      format_number(int64_t, char *, int size, int maxsize);
168 static int      format_octal(int64_t, char *, int);
169
170 /*
171  * Set output format to 'GNU tar' format.
172  */
173 int
174 archive_write_set_format_gnutar(struct archive *_a)
175 {
176         struct archive_write *a = (struct archive_write *)_a;
177         struct gnutar *gnutar;
178
179         gnutar = (struct gnutar *)calloc(1, sizeof(*gnutar));
180         if (gnutar == NULL) {
181                 archive_set_error(&a->archive, ENOMEM,
182                     "Can't allocate gnutar data");
183                 return (ARCHIVE_FATAL);
184         }
185         a->format_data = gnutar;
186         a->format_name = "gnutar";
187         a->format_options = archive_write_gnutar_options;
188         a->format_write_header = archive_write_gnutar_header;
189         a->format_write_data = archive_write_gnutar_data;
190         a->format_close = archive_write_gnutar_close;
191         a->format_free = archive_write_gnutar_free;
192         a->format_finish_entry = archive_write_gnutar_finish_entry;
193         a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
194         a->archive.archive_format_name = "GNU tar";
195         return (ARCHIVE_OK);
196 }
197
198 static int
199 archive_write_gnutar_options(struct archive_write *a, const char *key,
200     const char *val)
201 {
202         struct gnutar *gnutar = (struct gnutar *)a->format_data;
203         int ret = ARCHIVE_FAILED;
204
205         if (strcmp(key, "hdrcharset")  == 0) {
206                 if (val == NULL || val[0] == 0)
207                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
208                             "%s: hdrcharset option needs a character-set name",
209                             a->format_name);
210                 else {
211                         gnutar->opt_sconv = archive_string_conversion_to_charset(
212                             &a->archive, val, 0);
213                         if (gnutar->opt_sconv != NULL)
214                                 ret = ARCHIVE_OK;
215                         else
216                                 ret = ARCHIVE_FATAL;
217                 }
218                 return (ret);
219         }
220
221         /* Note: The "warn" return is just to inform the options
222          * supervisor that we didn't handle it.  It will generate
223          * a suitable error if no one used this option. */
224         return (ARCHIVE_WARN);
225 }
226
227 static int
228 archive_write_gnutar_close(struct archive_write *a)
229 {
230         return (__archive_write_nulls(a, 512*2));
231 }
232
233 static int
234 archive_write_gnutar_free(struct archive_write *a)
235 {
236         struct gnutar *gnutar;
237
238         gnutar = (struct gnutar *)a->format_data;
239         free(gnutar);
240         a->format_data = NULL;
241         return (ARCHIVE_OK);
242 }
243
244 static int
245 archive_write_gnutar_finish_entry(struct archive_write *a)
246 {
247         struct gnutar *gnutar;
248         int ret;
249
250         gnutar = (struct gnutar *)a->format_data;
251         ret = __archive_write_nulls(a, (size_t)
252             (gnutar->entry_bytes_remaining + gnutar->entry_padding));
253         gnutar->entry_bytes_remaining = gnutar->entry_padding = 0;
254         return (ret);
255 }
256
257 static ssize_t
258 archive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s)
259 {
260         struct gnutar *gnutar;
261         int ret;
262
263         gnutar = (struct gnutar *)a->format_data;
264         if (s > gnutar->entry_bytes_remaining)
265                 s = (size_t)gnutar->entry_bytes_remaining;
266         ret = __archive_write_output(a, buff, s);
267         gnutar->entry_bytes_remaining -= s;
268         if (ret != ARCHIVE_OK)
269                 return (ret);
270         return (s);
271 }
272
273 static int
274 archive_write_gnutar_header(struct archive_write *a,
275      struct archive_entry *entry)
276 {
277         char buff[512];
278         int r, ret, ret2 = ARCHIVE_OK;
279         int tartype;
280         struct gnutar *gnutar;
281         struct archive_string_conv *sconv;
282         struct archive_entry *entry_main;
283
284         gnutar = (struct gnutar *)a->format_data;
285
286         /* Setup default string conversion. */
287         if (gnutar->opt_sconv == NULL) {
288                 if (!gnutar->init_default_conversion) {
289                         gnutar->sconv_default =
290                             archive_string_default_conversion_for_write(
291                                 &(a->archive));
292                         gnutar->init_default_conversion = 1;
293                 }
294                 sconv = gnutar->sconv_default;
295         } else
296                 sconv = gnutar->opt_sconv;
297
298         /* Only regular files (not hardlinks) have data. */
299         if (archive_entry_hardlink(entry) != NULL ||
300             archive_entry_symlink(entry) != NULL ||
301             !(archive_entry_filetype(entry) == AE_IFREG))
302                 archive_entry_set_size(entry, 0);
303
304         if (AE_IFDIR == archive_entry_filetype(entry)) {
305                 const char *p;
306                 size_t path_length;
307                 /*
308                  * Ensure a trailing '/'.  Modify the entry so
309                  * the client sees the change.
310                  */
311 #if defined(_WIN32) && !defined(__CYGWIN__)
312                 const wchar_t *wp;
313
314                 wp = archive_entry_pathname_w(entry);
315                 if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
316                         struct archive_wstring ws;
317
318                         archive_string_init(&ws);
319                         path_length = wcslen(wp);
320                         if (archive_wstring_ensure(&ws,
321                             path_length + 2) == NULL) {
322                                 archive_set_error(&a->archive, ENOMEM,
323                                     "Can't allocate ustar data");
324                                 archive_wstring_free(&ws);
325                                 return(ARCHIVE_FATAL);
326                         }
327                         /* Should we keep '\' ? */
328                         if (wp[path_length -1] == L'\\')
329                                 path_length--;
330                         archive_wstrncpy(&ws, wp, path_length);
331                         archive_wstrappend_wchar(&ws, L'/');
332                         archive_entry_copy_pathname_w(entry, ws.s);
333                         archive_wstring_free(&ws);
334                         p = NULL;
335                 } else
336 #endif
337                         p = archive_entry_pathname(entry);
338                 /*
339                  * On Windows, this is a backup operation just in
340                  * case getting WCS failed. On POSIX, this is a
341                  * normal operation.
342                  */
343                 if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
344                         struct archive_string as;
345
346                         archive_string_init(&as);
347                         path_length = strlen(p);
348                         if (archive_string_ensure(&as,
349                             path_length + 2) == NULL) {
350                                 archive_set_error(&a->archive, ENOMEM,
351                                     "Can't allocate ustar data");
352                                 archive_string_free(&as);
353                                 return(ARCHIVE_FATAL);
354                         }
355 #if defined(_WIN32) && !defined(__CYGWIN__)
356                         /* NOTE: This might break the pathname
357                          * if the current code page is CP932 and
358                          * the pathname includes a character '\'
359                          * as a part of its multibyte pathname. */
360                         if (p[strlen(p) -1] == '\\')
361                                 path_length--;
362                         else
363 #endif
364                         archive_strncpy(&as, p, path_length);
365                         archive_strappend_char(&as, '/');
366                         archive_entry_copy_pathname(entry, as.s);
367                         archive_string_free(&as);
368                 }
369         }
370
371 #if defined(_WIN32) && !defined(__CYGWIN__)
372         /* Make sure the path separators in pathname, hardlink and symlink
373          * are all slash '/', not the Windows path separator '\'. */
374         entry_main = __la_win_entry_in_posix_pathseparator(entry);
375         if (entry_main == NULL) {
376                 archive_set_error(&a->archive, ENOMEM,
377                     "Can't allocate ustar data");
378                 return(ARCHIVE_FATAL);
379         }
380         if (entry != entry_main)
381                 entry = entry_main;
382         else
383                 entry_main = NULL;
384 #else
385         entry_main = NULL;
386 #endif
387         r = archive_entry_pathname_l(entry, &(gnutar->pathname),
388             &(gnutar->pathname_length), sconv);
389         if (r != 0) {
390                 if (errno == ENOMEM) {
391                         archive_set_error(&a->archive, ENOMEM,
392                             "Can't allocate memory for Pathame");
393                         ret = ARCHIVE_FATAL;
394                         goto exit_write_header;
395                 }
396                 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
397                     "Can't translate pathname '%s' to %s",
398                     archive_entry_pathname(entry),
399                     archive_string_conversion_charset_name(sconv));
400                 ret2 = ARCHIVE_WARN;
401         }
402         r = archive_entry_uname_l(entry, &(gnutar->uname),
403             &(gnutar->uname_length), sconv);
404         if (r != 0) {
405                 if (errno == ENOMEM) {
406                         archive_set_error(&a->archive, ENOMEM,
407                             "Can't allocate memory for Uname");
408                         ret = ARCHIVE_FATAL;
409                         goto exit_write_header;
410                 }
411                 archive_set_error(&a->archive,
412                     ARCHIVE_ERRNO_FILE_FORMAT,
413                     "Can't translate uname '%s' to %s",
414                     archive_entry_uname(entry),
415                     archive_string_conversion_charset_name(sconv));
416                 ret2 = ARCHIVE_WARN;
417         }
418         r = archive_entry_gname_l(entry, &(gnutar->gname),
419             &(gnutar->gname_length), sconv);
420         if (r != 0) {
421                 if (errno == ENOMEM) {
422                         archive_set_error(&a->archive, ENOMEM,
423                             "Can't allocate memory for Gname");
424                         ret = ARCHIVE_FATAL;
425                         goto exit_write_header;
426                 }
427                 archive_set_error(&a->archive,
428                     ARCHIVE_ERRNO_FILE_FORMAT,
429                     "Can't translate gname '%s' to %s",
430                     archive_entry_gname(entry),
431                     archive_string_conversion_charset_name(sconv));
432                 ret2 = ARCHIVE_WARN;
433         }
434
435         /* If linkname is longer than 100 chars we need to add a 'K' header. */
436         r = archive_entry_hardlink_l(entry, &(gnutar->linkname),
437             &(gnutar->linkname_length), sconv);
438         if (r != 0) {
439                 if (errno == ENOMEM) {
440                         archive_set_error(&a->archive, ENOMEM,
441                             "Can't allocate memory for Linkname");
442                         ret = ARCHIVE_FATAL;
443                         goto exit_write_header;
444                 }
445                 archive_set_error(&a->archive,
446                     ARCHIVE_ERRNO_FILE_FORMAT,
447                     "Can't translate linkname '%s' to %s",
448                     archive_entry_hardlink(entry),
449                     archive_string_conversion_charset_name(sconv));
450                 ret2 = ARCHIVE_WARN;
451         }
452         if (gnutar->linkname_length == 0) {
453                 r = archive_entry_symlink_l(entry, &(gnutar->linkname),
454                     &(gnutar->linkname_length), sconv);
455                 if (r != 0) {
456                         if (errno == ENOMEM) {
457                                 archive_set_error(&a->archive, ENOMEM,
458                                     "Can't allocate memory for Linkname");
459                                 ret = ARCHIVE_FATAL;
460                                 goto exit_write_header;
461                         }
462                         archive_set_error(&a->archive,
463                             ARCHIVE_ERRNO_FILE_FORMAT,
464                             "Can't translate linkname '%s' to %s",
465                             archive_entry_hardlink(entry),
466                             archive_string_conversion_charset_name(sconv));
467                         ret2 = ARCHIVE_WARN;
468                 }
469         }
470         if (gnutar->linkname_length > GNUTAR_linkname_size) {
471                 size_t length = gnutar->linkname_length + 1;
472                 struct archive_entry *temp = archive_entry_new2(&a->archive);
473
474                 /* Uname/gname here don't really matter since no one reads them;
475                  * these are the values that GNU tar happens to use on FreeBSD. */
476                 archive_entry_set_uname(temp, "root");
477                 archive_entry_set_gname(temp, "wheel");
478
479                 archive_entry_set_pathname(temp, "././@LongLink");
480                 archive_entry_set_size(temp, length);
481                 ret = archive_format_gnutar_header(a, buff, temp, 'K');
482                 archive_entry_free(temp);
483                 if (ret < ARCHIVE_WARN)
484                         goto exit_write_header;
485                 ret = __archive_write_output(a, buff, 512);
486                 if (ret < ARCHIVE_WARN)
487                         goto exit_write_header;
488                 /* Write name and trailing null byte. */
489                 ret = __archive_write_output(a, gnutar->linkname, length);
490                 if (ret < ARCHIVE_WARN)
491                         goto exit_write_header;
492                 /* Pad to 512 bytes */
493                 ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
494                 if (ret < ARCHIVE_WARN)
495                         goto exit_write_header;
496         }
497
498         /* If pathname is longer than 100 chars we need to add an 'L' header. */
499         if (gnutar->pathname_length > GNUTAR_name_size) {
500                 const char *pathname = gnutar->pathname;
501                 size_t length = gnutar->pathname_length + 1;
502                 struct archive_entry *temp = archive_entry_new2(&a->archive);
503
504                 /* Uname/gname here don't really matter since no one reads them;
505                  * these are the values that GNU tar happens to use on FreeBSD. */
506                 archive_entry_set_uname(temp, "root");
507                 archive_entry_set_gname(temp, "wheel");
508
509                 archive_entry_set_pathname(temp, "././@LongLink");
510                 archive_entry_set_size(temp, length);
511                 ret = archive_format_gnutar_header(a, buff, temp, 'L');
512                 archive_entry_free(temp);
513                 if (ret < ARCHIVE_WARN)
514                         goto exit_write_header;
515                 ret = __archive_write_output(a, buff, 512);
516                 if(ret < ARCHIVE_WARN)
517                         goto exit_write_header;
518                 /* Write pathname + trailing null byte. */
519                 ret = __archive_write_output(a, pathname, length);
520                 if(ret < ARCHIVE_WARN)
521                         goto exit_write_header;
522                 /* Pad to multiple of 512 bytes. */
523                 ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
524                 if (ret < ARCHIVE_WARN)
525                         goto exit_write_header;
526         }
527
528         if (archive_entry_hardlink(entry) != NULL) {
529                 tartype = '1';
530         } else
531                 switch (archive_entry_filetype(entry)) {
532                 case AE_IFREG: tartype = '0' ; break;
533                 case AE_IFLNK: tartype = '2' ; break;
534                 case AE_IFCHR: tartype = '3' ; break;
535                 case AE_IFBLK: tartype = '4' ; break;
536                 case AE_IFDIR: tartype = '5' ; break;
537                 case AE_IFIFO: tartype = '6' ; break;
538                 default: /* AE_IFSOCK and unknown */
539                         __archive_write_entry_filetype_unsupported(
540                             &a->archive, entry, "gnutar");
541                         ret = ARCHIVE_FAILED;
542                         goto exit_write_header;
543                 }
544
545         ret = archive_format_gnutar_header(a, buff, entry, tartype);
546         if (ret < ARCHIVE_WARN)
547                 goto exit_write_header;
548         if (ret2 < ret)
549                 ret = ret2;
550         ret2 = __archive_write_output(a, buff, 512);
551         if (ret2 < ARCHIVE_WARN) {
552                 ret = ret2;
553                 goto exit_write_header;
554         }
555         if (ret2 < ret)
556                 ret = ret2;
557
558         gnutar->entry_bytes_remaining = archive_entry_size(entry);
559         gnutar->entry_padding = 0x1ff & (-(int64_t)gnutar->entry_bytes_remaining);
560 exit_write_header:
561         archive_entry_free(entry_main);
562         return (ret);
563 }
564
565 static int
566 archive_format_gnutar_header(struct archive_write *a, char h[512],
567     struct archive_entry *entry, int tartype)
568 {
569         unsigned int checksum;
570         int i, ret;
571         size_t copy_length;
572         const char *p;
573         struct gnutar *gnutar;
574
575         gnutar = (struct gnutar *)a->format_data;
576
577         ret = 0;
578
579         /*
580          * The "template header" already includes the signature,
581          * various end-of-field markers, and other required elements.
582          */
583         memcpy(h, &template_header, 512);
584
585         /*
586          * Because the block is already null-filled, and strings
587          * are allowed to exactly fill their destination (without null),
588          * I use memcpy(dest, src, strlen()) here a lot to copy strings.
589          */
590
591         if (tartype == 'K' || tartype == 'L') {
592                 p = archive_entry_pathname(entry);
593                 copy_length = strlen(p);
594         } else {
595                 p = gnutar->pathname;
596                 copy_length = gnutar->pathname_length;
597         }
598         if (copy_length > GNUTAR_name_size)
599                 copy_length = GNUTAR_name_size;
600         memcpy(h + GNUTAR_name_offset, p, copy_length);
601
602         if ((copy_length = gnutar->linkname_length) > 0) {
603                 if (copy_length > GNUTAR_linkname_size)
604                         copy_length = GNUTAR_linkname_size;
605                 memcpy(h + GNUTAR_linkname_offset, gnutar->linkname,
606                     copy_length);
607         }
608
609         /* TODO: How does GNU tar handle unames longer than GNUTAR_uname_size? */
610         if (tartype == 'K' || tartype == 'L') {
611                 p = archive_entry_uname(entry);
612                 copy_length = strlen(p);
613         } else {
614                 p = gnutar->uname;
615                 copy_length = gnutar->uname_length;
616         }
617         if (copy_length > 0) {
618                 if (copy_length > GNUTAR_uname_size)
619                         copy_length = GNUTAR_uname_size;
620                 memcpy(h + GNUTAR_uname_offset, p, copy_length);
621         }
622
623         /* TODO: How does GNU tar handle gnames longer than GNUTAR_gname_size? */
624         if (tartype == 'K' || tartype == 'L') {
625                 p = archive_entry_gname(entry);
626                 copy_length = strlen(p);
627         } else {
628                 p = gnutar->gname;
629                 copy_length = gnutar->gname_length;
630         }
631         if (copy_length > 0) {
632                 if (strlen(p) > GNUTAR_gname_size)
633                         copy_length = GNUTAR_gname_size;
634                 memcpy(h + GNUTAR_gname_offset, p, copy_length);
635         }
636
637         /* By truncating the mode here, we ensure it always fits. */
638         format_octal(archive_entry_mode(entry) & 07777,
639             h + GNUTAR_mode_offset, GNUTAR_mode_size);
640
641         /* GNU tar supports base-256 here, so should never overflow. */
642         if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset,
643                 GNUTAR_uid_size, GNUTAR_uid_max_size)) {
644                 archive_set_error(&a->archive, ERANGE,
645                     "Numeric user ID %jd too large",
646                     (intmax_t)archive_entry_uid(entry));
647                 ret = ARCHIVE_FAILED;
648         }
649
650         /* GNU tar supports base-256 here, so should never overflow. */
651         if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset,
652                 GNUTAR_gid_size, GNUTAR_gid_max_size)) {
653                 archive_set_error(&a->archive, ERANGE,
654                     "Numeric group ID %jd too large",
655                     (intmax_t)archive_entry_gid(entry));
656                 ret = ARCHIVE_FAILED;
657         }
658
659         /* GNU tar supports base-256 here, so should never overflow. */
660         if (format_number(archive_entry_size(entry), h + GNUTAR_size_offset,
661                 GNUTAR_size_size, GNUTAR_size_max_size)) {
662                 archive_set_error(&a->archive, ERANGE,
663                     "File size out of range");
664                 ret = ARCHIVE_FAILED;
665         }
666
667         /* Shouldn't overflow before 2106, since mtime field is 33 bits. */
668         format_octal(archive_entry_mtime(entry),
669             h + GNUTAR_mtime_offset, GNUTAR_mtime_size);
670
671         if (archive_entry_filetype(entry) == AE_IFBLK
672             || archive_entry_filetype(entry) == AE_IFCHR) {
673                 if (format_octal(archive_entry_rdevmajor(entry),
674                     h + GNUTAR_rdevmajor_offset,
675                         GNUTAR_rdevmajor_size)) {
676                         archive_set_error(&a->archive, ERANGE,
677                             "Major device number too large");
678                         ret = ARCHIVE_FAILED;
679                 }
680
681                 if (format_octal(archive_entry_rdevminor(entry),
682                     h + GNUTAR_rdevminor_offset,
683                         GNUTAR_rdevminor_size)) {
684                         archive_set_error(&a->archive, ERANGE,
685                             "Minor device number too large");
686                         ret = ARCHIVE_FAILED;
687                 }
688         }
689
690         h[GNUTAR_typeflag_offset] = tartype;
691
692         checksum = 0;
693         for (i = 0; i < 512; i++)
694                 checksum += 255 & (unsigned int)h[i];
695         h[GNUTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */
696         /* h[GNUTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */
697         format_octal(checksum, h + GNUTAR_checksum_offset, 6);
698         return (ret);
699 }
700
701 /*
702  * Format a number into a field, falling back to base-256 if necessary.
703  */
704 static int
705 format_number(int64_t v, char *p, int s, int maxsize)
706 {
707         int64_t limit = ((int64_t)1 << (s*3));
708
709         if (v < limit)
710                 return (format_octal(v, p, s));
711         return (format_256(v, p, maxsize));
712 }
713
714 /*
715  * Format a number into the specified field using base-256.
716  */
717 static int
718 format_256(int64_t v, char *p, int s)
719 {
720         p += s;
721         while (s-- > 0) {
722                 *--p = (char)(v & 0xff);
723                 v >>= 8;
724         }
725         *p |= 0x80; /* Set the base-256 marker bit. */
726         return (0);
727 }
728
729 /*
730  * Format a number into the specified field using octal.
731  */
732 static int
733 format_octal(int64_t v, char *p, int s)
734 {
735         int len = s;
736
737         /* Octal values can't be negative, so use 0. */
738         if (v < 0)
739                 v = 0;
740
741         p += s;         /* Start at the end and work backwards. */
742         while (s-- > 0) {
743                 *--p = (char)('0' + (v & 7));
744                 v >>= 3;
745         }
746
747         if (v == 0)
748                 return (0);
749
750         /* If it overflowed, fill field with max value. */
751         while (len-- > 0)
752                 *p++ = '7';
753
754         return (-1);
755 }