1248590Smm/*- 2248590Smm * Copyright (c) 2003-2007 Tim Kientzle 3248590Smm * Copyright (c) 2011-2012 Michihiro NAKAJIMA 4248590Smm * All rights reserved. 5248590Smm * 6248590Smm * Redistribution and use in source and binary forms, with or without 7248590Smm * modification, are permitted provided that the following conditions 8248590Smm * are met: 9248590Smm * 1. Redistributions of source code must retain the above copyright 10248590Smm * notice, this list of conditions and the following disclaimer. 11248590Smm * 2. Redistributions in binary form must reproduce the above copyright 12248590Smm * notice, this list of conditions and the following disclaimer in the 13248590Smm * documentation and/or other materials provided with the distribution. 14248590Smm * 15248590Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16248590Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17248590Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18248590Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19248590Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20248590Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21248590Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22248590Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23248590Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24248590Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25248590Smm */ 26248590Smm 27248590Smm#include "archive_platform.h" 28248590Smm__FBSDID("$FreeBSD$"); 29248590Smm 30248590Smm 31248590Smm#ifdef HAVE_ERRNO_H 32248590Smm#include <errno.h> 33248590Smm#endif 34248590Smm#include <stdio.h> 35248590Smm#ifdef HAVE_STDLIB_H 36248590Smm#include <stdlib.h> 37248590Smm#endif 38248590Smm#ifdef HAVE_STRING_H 39248590Smm#include <string.h> 40248590Smm#endif 41248590Smm 42248590Smm#include "archive.h" 43248590Smm#include "archive_entry.h" 44248590Smm#include "archive_entry_locale.h" 45248590Smm#include "archive_private.h" 46248590Smm#include "archive_write_private.h" 47248590Smm 48248590Smmstruct v7tar { 49248590Smm uint64_t entry_bytes_remaining; 50248590Smm uint64_t entry_padding; 51248590Smm 52248590Smm struct archive_string_conv *opt_sconv; 53248590Smm struct archive_string_conv *sconv_default; 54248590Smm int init_default_conversion; 55248590Smm}; 56248590Smm 57248590Smm/* 58248590Smm * Define structure of POSIX 'v7tar' tar header. 59248590Smm */ 60248590Smm#define V7TAR_name_offset 0 61248590Smm#define V7TAR_name_size 100 62248590Smm#define V7TAR_mode_offset 100 63248590Smm#define V7TAR_mode_size 6 64248590Smm#define V7TAR_mode_max_size 8 65248590Smm#define V7TAR_uid_offset 108 66248590Smm#define V7TAR_uid_size 6 67248590Smm#define V7TAR_uid_max_size 8 68248590Smm#define V7TAR_gid_offset 116 69248590Smm#define V7TAR_gid_size 6 70248590Smm#define V7TAR_gid_max_size 8 71248590Smm#define V7TAR_size_offset 124 72248590Smm#define V7TAR_size_size 11 73248590Smm#define V7TAR_size_max_size 12 74248590Smm#define V7TAR_mtime_offset 136 75248590Smm#define V7TAR_mtime_size 11 76248590Smm#define V7TAR_mtime_max_size 12 77248590Smm#define V7TAR_checksum_offset 148 78248590Smm#define V7TAR_checksum_size 8 79248590Smm#define V7TAR_typeflag_offset 156 80248590Smm#define V7TAR_typeflag_size 1 81248590Smm#define V7TAR_linkname_offset 157 82248590Smm#define V7TAR_linkname_size 100 83248590Smm#define V7TAR_padding_offset 257 84248590Smm#define V7TAR_padding_size 255 85248590Smm 86248590Smm/* 87248590Smm * A filled-in copy of the header for initialization. 88248590Smm */ 89248590Smmstatic const char template_header[] = { 90248590Smm /* name: 100 bytes */ 91248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 92248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 93248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 94248590Smm 0,0,0,0, 95248590Smm /* Mode, space-null termination: 8 bytes */ 96248590Smm '0','0','0','0','0','0', ' ','\0', 97248590Smm /* uid, space-null termination: 8 bytes */ 98248590Smm '0','0','0','0','0','0', ' ','\0', 99248590Smm /* gid, space-null termination: 8 bytes */ 100248590Smm '0','0','0','0','0','0', ' ','\0', 101248590Smm /* size, space termation: 12 bytes */ 102248590Smm '0','0','0','0','0','0','0','0','0','0','0', ' ', 103248590Smm /* mtime, space termation: 12 bytes */ 104248590Smm '0','0','0','0','0','0','0','0','0','0','0', ' ', 105248590Smm /* Initial checksum value: 8 spaces */ 106248590Smm ' ',' ',' ',' ',' ',' ',' ',' ', 107248590Smm /* Typeflag: 1 byte */ 108248590Smm 0, 109248590Smm /* Linkname: 100 bytes */ 110248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 111248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 112248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 113248590Smm 0,0,0,0, 114248590Smm /* Padding: 255 bytes */ 115248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 116248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 117248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 118248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 119248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 120248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 121248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 122248590Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0 123248590Smm}; 124248590Smm 125248590Smmstatic ssize_t archive_write_v7tar_data(struct archive_write *a, const void *buff, 126248590Smm size_t s); 127248590Smmstatic int archive_write_v7tar_free(struct archive_write *); 128248590Smmstatic int archive_write_v7tar_close(struct archive_write *); 129248590Smmstatic int archive_write_v7tar_finish_entry(struct archive_write *); 130248590Smmstatic int archive_write_v7tar_header(struct archive_write *, 131248590Smm struct archive_entry *entry); 132248590Smmstatic int archive_write_v7tar_options(struct archive_write *, 133248590Smm const char *, const char *); 134248590Smmstatic int format_256(int64_t, char *, int); 135248590Smmstatic int format_number(int64_t, char *, int size, int max, int strict); 136248590Smmstatic int format_octal(int64_t, char *, int); 137248590Smmstatic int format_header_v7tar(struct archive_write *, char h[512], 138248590Smm struct archive_entry *, int, struct archive_string_conv *); 139248590Smm 140248590Smm/* 141248590Smm * Set output format to 'v7tar' format. 142248590Smm */ 143248590Smmint 144248590Smmarchive_write_set_format_v7tar(struct archive *_a) 145248590Smm{ 146248590Smm struct archive_write *a = (struct archive_write *)_a; 147248590Smm struct v7tar *v7tar; 148248590Smm 149248590Smm archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 150248590Smm ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar"); 151248590Smm 152248590Smm /* If someone else was already registered, unregister them. */ 153248590Smm if (a->format_free != NULL) 154248590Smm (a->format_free)(a); 155248590Smm 156248590Smm /* Basic internal sanity test. */ 157248590Smm if (sizeof(template_header) != 512) { 158248590Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 159248590Smm "Internal: template_header wrong size: %zu should be 512", 160248590Smm sizeof(template_header)); 161248590Smm return (ARCHIVE_FATAL); 162248590Smm } 163248590Smm 164248590Smm v7tar = (struct v7tar *)malloc(sizeof(*v7tar)); 165248590Smm if (v7tar == NULL) { 166248590Smm archive_set_error(&a->archive, ENOMEM, 167248590Smm "Can't allocate v7tar data"); 168248590Smm return (ARCHIVE_FATAL); 169248590Smm } 170248590Smm memset(v7tar, 0, sizeof(*v7tar)); 171248590Smm a->format_data = v7tar; 172248590Smm a->format_name = "tar (non-POSIX)"; 173248590Smm a->format_options = archive_write_v7tar_options; 174248590Smm a->format_write_header = archive_write_v7tar_header; 175248590Smm a->format_write_data = archive_write_v7tar_data; 176248590Smm a->format_close = archive_write_v7tar_close; 177248590Smm a->format_free = archive_write_v7tar_free; 178248590Smm a->format_finish_entry = archive_write_v7tar_finish_entry; 179248590Smm a->archive.archive_format = ARCHIVE_FORMAT_TAR; 180248590Smm a->archive.archive_format_name = "tar (non-POSIX)"; 181248590Smm return (ARCHIVE_OK); 182248590Smm} 183248590Smm 184248590Smmstatic int 185248590Smmarchive_write_v7tar_options(struct archive_write *a, const char *key, 186248590Smm const char *val) 187248590Smm{ 188248590Smm struct v7tar *v7tar = (struct v7tar *)a->format_data; 189248590Smm int ret = ARCHIVE_FAILED; 190248590Smm 191248590Smm if (strcmp(key, "hdrcharset") == 0) { 192248590Smm if (val == NULL || val[0] == 0) 193248590Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 194248590Smm "%s: hdrcharset option needs a character-set name", 195248590Smm a->format_name); 196248590Smm else { 197248590Smm v7tar->opt_sconv = archive_string_conversion_to_charset( 198248590Smm &a->archive, val, 0); 199248590Smm if (v7tar->opt_sconv != NULL) 200248590Smm ret = ARCHIVE_OK; 201248590Smm else 202248590Smm ret = ARCHIVE_FATAL; 203248590Smm } 204248590Smm return (ret); 205248590Smm } 206248590Smm 207248590Smm /* Note: The "warn" return is just to inform the options 208248590Smm * supervisor that we didn't handle it. It will generate 209248590Smm * a suitable error if no one used this option. */ 210248590Smm return (ARCHIVE_WARN); 211248590Smm} 212248590Smm 213248590Smmstatic int 214248590Smmarchive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry) 215248590Smm{ 216248590Smm char buff[512]; 217248590Smm int ret, ret2; 218248590Smm struct v7tar *v7tar; 219248590Smm struct archive_entry *entry_main; 220248590Smm struct archive_string_conv *sconv; 221248590Smm 222248590Smm v7tar = (struct v7tar *)a->format_data; 223248590Smm 224248590Smm /* Setup default string conversion. */ 225248590Smm if (v7tar->opt_sconv == NULL) { 226248590Smm if (!v7tar->init_default_conversion) { 227248590Smm v7tar->sconv_default = 228248590Smm archive_string_default_conversion_for_write( 229248590Smm &(a->archive)); 230248590Smm v7tar->init_default_conversion = 1; 231248590Smm } 232248590Smm sconv = v7tar->sconv_default; 233248590Smm } else 234248590Smm sconv = v7tar->opt_sconv; 235248590Smm 236248590Smm /* Sanity check. */ 237248590Smm if (archive_entry_pathname(entry) == NULL) { 238248590Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 239248590Smm "Can't record entry in tar file without pathname"); 240248590Smm return (ARCHIVE_FAILED); 241248590Smm } 242248590Smm 243248590Smm /* Only regular files (not hardlinks) have data. */ 244248590Smm if (archive_entry_hardlink(entry) != NULL || 245248590Smm archive_entry_symlink(entry) != NULL || 246248590Smm !(archive_entry_filetype(entry) == AE_IFREG)) 247248590Smm archive_entry_set_size(entry, 0); 248248590Smm 249248590Smm if (AE_IFDIR == archive_entry_filetype(entry)) { 250248590Smm const char *p; 251248590Smm size_t path_length; 252248590Smm /* 253248590Smm * Ensure a trailing '/'. Modify the entry so 254248590Smm * the client sees the change. 255248590Smm */ 256248590Smm#if defined(_WIN32) && !defined(__CYGWIN__) 257248590Smm const wchar_t *wp; 258248590Smm 259248590Smm wp = archive_entry_pathname_w(entry); 260248590Smm if (wp != NULL && wp[wcslen(wp) -1] != L'/') { 261248590Smm struct archive_wstring ws; 262248590Smm 263248590Smm archive_string_init(&ws); 264248590Smm path_length = wcslen(wp); 265248590Smm if (archive_wstring_ensure(&ws, 266248590Smm path_length + 2) == NULL) { 267248590Smm archive_set_error(&a->archive, ENOMEM, 268248590Smm "Can't allocate v7tar data"); 269248590Smm archive_wstring_free(&ws); 270248590Smm return(ARCHIVE_FATAL); 271248590Smm } 272248590Smm /* Should we keep '\' ? */ 273248590Smm if (wp[path_length -1] == L'\\') 274248590Smm path_length--; 275248590Smm archive_wstrncpy(&ws, wp, path_length); 276248590Smm archive_wstrappend_wchar(&ws, L'/'); 277248590Smm archive_entry_copy_pathname_w(entry, ws.s); 278248590Smm archive_wstring_free(&ws); 279248590Smm p = NULL; 280248590Smm } else 281248590Smm#endif 282248590Smm p = archive_entry_pathname(entry); 283248590Smm /* 284248590Smm * On Windows, this is a backup operation just in 285248590Smm * case getting WCS failed. On POSIX, this is a 286248590Smm * normal operation. 287248590Smm */ 288248590Smm if (p != NULL && p[strlen(p) - 1] != '/') { 289248590Smm struct archive_string as; 290248590Smm 291248590Smm archive_string_init(&as); 292248590Smm path_length = strlen(p); 293248590Smm if (archive_string_ensure(&as, 294248590Smm path_length + 2) == NULL) { 295248590Smm archive_set_error(&a->archive, ENOMEM, 296248590Smm "Can't allocate v7tar data"); 297248590Smm archive_string_free(&as); 298248590Smm return(ARCHIVE_FATAL); 299248590Smm } 300248590Smm#if defined(_WIN32) && !defined(__CYGWIN__) 301248590Smm /* NOTE: This might break the pathname 302248590Smm * if the current code page is CP932 and 303248590Smm * the pathname includes a character '\' 304248590Smm * as a part of its multibyte pathname. */ 305248590Smm if (p[strlen(p) -1] == '\\') 306248590Smm path_length--; 307248590Smm else 308248590Smm#endif 309248590Smm archive_strncpy(&as, p, path_length); 310248590Smm archive_strappend_char(&as, '/'); 311248590Smm archive_entry_copy_pathname(entry, as.s); 312248590Smm archive_string_free(&as); 313248590Smm } 314248590Smm } 315248590Smm 316248590Smm#if defined(_WIN32) && !defined(__CYGWIN__) 317248590Smm /* Make sure the path separators in pahtname, hardlink and symlink 318248590Smm * are all slash '/', not the Windows path separator '\'. */ 319248590Smm entry_main = __la_win_entry_in_posix_pathseparator(entry); 320248590Smm if (entry_main == NULL) { 321248590Smm archive_set_error(&a->archive, ENOMEM, 322248590Smm "Can't allocate v7tar data"); 323248590Smm return(ARCHIVE_FATAL); 324248590Smm } 325248590Smm if (entry != entry_main) 326248590Smm entry = entry_main; 327248590Smm else 328248590Smm entry_main = NULL; 329248590Smm#else 330248590Smm entry_main = NULL; 331248590Smm#endif 332248590Smm ret = format_header_v7tar(a, buff, entry, 1, sconv); 333248590Smm if (ret < ARCHIVE_WARN) { 334248590Smm if (entry_main) 335248590Smm archive_entry_free(entry_main); 336248590Smm return (ret); 337248590Smm } 338248590Smm ret2 = __archive_write_output(a, buff, 512); 339248590Smm if (ret2 < ARCHIVE_WARN) { 340248590Smm if (entry_main) 341248590Smm archive_entry_free(entry_main); 342248590Smm return (ret2); 343248590Smm } 344248590Smm if (ret2 < ret) 345248590Smm ret = ret2; 346248590Smm 347248590Smm v7tar->entry_bytes_remaining = archive_entry_size(entry); 348248590Smm v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining); 349248590Smm if (entry_main) 350248590Smm archive_entry_free(entry_main); 351248590Smm return (ret); 352248590Smm} 353248590Smm 354248590Smm/* 355248590Smm * Format a basic 512-byte "v7tar" header. 356248590Smm * 357248590Smm * Returns -1 if format failed (due to field overflow). 358248590Smm * Note that this always formats as much of the header as possible. 359248590Smm * If "strict" is set to zero, it will extend numeric fields as 360248590Smm * necessary (overwriting terminators or using base-256 extensions). 361248590Smm * 362248590Smm */ 363248590Smmstatic int 364248590Smmformat_header_v7tar(struct archive_write *a, char h[512], 365248590Smm struct archive_entry *entry, int strict, 366248590Smm struct archive_string_conv *sconv) 367248590Smm{ 368248590Smm unsigned int checksum; 369248590Smm int i, r, ret; 370248590Smm size_t copy_length; 371248590Smm const char *p, *pp; 372248590Smm int mytartype; 373248590Smm 374248590Smm ret = 0; 375248590Smm mytartype = -1; 376248590Smm /* 377248590Smm * The "template header" already includes the "v7tar" 378248590Smm * signature, various end-of-field markers and other required 379248590Smm * elements. 380248590Smm */ 381248590Smm memcpy(h, &template_header, 512); 382248590Smm 383248590Smm /* 384248590Smm * Because the block is already null-filled, and strings 385248590Smm * are allowed to exactly fill their destination (without null), 386248590Smm * I use memcpy(dest, src, strlen()) here a lot to copy strings. 387248590Smm */ 388248590Smm r = archive_entry_pathname_l(entry, &pp, ©_length, sconv); 389248590Smm if (r != 0) { 390248590Smm if (errno == ENOMEM) { 391248590Smm archive_set_error(&a->archive, ENOMEM, 392248590Smm "Can't allocate memory for Pathname"); 393248590Smm return (ARCHIVE_FATAL); 394248590Smm } 395248590Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 396248590Smm "Can't translate pathname '%s' to %s", 397248590Smm pp, archive_string_conversion_charset_name(sconv)); 398248590Smm ret = ARCHIVE_WARN; 399248590Smm } 400248590Smm if (strict && copy_length < V7TAR_name_size) 401248590Smm memcpy(h + V7TAR_name_offset, pp, copy_length); 402248590Smm else if (!strict && copy_length <= V7TAR_name_size) 403248590Smm memcpy(h + V7TAR_name_offset, pp, copy_length); 404248590Smm else { 405248590Smm /* Prefix is too long. */ 406248590Smm archive_set_error(&a->archive, ENAMETOOLONG, 407248590Smm "Pathname too long"); 408248590Smm ret = ARCHIVE_FAILED; 409248590Smm } 410248590Smm 411248590Smm r = archive_entry_hardlink_l(entry, &p, ©_length, sconv); 412248590Smm if (r != 0) { 413248590Smm if (errno == ENOMEM) { 414248590Smm archive_set_error(&a->archive, ENOMEM, 415248590Smm "Can't allocate memory for Linkname"); 416248590Smm return (ARCHIVE_FATAL); 417248590Smm } 418248590Smm archive_set_error(&a->archive, 419248590Smm ARCHIVE_ERRNO_FILE_FORMAT, 420248590Smm "Can't translate linkname '%s' to %s", 421248590Smm p, archive_string_conversion_charset_name(sconv)); 422248590Smm ret = ARCHIVE_WARN; 423248590Smm } 424248590Smm if (copy_length > 0) 425248590Smm mytartype = '1'; 426248590Smm else { 427248590Smm r = archive_entry_symlink_l(entry, &p, ©_length, sconv); 428248590Smm if (r != 0) { 429248590Smm if (errno == ENOMEM) { 430248590Smm archive_set_error(&a->archive, ENOMEM, 431248590Smm "Can't allocate memory for Linkname"); 432248590Smm return (ARCHIVE_FATAL); 433248590Smm } 434248590Smm archive_set_error(&a->archive, 435248590Smm ARCHIVE_ERRNO_FILE_FORMAT, 436248590Smm "Can't translate linkname '%s' to %s", 437248590Smm p, archive_string_conversion_charset_name(sconv)); 438248590Smm ret = ARCHIVE_WARN; 439248590Smm } 440248590Smm } 441248590Smm if (copy_length > 0) { 442248590Smm if (copy_length >= V7TAR_linkname_size) { 443248590Smm archive_set_error(&a->archive, ENAMETOOLONG, 444248590Smm "Link contents too long"); 445248590Smm ret = ARCHIVE_FAILED; 446248590Smm copy_length = V7TAR_linkname_size; 447248590Smm } 448248590Smm memcpy(h + V7TAR_linkname_offset, p, copy_length); 449248590Smm } 450248590Smm 451248590Smm if (format_number(archive_entry_mode(entry) & 07777, 452248590Smm h + V7TAR_mode_offset, V7TAR_mode_size, 453248590Smm V7TAR_mode_max_size, strict)) { 454248590Smm archive_set_error(&a->archive, ERANGE, 455248590Smm "Numeric mode too large"); 456248590Smm ret = ARCHIVE_FAILED; 457248590Smm } 458248590Smm 459248590Smm if (format_number(archive_entry_uid(entry), 460248590Smm h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) { 461248590Smm archive_set_error(&a->archive, ERANGE, 462248590Smm "Numeric user ID too large"); 463248590Smm ret = ARCHIVE_FAILED; 464248590Smm } 465248590Smm 466248590Smm if (format_number(archive_entry_gid(entry), 467248590Smm h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) { 468248590Smm archive_set_error(&a->archive, ERANGE, 469248590Smm "Numeric group ID too large"); 470248590Smm ret = ARCHIVE_FAILED; 471248590Smm } 472248590Smm 473248590Smm if (format_number(archive_entry_size(entry), 474248590Smm h + V7TAR_size_offset, V7TAR_size_size, 475248590Smm V7TAR_size_max_size, strict)) { 476248590Smm archive_set_error(&a->archive, ERANGE, 477248590Smm "File size out of range"); 478248590Smm ret = ARCHIVE_FAILED; 479248590Smm } 480248590Smm 481248590Smm if (format_number(archive_entry_mtime(entry), 482248590Smm h + V7TAR_mtime_offset, V7TAR_mtime_size, 483248590Smm V7TAR_mtime_max_size, strict)) { 484248590Smm archive_set_error(&a->archive, ERANGE, 485248590Smm "File modification time too large"); 486248590Smm ret = ARCHIVE_FAILED; 487248590Smm } 488248590Smm 489248590Smm if (mytartype >= 0) { 490248590Smm h[V7TAR_typeflag_offset] = mytartype; 491248590Smm } else { 492248590Smm switch (archive_entry_filetype(entry)) { 493248590Smm case AE_IFREG: case AE_IFDIR: 494248590Smm break; 495248590Smm case AE_IFLNK: 496248590Smm h[V7TAR_typeflag_offset] = '2'; 497248590Smm break; 498248590Smm case AE_IFCHR: 499248590Smm archive_set_error(&a->archive, 500248590Smm ARCHIVE_ERRNO_FILE_FORMAT, 501248590Smm "tar format cannot archive character device"); 502248590Smm return (ARCHIVE_FAILED); 503248590Smm case AE_IFBLK: 504248590Smm archive_set_error(&a->archive, 505248590Smm ARCHIVE_ERRNO_FILE_FORMAT, 506248590Smm "tar format cannot archive block device"); 507248590Smm return (ARCHIVE_FAILED); 508248590Smm case AE_IFIFO: 509248590Smm archive_set_error(&a->archive, 510248590Smm ARCHIVE_ERRNO_FILE_FORMAT, 511248590Smm "tar format cannot archive fifo"); 512248590Smm return (ARCHIVE_FAILED); 513248590Smm case AE_IFSOCK: 514248590Smm archive_set_error(&a->archive, 515248590Smm ARCHIVE_ERRNO_FILE_FORMAT, 516248590Smm "tar format cannot archive socket"); 517248590Smm return (ARCHIVE_FAILED); 518248590Smm default: 519248590Smm archive_set_error(&a->archive, 520248590Smm ARCHIVE_ERRNO_FILE_FORMAT, 521248590Smm "tar format cannot archive this (mode=0%lo)", 522248590Smm (unsigned long)archive_entry_mode(entry)); 523248590Smm ret = ARCHIVE_FAILED; 524248590Smm } 525248590Smm } 526248590Smm 527248590Smm checksum = 0; 528248590Smm for (i = 0; i < 512; i++) 529248590Smm checksum += 255 & (unsigned int)h[i]; 530248590Smm format_octal(checksum, h + V7TAR_checksum_offset, 6); 531248590Smm /* Can't be pre-set in the template. */ 532248590Smm h[V7TAR_checksum_offset + 6] = '\0'; 533248590Smm return (ret); 534248590Smm} 535248590Smm 536248590Smm/* 537248590Smm * Format a number into a field, with some intelligence. 538248590Smm */ 539248590Smmstatic int 540248590Smmformat_number(int64_t v, char *p, int s, int maxsize, int strict) 541248590Smm{ 542248590Smm int64_t limit; 543248590Smm 544248590Smm limit = ((int64_t)1 << (s*3)); 545248590Smm 546248590Smm /* "Strict" only permits octal values with proper termination. */ 547248590Smm if (strict) 548248590Smm return (format_octal(v, p, s)); 549248590Smm 550248590Smm /* 551248590Smm * In non-strict mode, we allow the number to overwrite one or 552248590Smm * more bytes of the field termination. Even old tar 553248590Smm * implementations should be able to handle this with no 554248590Smm * problem. 555248590Smm */ 556248590Smm if (v >= 0) { 557248590Smm while (s <= maxsize) { 558248590Smm if (v < limit) 559248590Smm return (format_octal(v, p, s)); 560248590Smm s++; 561248590Smm limit <<= 3; 562248590Smm } 563248590Smm } 564248590Smm 565248590Smm /* Base-256 can handle any number, positive or negative. */ 566248590Smm return (format_256(v, p, maxsize)); 567248590Smm} 568248590Smm 569248590Smm/* 570248590Smm * Format a number into the specified field using base-256. 571248590Smm */ 572248590Smmstatic int 573248590Smmformat_256(int64_t v, char *p, int s) 574248590Smm{ 575248590Smm p += s; 576248590Smm while (s-- > 0) { 577248590Smm *--p = (char)(v & 0xff); 578248590Smm v >>= 8; 579248590Smm } 580248590Smm *p |= 0x80; /* Set the base-256 marker bit. */ 581248590Smm return (0); 582248590Smm} 583248590Smm 584248590Smm/* 585248590Smm * Format a number into the specified field. 586248590Smm */ 587248590Smmstatic int 588248590Smmformat_octal(int64_t v, char *p, int s) 589248590Smm{ 590248590Smm int len; 591248590Smm 592248590Smm len = s; 593248590Smm 594248590Smm /* Octal values can't be negative, so use 0. */ 595248590Smm if (v < 0) { 596248590Smm while (len-- > 0) 597248590Smm *p++ = '0'; 598248590Smm return (-1); 599248590Smm } 600248590Smm 601248590Smm p += s; /* Start at the end and work backwards. */ 602248590Smm while (s-- > 0) { 603248590Smm *--p = (char)('0' + (v & 7)); 604248590Smm v >>= 3; 605248590Smm } 606248590Smm 607248590Smm if (v == 0) 608248590Smm return (0); 609248590Smm 610248590Smm /* If it overflowed, fill field with max value. */ 611248590Smm while (len-- > 0) 612248590Smm *p++ = '7'; 613248590Smm 614248590Smm return (-1); 615248590Smm} 616248590Smm 617248590Smmstatic int 618248590Smmarchive_write_v7tar_close(struct archive_write *a) 619248590Smm{ 620248590Smm return (__archive_write_nulls(a, 512*2)); 621248590Smm} 622248590Smm 623248590Smmstatic int 624248590Smmarchive_write_v7tar_free(struct archive_write *a) 625248590Smm{ 626248590Smm struct v7tar *v7tar; 627248590Smm 628248590Smm v7tar = (struct v7tar *)a->format_data; 629248590Smm free(v7tar); 630248590Smm a->format_data = NULL; 631248590Smm return (ARCHIVE_OK); 632248590Smm} 633248590Smm 634248590Smmstatic int 635248590Smmarchive_write_v7tar_finish_entry(struct archive_write *a) 636248590Smm{ 637248590Smm struct v7tar *v7tar; 638248590Smm int ret; 639248590Smm 640248590Smm v7tar = (struct v7tar *)a->format_data; 641248590Smm ret = __archive_write_nulls(a, 642248590Smm (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding)); 643248590Smm v7tar->entry_bytes_remaining = v7tar->entry_padding = 0; 644248590Smm return (ret); 645248590Smm} 646248590Smm 647248590Smmstatic ssize_t 648248590Smmarchive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s) 649248590Smm{ 650248590Smm struct v7tar *v7tar; 651248590Smm int ret; 652248590Smm 653248590Smm v7tar = (struct v7tar *)a->format_data; 654248590Smm if (s > v7tar->entry_bytes_remaining) 655248590Smm s = (size_t)v7tar->entry_bytes_remaining; 656248590Smm ret = __archive_write_output(a, buff, s); 657248590Smm v7tar->entry_bytes_remaining -= s; 658248590Smm if (ret != ARCHIVE_OK) 659248590Smm return (ret); 660248590Smm return (s); 661248590Smm} 662