1231200Smm/*- 2231200Smm * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). 3231200Smm * Author: Jonas Gastal <jgastal@profusion.mobi> 4232153Smm * Copyright (c) 2011-2012 Michihiro NAKAJIMA 5231200Smm * 6231200Smm * All rights reserved. 7231200Smm * 8231200Smm * Redistribution and use in source and binary forms, with or without 9231200Smm * modification, are permitted provided that the following conditions 10231200Smm * are met: 11231200Smm * 1. Redistributions of source code must retain the above copyright 12231200Smm * notice, this list of conditions and the following disclaimer. 13231200Smm * 2. Redistributions in binary form must reproduce the above copyright 14231200Smm * notice, this list of conditions and the following disclaimer in the 15231200Smm * documentation and/or other materials provided with the distribution. 16231200Smm * 17231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 18231200Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19231200Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20231200Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 21231200Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22231200Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23231200Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24231200Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25231200Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26231200Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27231200Smm */ 28231200Smm 29231200Smm#include "archive_platform.h" 30231200Smm__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_gnu_tar.c 191579 2009-04-27 18:35:03Z gastal $"); 31231200Smm 32231200Smm 33231200Smm#ifdef HAVE_ERRNO_H 34231200Smm#include <errno.h> 35231200Smm#endif 36231200Smm#include <stdio.h> 37231200Smm#ifdef HAVE_STDLIB_H 38231200Smm#include <stdlib.h> 39231200Smm#endif 40231200Smm#ifdef HAVE_STRING_H 41231200Smm#include <string.h> 42231200Smm#endif 43231200Smm 44231200Smm#include "archive.h" 45231200Smm#include "archive_entry.h" 46231200Smm#include "archive_entry_locale.h" 47231200Smm#include "archive_private.h" 48231200Smm#include "archive_write_private.h" 49231200Smm 50231200Smmstruct gnutar { 51231200Smm uint64_t entry_bytes_remaining; 52231200Smm uint64_t entry_padding; 53231200Smm const char * linkname; 54231200Smm size_t linkname_length; 55231200Smm const char * pathname; 56231200Smm size_t pathname_length; 57231200Smm const char * uname; 58231200Smm size_t uname_length; 59231200Smm const char * gname; 60231200Smm size_t gname_length; 61231200Smm struct archive_string_conv *opt_sconv; 62231200Smm struct archive_string_conv *sconv_default; 63231200Smm int init_default_conversion; 64231200Smm}; 65231200Smm 66231200Smm/* 67231200Smm * Define structure of GNU tar header. 68231200Smm */ 69231200Smm#define GNUTAR_name_offset 0 70231200Smm#define GNUTAR_name_size 100 71231200Smm#define GNUTAR_mode_offset 100 72231200Smm#define GNUTAR_mode_size 7 73231200Smm#define GNUTAR_mode_max_size 8 74231200Smm#define GNUTAR_uid_offset 108 75231200Smm#define GNUTAR_uid_size 7 76231200Smm#define GNUTAR_uid_max_size 8 77231200Smm#define GNUTAR_gid_offset 116 78231200Smm#define GNUTAR_gid_size 7 79231200Smm#define GNUTAR_gid_max_size 8 80231200Smm#define GNUTAR_size_offset 124 81231200Smm#define GNUTAR_size_size 11 82231200Smm#define GNUTAR_size_max_size 12 83231200Smm#define GNUTAR_mtime_offset 136 84231200Smm#define GNUTAR_mtime_size 11 85231200Smm#define GNUTAR_mtime_max_size 11 86231200Smm#define GNUTAR_checksum_offset 148 87231200Smm#define GNUTAR_checksum_size 8 88231200Smm#define GNUTAR_typeflag_offset 156 89231200Smm#define GNUTAR_typeflag_size 1 90231200Smm#define GNUTAR_linkname_offset 157 91231200Smm#define GNUTAR_linkname_size 100 92231200Smm#define GNUTAR_magic_offset 257 93231200Smm#define GNUTAR_magic_size 6 94231200Smm#define GNUTAR_version_offset 263 95231200Smm#define GNUTAR_version_size 2 96231200Smm#define GNUTAR_uname_offset 265 97231200Smm#define GNUTAR_uname_size 32 98231200Smm#define GNUTAR_gname_offset 297 99231200Smm#define GNUTAR_gname_size 32 100231200Smm#define GNUTAR_rdevmajor_offset 329 101231200Smm#define GNUTAR_rdevmajor_size 6 102231200Smm#define GNUTAR_rdevmajor_max_size 8 103231200Smm#define GNUTAR_rdevminor_offset 337 104231200Smm#define GNUTAR_rdevminor_size 6 105231200Smm#define GNUTAR_rdevminor_max_size 8 106231200Smm 107231200Smm/* 108231200Smm * A filled-in copy of the header for initialization. 109231200Smm */ 110231200Smmstatic const char template_header[] = { 111231200Smm /* name: 100 bytes */ 112231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 113231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 114231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 115231200Smm 0,0,0,0, 116231200Smm /* Mode, null termination: 8 bytes */ 117231200Smm '0','0','0','0','0','0', '0','\0', 118231200Smm /* uid, null termination: 8 bytes */ 119231200Smm '0','0','0','0','0','0', '0','\0', 120231200Smm /* gid, null termination: 8 bytes */ 121231200Smm '0','0','0','0','0','0', '0','\0', 122231200Smm /* size, space termation: 12 bytes */ 123231200Smm '0','0','0','0','0','0','0','0','0','0','0', '\0', 124231200Smm /* mtime, space termation: 12 bytes */ 125231200Smm '0','0','0','0','0','0','0','0','0','0','0', '\0', 126231200Smm /* Initial checksum value: 8 spaces */ 127231200Smm ' ',' ',' ',' ',' ',' ',' ',' ', 128231200Smm /* Typeflag: 1 byte */ 129231200Smm '0', /* '0' = regular file */ 130231200Smm /* Linkname: 100 bytes */ 131231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 132231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 133231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 134231200Smm 0,0,0,0, 135231200Smm /* Magic: 8 bytes */ 136231200Smm 'u','s','t','a','r',' ', ' ','\0', 137231200Smm /* Uname: 32 bytes */ 138231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 139231200Smm /* Gname: 32 bytes */ 140231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 141231200Smm /* rdevmajor + null padding: 8 bytes */ 142231200Smm '\0','\0','\0','\0','\0','\0', '\0','\0', 143231200Smm /* rdevminor + null padding: 8 bytes */ 144231200Smm '\0','\0','\0','\0','\0','\0', '\0','\0', 145231200Smm /* Padding: 167 bytes */ 146231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 147231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 148231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 149231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 150231200Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 151231200Smm 0,0,0,0,0,0,0 152231200Smm}; 153231200Smm 154231200Smmstatic int archive_write_gnutar_options(struct archive_write *, 155231200Smm const char *, const char *); 156231200Smmstatic int archive_format_gnutar_header(struct archive_write *, char h[512], 157231200Smm struct archive_entry *, int tartype); 158231200Smmstatic int archive_write_gnutar_header(struct archive_write *, 159231200Smm struct archive_entry *entry); 160231200Smmstatic ssize_t archive_write_gnutar_data(struct archive_write *a, const void *buff, 161231200Smm size_t s); 162231200Smmstatic int archive_write_gnutar_free(struct archive_write *); 163231200Smmstatic int archive_write_gnutar_close(struct archive_write *); 164231200Smmstatic int archive_write_gnutar_finish_entry(struct archive_write *); 165231200Smmstatic int format_256(int64_t, char *, int); 166231200Smmstatic int format_number(int64_t, char *, int size, int maxsize); 167231200Smmstatic int format_octal(int64_t, char *, int); 168231200Smm 169231200Smm/* 170231200Smm * Set output format to 'GNU tar' format. 171231200Smm */ 172231200Smmint 173231200Smmarchive_write_set_format_gnutar(struct archive *_a) 174231200Smm{ 175231200Smm struct archive_write *a = (struct archive_write *)_a; 176231200Smm struct gnutar *gnutar; 177231200Smm 178231200Smm gnutar = (struct gnutar *)calloc(1, sizeof(*gnutar)); 179231200Smm if (gnutar == NULL) { 180232153Smm archive_set_error(&a->archive, ENOMEM, 181232153Smm "Can't allocate gnutar data"); 182231200Smm return (ARCHIVE_FATAL); 183231200Smm } 184231200Smm a->format_data = gnutar; 185231200Smm a->format_name = "gnutar"; 186231200Smm a->format_options = archive_write_gnutar_options; 187231200Smm a->format_write_header = archive_write_gnutar_header; 188231200Smm a->format_write_data = archive_write_gnutar_data; 189231200Smm a->format_close = archive_write_gnutar_close; 190231200Smm a->format_free = archive_write_gnutar_free; 191231200Smm a->format_finish_entry = archive_write_gnutar_finish_entry; 192231200Smm a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR; 193231200Smm a->archive.archive_format_name = "GNU tar"; 194231200Smm return (ARCHIVE_OK); 195231200Smm} 196231200Smm 197231200Smmstatic int 198231200Smmarchive_write_gnutar_options(struct archive_write *a, const char *key, 199231200Smm const char *val) 200231200Smm{ 201231200Smm struct gnutar *gnutar = (struct gnutar *)a->format_data; 202231200Smm int ret = ARCHIVE_FAILED; 203231200Smm 204231200Smm if (strcmp(key, "hdrcharset") == 0) { 205231200Smm if (val == NULL || val[0] == 0) 206231200Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 207231200Smm "%s: hdrcharset option needs a character-set name", 208231200Smm a->format_name); 209231200Smm else { 210231200Smm gnutar->opt_sconv = archive_string_conversion_to_charset( 211231200Smm &a->archive, val, 0); 212231200Smm if (gnutar->opt_sconv != NULL) 213231200Smm ret = ARCHIVE_OK; 214231200Smm else 215231200Smm ret = ARCHIVE_FATAL; 216231200Smm } 217232153Smm return (ret); 218232153Smm } 219231200Smm 220232153Smm /* Note: The "warn" return is just to inform the options 221232153Smm * supervisor that we didn't handle it. It will generate 222232153Smm * a suitable error if no one used this option. */ 223232153Smm return (ARCHIVE_WARN); 224231200Smm} 225231200Smm 226231200Smmstatic int 227231200Smmarchive_write_gnutar_close(struct archive_write *a) 228231200Smm{ 229231200Smm return (__archive_write_nulls(a, 512*2)); 230231200Smm} 231231200Smm 232231200Smmstatic int 233231200Smmarchive_write_gnutar_free(struct archive_write *a) 234231200Smm{ 235231200Smm struct gnutar *gnutar; 236231200Smm 237231200Smm gnutar = (struct gnutar *)a->format_data; 238231200Smm free(gnutar); 239231200Smm a->format_data = NULL; 240231200Smm return (ARCHIVE_OK); 241231200Smm} 242231200Smm 243231200Smmstatic int 244231200Smmarchive_write_gnutar_finish_entry(struct archive_write *a) 245231200Smm{ 246231200Smm struct gnutar *gnutar; 247231200Smm int ret; 248231200Smm 249231200Smm gnutar = (struct gnutar *)a->format_data; 250238856Smm ret = __archive_write_nulls(a, (size_t) 251238856Smm (gnutar->entry_bytes_remaining + gnutar->entry_padding)); 252231200Smm gnutar->entry_bytes_remaining = gnutar->entry_padding = 0; 253231200Smm return (ret); 254231200Smm} 255231200Smm 256231200Smmstatic ssize_t 257231200Smmarchive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s) 258231200Smm{ 259231200Smm struct gnutar *gnutar; 260231200Smm int ret; 261231200Smm 262231200Smm gnutar = (struct gnutar *)a->format_data; 263231200Smm if (s > gnutar->entry_bytes_remaining) 264238856Smm s = (size_t)gnutar->entry_bytes_remaining; 265231200Smm ret = __archive_write_output(a, buff, s); 266231200Smm gnutar->entry_bytes_remaining -= s; 267231200Smm if (ret != ARCHIVE_OK) 268231200Smm return (ret); 269231200Smm return (s); 270231200Smm} 271231200Smm 272231200Smmstatic int 273231200Smmarchive_write_gnutar_header(struct archive_write *a, 274231200Smm struct archive_entry *entry) 275231200Smm{ 276231200Smm char buff[512]; 277231200Smm int r, ret, ret2 = ARCHIVE_OK; 278231200Smm int tartype; 279231200Smm struct gnutar *gnutar; 280231200Smm struct archive_string_conv *sconv; 281232153Smm struct archive_entry *entry_main; 282231200Smm 283231200Smm gnutar = (struct gnutar *)a->format_data; 284231200Smm 285231200Smm /* Setup default string conversion. */ 286231200Smm if (gnutar->opt_sconv == NULL) { 287231200Smm if (!gnutar->init_default_conversion) { 288231200Smm gnutar->sconv_default = 289231200Smm archive_string_default_conversion_for_write( 290231200Smm &(a->archive)); 291231200Smm gnutar->init_default_conversion = 1; 292231200Smm } 293231200Smm sconv = gnutar->sconv_default; 294231200Smm } else 295231200Smm sconv = gnutar->opt_sconv; 296231200Smm 297231200Smm /* Only regular files (not hardlinks) have data. */ 298231200Smm if (archive_entry_hardlink(entry) != NULL || 299231200Smm archive_entry_symlink(entry) != NULL || 300231200Smm !(archive_entry_filetype(entry) == AE_IFREG)) 301231200Smm archive_entry_set_size(entry, 0); 302231200Smm 303231200Smm if (AE_IFDIR == archive_entry_filetype(entry)) { 304231200Smm const char *p; 305232153Smm size_t path_length; 306231200Smm /* 307231200Smm * Ensure a trailing '/'. Modify the entry so 308231200Smm * the client sees the change. 309231200Smm */ 310232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 311232153Smm const wchar_t *wp; 312232153Smm 313232153Smm wp = archive_entry_pathname_w(entry); 314232153Smm if (wp != NULL && wp[wcslen(wp) -1] != L'/') { 315232153Smm struct archive_wstring ws; 316232153Smm 317232153Smm archive_string_init(&ws); 318232153Smm path_length = wcslen(wp); 319232153Smm if (archive_wstring_ensure(&ws, 320232153Smm path_length + 2) == NULL) { 321231200Smm archive_set_error(&a->archive, ENOMEM, 322232153Smm "Can't allocate ustar data"); 323232153Smm archive_wstring_free(&ws); 324231200Smm return(ARCHIVE_FATAL); 325231200Smm } 326232153Smm /* Should we keep '\' ? */ 327232153Smm if (wp[path_length -1] == L'\\') 328232153Smm path_length--; 329232153Smm archive_wstrncpy(&ws, wp, path_length); 330232153Smm archive_wstrappend_wchar(&ws, L'/'); 331232153Smm archive_entry_copy_pathname_w(entry, ws.s); 332232153Smm archive_wstring_free(&ws); 333232153Smm p = NULL; 334232153Smm } else 335232153Smm#endif 336232153Smm p = archive_entry_pathname(entry); 337232153Smm /* 338232153Smm * On Windows, this is a backup operation just in 339232153Smm * case getting WCS failed. On POSIX, this is a 340232153Smm * normal operation. 341232153Smm */ 342232153Smm if (p != NULL && p[strlen(p) - 1] != '/') { 343232153Smm struct archive_string as; 344232153Smm 345232153Smm archive_string_init(&as); 346232153Smm path_length = strlen(p); 347232153Smm if (archive_string_ensure(&as, 348232153Smm path_length + 2) == NULL) { 349232153Smm archive_set_error(&a->archive, ENOMEM, 350232153Smm "Can't allocate ustar data"); 351232153Smm archive_string_free(&as); 352232153Smm return(ARCHIVE_FATAL); 353232153Smm } 354232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 355232153Smm /* NOTE: This might break the pathname 356232153Smm * if the current code page is CP932 and 357232153Smm * the pathname includes a character '\' 358232153Smm * as a part of its multibyte pathname. */ 359232153Smm if (p[strlen(p) -1] == '\\') 360232153Smm path_length--; 361232153Smm else 362232153Smm#endif 363232153Smm archive_strncpy(&as, p, path_length); 364232153Smm archive_strappend_char(&as, '/'); 365232153Smm archive_entry_copy_pathname(entry, as.s); 366232153Smm archive_string_free(&as); 367231200Smm } 368231200Smm } 369231200Smm 370232153Smm#if defined(_WIN32) && !defined(__CYGWIN__) 371232153Smm /* Make sure the path separators in pahtname, hardlink and symlink 372232153Smm * are all slash '/', not the Windows path separator '\'. */ 373232153Smm entry_main = __la_win_entry_in_posix_pathseparator(entry); 374232153Smm if (entry_main == NULL) { 375232153Smm archive_set_error(&a->archive, ENOMEM, 376232153Smm "Can't allocate ustar data"); 377232153Smm return(ARCHIVE_FATAL); 378232153Smm } 379232153Smm if (entry != entry_main) 380232153Smm entry = entry_main; 381232153Smm else 382232153Smm entry_main = NULL; 383232153Smm#else 384232153Smm entry_main = NULL; 385232153Smm#endif 386231200Smm r = archive_entry_pathname_l(entry, &(gnutar->pathname), 387231200Smm &(gnutar->pathname_length), sconv); 388231200Smm if (r != 0) { 389231200Smm if (errno == ENOMEM) { 390231200Smm archive_set_error(&a->archive, ENOMEM, 391231200Smm "Can't allocate memory for Pathame"); 392232153Smm ret = ARCHIVE_FATAL; 393232153Smm goto exit_write_header; 394231200Smm } 395231200Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 396231200Smm "Can't translate pathname '%s' to %s", 397231200Smm archive_entry_pathname(entry), 398231200Smm archive_string_conversion_charset_name(sconv)); 399231200Smm ret2 = ARCHIVE_WARN; 400231200Smm } 401231200Smm r = archive_entry_uname_l(entry, &(gnutar->uname), 402231200Smm &(gnutar->uname_length), sconv); 403231200Smm if (r != 0) { 404231200Smm if (errno == ENOMEM) { 405231200Smm archive_set_error(&a->archive, ENOMEM, 406231200Smm "Can't allocate memory for Uname"); 407232153Smm ret = ARCHIVE_FATAL; 408232153Smm goto exit_write_header; 409231200Smm } 410231200Smm archive_set_error(&a->archive, 411231200Smm ARCHIVE_ERRNO_FILE_FORMAT, 412231200Smm "Can't translate uname '%s' to %s", 413231200Smm archive_entry_uname(entry), 414231200Smm archive_string_conversion_charset_name(sconv)); 415231200Smm ret2 = ARCHIVE_WARN; 416231200Smm } 417231200Smm r = archive_entry_gname_l(entry, &(gnutar->gname), 418231200Smm &(gnutar->gname_length), sconv); 419231200Smm if (r != 0) { 420231200Smm if (errno == ENOMEM) { 421231200Smm archive_set_error(&a->archive, ENOMEM, 422231200Smm "Can't allocate memory for Gname"); 423232153Smm ret = ARCHIVE_FATAL; 424232153Smm goto exit_write_header; 425231200Smm } 426231200Smm archive_set_error(&a->archive, 427231200Smm ARCHIVE_ERRNO_FILE_FORMAT, 428231200Smm "Can't translate gname '%s' to %s", 429231200Smm archive_entry_gname(entry), 430231200Smm archive_string_conversion_charset_name(sconv)); 431231200Smm ret2 = ARCHIVE_WARN; 432231200Smm } 433231200Smm 434231200Smm /* If linkname is longer than 100 chars we need to add a 'K' header. */ 435231200Smm r = archive_entry_hardlink_l(entry, &(gnutar->linkname), 436231200Smm &(gnutar->linkname_length), sconv); 437231200Smm if (r != 0) { 438231200Smm if (errno == ENOMEM) { 439231200Smm archive_set_error(&a->archive, ENOMEM, 440231200Smm "Can't allocate memory for Linkname"); 441232153Smm ret = ARCHIVE_FATAL; 442232153Smm goto exit_write_header; 443231200Smm } 444231200Smm archive_set_error(&a->archive, 445231200Smm ARCHIVE_ERRNO_FILE_FORMAT, 446231200Smm "Can't translate linkname '%s' to %s", 447231200Smm archive_entry_hardlink(entry), 448231200Smm archive_string_conversion_charset_name(sconv)); 449231200Smm ret2 = ARCHIVE_WARN; 450231200Smm } 451231200Smm if (gnutar->linkname_length == 0) { 452231200Smm r = archive_entry_symlink_l(entry, &(gnutar->linkname), 453231200Smm &(gnutar->linkname_length), sconv); 454231200Smm if (r != 0) { 455231200Smm if (errno == ENOMEM) { 456231200Smm archive_set_error(&a->archive, ENOMEM, 457231200Smm "Can't allocate memory for Linkname"); 458232153Smm ret = ARCHIVE_FATAL; 459232153Smm goto exit_write_header; 460231200Smm } 461231200Smm archive_set_error(&a->archive, 462231200Smm ARCHIVE_ERRNO_FILE_FORMAT, 463231200Smm "Can't translate linkname '%s' to %s", 464231200Smm archive_entry_hardlink(entry), 465231200Smm archive_string_conversion_charset_name(sconv)); 466231200Smm ret2 = ARCHIVE_WARN; 467231200Smm } 468231200Smm } 469231200Smm if (gnutar->linkname_length > GNUTAR_linkname_size) { 470231200Smm size_t todo = gnutar->linkname_length; 471231200Smm struct archive_entry *temp = archive_entry_new2(&a->archive); 472231200Smm 473231200Smm /* Uname/gname here don't really matter since no one reads them; 474231200Smm * these are the values that GNU tar happens to use on FreeBSD. */ 475231200Smm archive_entry_set_uname(temp, "root"); 476231200Smm archive_entry_set_gname(temp, "wheel"); 477231200Smm 478231200Smm archive_entry_set_pathname(temp, "././@LongLink"); 479231200Smm archive_entry_set_size(temp, gnutar->linkname_length + 1); 480231200Smm ret = archive_format_gnutar_header(a, buff, temp, 'K'); 481231200Smm if (ret < ARCHIVE_WARN) 482232153Smm goto exit_write_header; 483231200Smm ret = __archive_write_output(a, buff, 512); 484231200Smm if(ret < ARCHIVE_WARN) 485232153Smm goto exit_write_header; 486231200Smm archive_entry_free(temp); 487231200Smm /* Write as many 512 bytes blocks as needed to write full name. */ 488231200Smm ret = __archive_write_output(a, gnutar->linkname, todo); 489231200Smm if(ret < ARCHIVE_WARN) 490232153Smm goto exit_write_header; 491231200Smm ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo)); 492231200Smm if (ret < ARCHIVE_WARN) 493232153Smm goto exit_write_header; 494231200Smm } 495231200Smm 496231200Smm /* If pathname is longer than 100 chars we need to add an 'L' header. */ 497231200Smm if (gnutar->pathname_length > GNUTAR_name_size) { 498231200Smm const char *pathname = gnutar->pathname; 499231200Smm size_t todo = gnutar->pathname_length; 500231200Smm struct archive_entry *temp = archive_entry_new2(&a->archive); 501231200Smm 502231200Smm /* Uname/gname here don't really matter since no one reads them; 503231200Smm * these are the values that GNU tar happens to use on FreeBSD. */ 504231200Smm archive_entry_set_uname(temp, "root"); 505231200Smm archive_entry_set_gname(temp, "wheel"); 506231200Smm 507231200Smm archive_entry_set_pathname(temp, "././@LongLink"); 508231200Smm archive_entry_set_size(temp, gnutar->pathname_length + 1); 509231200Smm ret = archive_format_gnutar_header(a, buff, temp, 'L'); 510231200Smm if (ret < ARCHIVE_WARN) 511232153Smm goto exit_write_header; 512231200Smm ret = __archive_write_output(a, buff, 512); 513231200Smm if(ret < ARCHIVE_WARN) 514232153Smm goto exit_write_header; 515231200Smm archive_entry_free(temp); 516231200Smm /* Write as many 512 bytes blocks as needed to write full name. */ 517231200Smm ret = __archive_write_output(a, pathname, todo); 518231200Smm if(ret < ARCHIVE_WARN) 519232153Smm goto exit_write_header; 520231200Smm ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo)); 521231200Smm if (ret < ARCHIVE_WARN) 522232153Smm goto exit_write_header; 523231200Smm } 524231200Smm 525231200Smm if (archive_entry_hardlink(entry) != NULL) { 526231200Smm tartype = '1'; 527231200Smm } else 528231200Smm switch (archive_entry_filetype(entry)) { 529231200Smm case AE_IFREG: tartype = '0' ; break; 530231200Smm case AE_IFLNK: tartype = '2' ; break; 531231200Smm case AE_IFCHR: tartype = '3' ; break; 532231200Smm case AE_IFBLK: tartype = '4' ; break; 533231200Smm case AE_IFDIR: tartype = '5' ; break; 534231200Smm case AE_IFIFO: tartype = '6' ; break; 535231200Smm case AE_IFSOCK: 536231200Smm archive_set_error(&a->archive, 537231200Smm ARCHIVE_ERRNO_FILE_FORMAT, 538231200Smm "tar format cannot archive socket"); 539232153Smm ret = ARCHIVE_FAILED; 540232153Smm goto exit_write_header; 541231200Smm default: 542231200Smm archive_set_error(&a->archive, 543231200Smm ARCHIVE_ERRNO_FILE_FORMAT, 544231200Smm "tar format cannot archive this (mode=0%lo)", 545231200Smm (unsigned long)archive_entry_mode(entry)); 546232153Smm ret = ARCHIVE_FAILED; 547232153Smm goto exit_write_header; 548231200Smm } 549231200Smm 550231200Smm ret = archive_format_gnutar_header(a, buff, entry, tartype); 551231200Smm if (ret < ARCHIVE_WARN) 552232153Smm goto exit_write_header; 553231200Smm if (ret2 < ret) 554231200Smm ret = ret2; 555231200Smm ret2 = __archive_write_output(a, buff, 512); 556232153Smm if (ret2 < ARCHIVE_WARN) { 557232153Smm ret = ret2; 558232153Smm goto exit_write_header; 559232153Smm } 560231200Smm if (ret2 < ret) 561231200Smm ret = ret2; 562231200Smm 563231200Smm gnutar->entry_bytes_remaining = archive_entry_size(entry); 564231200Smm gnutar->entry_padding = 0x1ff & (-(int64_t)gnutar->entry_bytes_remaining); 565232153Smmexit_write_header: 566232153Smm if (entry_main) 567232153Smm archive_entry_free(entry_main); 568231200Smm return (ret); 569231200Smm} 570231200Smm 571231200Smmstatic int 572231200Smmarchive_format_gnutar_header(struct archive_write *a, char h[512], 573231200Smm struct archive_entry *entry, int tartype) 574231200Smm{ 575231200Smm unsigned int checksum; 576231200Smm int i, ret; 577231200Smm size_t copy_length; 578231200Smm const char *p; 579231200Smm struct gnutar *gnutar; 580231200Smm 581231200Smm gnutar = (struct gnutar *)a->format_data; 582231200Smm 583231200Smm ret = 0; 584231200Smm 585231200Smm /* 586231200Smm * The "template header" already includes the signature, 587231200Smm * various end-of-field markers, and other required elements. 588231200Smm */ 589231200Smm memcpy(h, &template_header, 512); 590231200Smm 591231200Smm /* 592231200Smm * Because the block is already null-filled, and strings 593231200Smm * are allowed to exactly fill their destination (without null), 594231200Smm * I use memcpy(dest, src, strlen()) here a lot to copy strings. 595231200Smm */ 596231200Smm 597231200Smm if (tartype == 'K' || tartype == 'L') { 598231200Smm p = archive_entry_pathname(entry); 599231200Smm copy_length = strlen(p); 600231200Smm } else { 601231200Smm p = gnutar->pathname; 602231200Smm copy_length = gnutar->pathname_length; 603231200Smm } 604231200Smm if (copy_length > GNUTAR_name_size) 605231200Smm copy_length = GNUTAR_name_size; 606231200Smm memcpy(h + GNUTAR_name_offset, p, copy_length); 607231200Smm 608231200Smm if ((copy_length = gnutar->linkname_length) > 0) { 609231200Smm if (copy_length > GNUTAR_linkname_size) 610231200Smm copy_length = GNUTAR_linkname_size; 611231200Smm memcpy(h + GNUTAR_linkname_offset, gnutar->linkname, 612231200Smm copy_length); 613231200Smm } 614231200Smm 615231200Smm /* TODO: How does GNU tar handle unames longer than GNUTAR_uname_size? */ 616231200Smm if (tartype == 'K' || tartype == 'L') { 617231200Smm p = archive_entry_uname(entry); 618231200Smm copy_length = strlen(p); 619231200Smm } else { 620231200Smm p = gnutar->uname; 621231200Smm copy_length = gnutar->uname_length; 622231200Smm } 623231200Smm if (copy_length > 0) { 624231200Smm if (copy_length > GNUTAR_uname_size) 625231200Smm copy_length = GNUTAR_uname_size; 626231200Smm memcpy(h + GNUTAR_uname_offset, p, copy_length); 627231200Smm } 628231200Smm 629231200Smm /* TODO: How does GNU tar handle gnames longer than GNUTAR_gname_size? */ 630231200Smm if (tartype == 'K' || tartype == 'L') { 631231200Smm p = archive_entry_gname(entry); 632231200Smm copy_length = strlen(p); 633231200Smm } else { 634231200Smm p = gnutar->gname; 635231200Smm copy_length = gnutar->gname_length; 636231200Smm } 637231200Smm if (copy_length > 0) { 638231200Smm if (strlen(p) > GNUTAR_gname_size) 639231200Smm copy_length = GNUTAR_gname_size; 640231200Smm memcpy(h + GNUTAR_gname_offset, p, copy_length); 641231200Smm } 642231200Smm 643231200Smm /* By truncating the mode here, we ensure it always fits. */ 644231200Smm format_octal(archive_entry_mode(entry) & 07777, 645231200Smm h + GNUTAR_mode_offset, GNUTAR_mode_size); 646231200Smm 647231200Smm /* TODO: How does GNU tar handle large UIDs? */ 648231200Smm if (format_octal(archive_entry_uid(entry), 649231200Smm h + GNUTAR_uid_offset, GNUTAR_uid_size)) { 650231200Smm archive_set_error(&a->archive, ERANGE, 651231200Smm "Numeric user ID %jd too large", 652231200Smm (intmax_t)archive_entry_uid(entry)); 653231200Smm ret = ARCHIVE_FAILED; 654231200Smm } 655231200Smm 656231200Smm /* TODO: How does GNU tar handle large GIDs? */ 657231200Smm if (format_octal(archive_entry_gid(entry), 658231200Smm h + GNUTAR_gid_offset, GNUTAR_gid_size)) { 659231200Smm archive_set_error(&a->archive, ERANGE, 660231200Smm "Numeric group ID %jd too large", 661231200Smm (intmax_t)archive_entry_gid(entry)); 662231200Smm ret = ARCHIVE_FAILED; 663231200Smm } 664231200Smm 665231200Smm /* GNU tar supports base-256 here, so should never overflow. */ 666231200Smm if (format_number(archive_entry_size(entry), h + GNUTAR_size_offset, 667231200Smm GNUTAR_size_size, GNUTAR_size_max_size)) { 668231200Smm archive_set_error(&a->archive, ERANGE, 669231200Smm "File size out of range"); 670231200Smm ret = ARCHIVE_FAILED; 671231200Smm } 672231200Smm 673231200Smm /* Shouldn't overflow before 2106, since mtime field is 33 bits. */ 674231200Smm format_octal(archive_entry_mtime(entry), 675231200Smm h + GNUTAR_mtime_offset, GNUTAR_mtime_size); 676231200Smm 677231200Smm if (archive_entry_filetype(entry) == AE_IFBLK 678231200Smm || archive_entry_filetype(entry) == AE_IFCHR) { 679231200Smm if (format_octal(archive_entry_rdevmajor(entry), 680231200Smm h + GNUTAR_rdevmajor_offset, 681231200Smm GNUTAR_rdevmajor_size)) { 682231200Smm archive_set_error(&a->archive, ERANGE, 683231200Smm "Major device number too large"); 684231200Smm ret = ARCHIVE_FAILED; 685231200Smm } 686231200Smm 687231200Smm if (format_octal(archive_entry_rdevminor(entry), 688231200Smm h + GNUTAR_rdevminor_offset, 689231200Smm GNUTAR_rdevminor_size)) { 690231200Smm archive_set_error(&a->archive, ERANGE, 691231200Smm "Minor device number too large"); 692231200Smm ret = ARCHIVE_FAILED; 693231200Smm } 694231200Smm } 695231200Smm 696231200Smm h[GNUTAR_typeflag_offset] = tartype; 697231200Smm 698231200Smm checksum = 0; 699231200Smm for (i = 0; i < 512; i++) 700231200Smm checksum += 255 & (unsigned int)h[i]; 701231200Smm h[GNUTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */ 702231200Smm /* h[GNUTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */ 703231200Smm format_octal(checksum, h + GNUTAR_checksum_offset, 6); 704231200Smm return (ret); 705231200Smm} 706231200Smm 707231200Smm/* 708231200Smm * Format a number into a field, falling back to base-256 if necessary. 709231200Smm */ 710231200Smmstatic int 711231200Smmformat_number(int64_t v, char *p, int s, int maxsize) 712231200Smm{ 713231200Smm int64_t limit = ((int64_t)1 << (s*3)); 714231200Smm 715231200Smm if (v < limit) 716231200Smm return (format_octal(v, p, s)); 717231200Smm return (format_256(v, p, maxsize)); 718231200Smm} 719231200Smm 720231200Smm/* 721231200Smm * Format a number into the specified field using base-256. 722231200Smm */ 723231200Smmstatic int 724231200Smmformat_256(int64_t v, char *p, int s) 725231200Smm{ 726231200Smm p += s; 727231200Smm while (s-- > 0) { 728231200Smm *--p = (char)(v & 0xff); 729231200Smm v >>= 8; 730231200Smm } 731231200Smm *p |= 0x80; /* Set the base-256 marker bit. */ 732231200Smm return (0); 733231200Smm} 734231200Smm 735231200Smm/* 736231200Smm * Format a number into the specified field using octal. 737231200Smm */ 738231200Smmstatic int 739231200Smmformat_octal(int64_t v, char *p, int s) 740231200Smm{ 741231200Smm int len = s; 742231200Smm 743231200Smm /* Octal values can't be negative, so use 0. */ 744231200Smm if (v < 0) 745231200Smm v = 0; 746231200Smm 747231200Smm p += s; /* Start at the end and work backwards. */ 748231200Smm while (s-- > 0) { 749231200Smm *--p = (char)('0' + (v & 7)); 750231200Smm v >>= 3; 751231200Smm } 752231200Smm 753231200Smm if (v == 0) 754231200Smm return (0); 755231200Smm 756231200Smm /* If it overflowed, fill field with max value. */ 757231200Smm while (len-- > 0) 758231200Smm *p++ = '7'; 759231200Smm 760231200Smm return (-1); 761231200Smm} 762