2 * Copyright (c) 2003-2007 Tim Kientzle
3 * Copyright (c) 2011-2012 Michihiro NAKAJIMA
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
27 #include "archive_platform.h"
28 __FBSDID("$FreeBSD$");
43 #include "archive_entry.h"
44 #include "archive_entry_locale.h"
45 #include "archive_private.h"
46 #include "archive_write_private.h"
49 uint64_t entry_bytes_remaining;
50 uint64_t entry_padding;
52 struct archive_string_conv *opt_sconv;
53 struct archive_string_conv *sconv_default;
54 int init_default_conversion;
58 * Define structure of POSIX 'v7tar' tar header.
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
87 * A filled-in copy of the header for initialization.
89 static const char template_header[] = {
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,
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 */
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,
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
125 static ssize_t archive_write_v7tar_data(struct archive_write *a, const void *buff,
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 *);
141 * Set output format to 'v7tar' format.
144 archive_write_set_format_v7tar(struct archive *_a)
146 struct archive_write *a = (struct archive_write *)_a;
149 archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
150 ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar");
152 /* If someone else was already registered, unregister them. */
153 if (a->format_free != NULL)
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);
164 v7tar = (struct v7tar *)calloc(1, sizeof(*v7tar));
166 archive_set_error(&a->archive, ENOMEM,
167 "Can't allocate v7tar data");
168 return (ARCHIVE_FATAL);
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)";
184 archive_write_v7tar_options(struct archive_write *a, const char *key,
187 struct v7tar *v7tar = (struct v7tar *)a->format_data;
188 int ret = ARCHIVE_FAILED;
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",
196 v7tar->opt_sconv = archive_string_conversion_to_charset(
197 &a->archive, val, 0);
198 if (v7tar->opt_sconv != NULL)
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);
213 archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
218 struct archive_entry *entry_main;
219 struct archive_string_conv *sconv;
221 v7tar = (struct v7tar *)a->format_data;
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(
229 v7tar->init_default_conversion = 1;
231 sconv = v7tar->sconv_default;
233 sconv = v7tar->opt_sconv;
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);
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);
248 if (AE_IFDIR == archive_entry_filetype(entry)) {
252 * Ensure a trailing '/'. Modify the entry so
253 * the client sees the change.
255 #if defined(_WIN32) && !defined(__CYGWIN__)
258 wp = archive_entry_pathname_w(entry);
259 if (wp != NULL && wp[wcslen(wp) -1] != L'/') {
260 struct archive_wstring ws;
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);
271 /* Should we keep '\' ? */
272 if (wp[path_length -1] == L'\\')
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);
281 p = archive_entry_pathname(entry);
283 * On Windows, this is a backup operation just in
284 * case getting WCS failed. On POSIX, this is a
287 if (p != NULL && p[strlen(p) - 1] != '/') {
288 struct archive_string as;
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);
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] == '\\')
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);
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);
324 if (entry != entry_main)
331 ret = format_header_v7tar(a, buff, entry, 1, sconv);
332 if (ret < ARCHIVE_WARN) {
334 archive_entry_free(entry_main);
337 ret2 = __archive_write_output(a, buff, 512);
338 if (ret2 < ARCHIVE_WARN) {
340 archive_entry_free(entry_main);
346 v7tar->entry_bytes_remaining = archive_entry_size(entry);
347 v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining);
349 archive_entry_free(entry_main);
354 * Format a basic 512-byte "v7tar" header.
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).
363 format_header_v7tar(struct archive_write *a, char h[512],
364 struct archive_entry *entry, int strict,
365 struct archive_string_conv *sconv)
367 unsigned int checksum;
376 * The "template header" already includes the "v7tar"
377 * signature, various end-of-field markers and other required
380 memcpy(h, &template_header, 512);
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.
387 r = archive_entry_pathname_l(entry, &pp, ©_length, sconv);
389 if (errno == ENOMEM) {
390 archive_set_error(&a->archive, ENOMEM,
391 "Can't allocate memory for Pathname");
392 return (ARCHIVE_FATAL);
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));
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);
404 /* Prefix is too long. */
405 archive_set_error(&a->archive, ENAMETOOLONG,
406 "Pathname too long");
407 ret = ARCHIVE_FAILED;
410 r = archive_entry_hardlink_l(entry, &p, ©_length, sconv);
412 if (errno == ENOMEM) {
413 archive_set_error(&a->archive, ENOMEM,
414 "Can't allocate memory for Linkname");
415 return (ARCHIVE_FATAL);
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));
426 r = archive_entry_symlink_l(entry, &p, ©_length, sconv);
428 if (errno == ENOMEM) {
429 archive_set_error(&a->archive, ENOMEM,
430 "Can't allocate memory for Linkname");
431 return (ARCHIVE_FATAL);
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));
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;
447 memcpy(h + V7TAR_linkname_offset, p, copy_length);
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;
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;
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;
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;
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;
488 if (mytartype >= 0) {
489 h[V7TAR_typeflag_offset] = mytartype;
491 switch (archive_entry_filetype(entry)) {
492 case AE_IFREG: case AE_IFDIR:
495 h[V7TAR_typeflag_offset] = '2';
498 archive_set_error(&a->archive,
499 ARCHIVE_ERRNO_FILE_FORMAT,
500 "tar format cannot archive character device");
501 return (ARCHIVE_FAILED);
503 archive_set_error(&a->archive,
504 ARCHIVE_ERRNO_FILE_FORMAT,
505 "tar format cannot archive block device");
506 return (ARCHIVE_FAILED);
508 archive_set_error(&a->archive,
509 ARCHIVE_ERRNO_FILE_FORMAT,
510 "tar format cannot archive fifo");
511 return (ARCHIVE_FAILED);
513 archive_set_error(&a->archive,
514 ARCHIVE_ERRNO_FILE_FORMAT,
515 "tar format cannot archive socket");
516 return (ARCHIVE_FAILED);
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;
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';
536 * Format a number into a field, with some intelligence.
539 format_number(int64_t v, char *p, int s, int maxsize, int strict)
543 limit = ((int64_t)1 << (s*3));
545 /* "Strict" only permits octal values with proper termination. */
547 return (format_octal(v, p, s));
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
556 while (s <= maxsize) {
558 return (format_octal(v, p, s));
564 /* Base-256 can handle any number, positive or negative. */
565 return (format_256(v, p, maxsize));
569 * Format a number into the specified field using base-256.
572 format_256(int64_t v, char *p, int s)
576 *--p = (char)(v & 0xff);
579 *p |= 0x80; /* Set the base-256 marker bit. */
584 * Format a number into the specified field.
587 format_octal(int64_t v, char *p, int s)
593 /* Octal values can't be negative, so use 0. */
600 p += s; /* Start at the end and work backwards. */
602 *--p = (char)('0' + (v & 7));
609 /* If it overflowed, fill field with max value. */
617 archive_write_v7tar_close(struct archive_write *a)
619 return (__archive_write_nulls(a, 512*2));
623 archive_write_v7tar_free(struct archive_write *a)
627 v7tar = (struct v7tar *)a->format_data;
629 a->format_data = NULL;
634 archive_write_v7tar_finish_entry(struct archive_write *a)
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;
647 archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s)
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)