archive_write_set_format_gnutar.c revision 231200
1251881Speter/*- 2251881Speter * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). 3251881Speter * Author: Jonas Gastal <jgastal@profusion.mobi> 4251881Speter * Copyright (c) 2011 Michihiro NAKAJIMA 5251881Speter * 6251881Speter * All rights reserved. 7251881Speter * 8251881Speter * Redistribution and use in source and binary forms, with or without 9251881Speter * modification, are permitted provided that the following conditions 10251881Speter * are met: 11251881Speter * 1. Redistributions of source code must retain the above copyright 12251881Speter * notice, this list of conditions and the following disclaimer. 13251881Speter * 2. Redistributions in binary form must reproduce the above copyright 14251881Speter * notice, this list of conditions and the following disclaimer in the 15251881Speter * documentation and/or other materials provided with the distribution. 16251881Speter * 17251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 18251881Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19251881Speter * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20251881Speter * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 21251881Speter * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22251881Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23251881Speter * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24251881Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25251881Speter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26251881Speter * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27251881Speter */ 28251881Speter 29251881Speter#include "archive_platform.h" 30251881Speter__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_gnu_tar.c 191579 2009-04-27 18:35:03Z gastal $"); 31251881Speter 32251881Speter 33251881Speter#ifdef HAVE_ERRNO_H 34251881Speter#include <errno.h> 35251881Speter#endif 36251881Speter#include <stdio.h> 37251881Speter#ifdef HAVE_STDLIB_H 38251881Speter#include <stdlib.h> 39251881Speter#endif 40251881Speter#ifdef HAVE_STRING_H 41251881Speter#include <string.h> 42251881Speter#endif 43251881Speter 44251881Speter#include "archive.h" 45251881Speter#include "archive_entry.h" 46251881Speter#include "archive_entry_locale.h" 47251881Speter#include "archive_private.h" 48251881Speter#include "archive_write_private.h" 49251881Speter 50251881Speterstruct gnutar { 51251881Speter uint64_t entry_bytes_remaining; 52251881Speter uint64_t entry_padding; 53251881Speter const char * linkname; 54251881Speter size_t linkname_length; 55251881Speter const char * pathname; 56251881Speter size_t pathname_length; 57251881Speter const char * uname; 58251881Speter size_t uname_length; 59251881Speter const char * gname; 60251881Speter size_t gname_length; 61251881Speter struct archive_string_conv *opt_sconv; 62251881Speter struct archive_string_conv *sconv_default; 63251881Speter int init_default_conversion; 64251881Speter}; 65251881Speter 66251881Speter/* 67251881Speter * Define structure of GNU tar header. 68251881Speter */ 69251881Speter#define GNUTAR_name_offset 0 70251881Speter#define GNUTAR_name_size 100 71251881Speter#define GNUTAR_mode_offset 100 72251881Speter#define GNUTAR_mode_size 7 73251881Speter#define GNUTAR_mode_max_size 8 74251881Speter#define GNUTAR_uid_offset 108 75251881Speter#define GNUTAR_uid_size 7 76251881Speter#define GNUTAR_uid_max_size 8 77251881Speter#define GNUTAR_gid_offset 116 78251881Speter#define GNUTAR_gid_size 7 79251881Speter#define GNUTAR_gid_max_size 8 80251881Speter#define GNUTAR_size_offset 124 81251881Speter#define GNUTAR_size_size 11 82251881Speter#define GNUTAR_size_max_size 12 83251881Speter#define GNUTAR_mtime_offset 136 84251881Speter#define GNUTAR_mtime_size 11 85251881Speter#define GNUTAR_mtime_max_size 11 86251881Speter#define GNUTAR_checksum_offset 148 87251881Speter#define GNUTAR_checksum_size 8 88251881Speter#define GNUTAR_typeflag_offset 156 89251881Speter#define GNUTAR_typeflag_size 1 90251881Speter#define GNUTAR_linkname_offset 157 91251881Speter#define GNUTAR_linkname_size 100 92251881Speter#define GNUTAR_magic_offset 257 93251881Speter#define GNUTAR_magic_size 6 94251881Speter#define GNUTAR_version_offset 263 95251881Speter#define GNUTAR_version_size 2 96251881Speter#define GNUTAR_uname_offset 265 97251881Speter#define GNUTAR_uname_size 32 98251881Speter#define GNUTAR_gname_offset 297 99251881Speter#define GNUTAR_gname_size 32 100251881Speter#define GNUTAR_rdevmajor_offset 329 101251881Speter#define GNUTAR_rdevmajor_size 6 102251881Speter#define GNUTAR_rdevmajor_max_size 8 103251881Speter#define GNUTAR_rdevminor_offset 337 104251881Speter#define GNUTAR_rdevminor_size 6 105251881Speter#define GNUTAR_rdevminor_max_size 8 106251881Speter 107251881Speter/* 108251881Speter * A filled-in copy of the header for initialization. 109251881Speter */ 110251881Speterstatic const char template_header[] = { 111251881Speter /* name: 100 bytes */ 112251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 113251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 114251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 115251881Speter 0,0,0,0, 116251881Speter /* Mode, null termination: 8 bytes */ 117251881Speter '0','0','0','0','0','0', '0','\0', 118251881Speter /* uid, null termination: 8 bytes */ 119251881Speter '0','0','0','0','0','0', '0','\0', 120251881Speter /* gid, null termination: 8 bytes */ 121251881Speter '0','0','0','0','0','0', '0','\0', 122251881Speter /* size, space termation: 12 bytes */ 123251881Speter '0','0','0','0','0','0','0','0','0','0','0', '\0', 124251881Speter /* mtime, space termation: 12 bytes */ 125251881Speter '0','0','0','0','0','0','0','0','0','0','0', '\0', 126251881Speter /* Initial checksum value: 8 spaces */ 127251881Speter ' ',' ',' ',' ',' ',' ',' ',' ', 128251881Speter /* Typeflag: 1 byte */ 129251881Speter '0', /* '0' = regular file */ 130251881Speter /* Linkname: 100 bytes */ 131251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 132251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 133251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 134251881Speter 0,0,0,0, 135251881Speter /* Magic: 8 bytes */ 136251881Speter 'u','s','t','a','r',' ', ' ','\0', 137251881Speter /* Uname: 32 bytes */ 138251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 139251881Speter /* Gname: 32 bytes */ 140251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 141251881Speter /* rdevmajor + null padding: 8 bytes */ 142251881Speter '\0','\0','\0','\0','\0','\0', '\0','\0', 143251881Speter /* rdevminor + null padding: 8 bytes */ 144251881Speter '\0','\0','\0','\0','\0','\0', '\0','\0', 145251881Speter /* Padding: 167 bytes */ 146251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 147251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 148251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 149251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 150251881Speter 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 151251881Speter 0,0,0,0,0,0,0 152251881Speter}; 153251881Speter 154251881Speterstatic int archive_write_gnutar_options(struct archive_write *, 155251881Speter const char *, const char *); 156251881Speterstatic int archive_format_gnutar_header(struct archive_write *, char h[512], 157251881Speter struct archive_entry *, int tartype); 158251881Speterstatic int archive_write_gnutar_header(struct archive_write *, 159251881Speter struct archive_entry *entry); 160251881Speterstatic ssize_t archive_write_gnutar_data(struct archive_write *a, const void *buff, 161251881Speter size_t s); 162251881Speterstatic int archive_write_gnutar_free(struct archive_write *); 163251881Speterstatic int archive_write_gnutar_close(struct archive_write *); 164251881Speterstatic int archive_write_gnutar_finish_entry(struct archive_write *); 165251881Speterstatic int format_256(int64_t, char *, int); 166251881Speterstatic int format_number(int64_t, char *, int size, int maxsize); 167251881Speterstatic int format_octal(int64_t, char *, int); 168251881Speter 169251881Speter/* 170251881Speter * Set output format to 'GNU tar' format. 171251881Speter */ 172251881Speterint 173251881Speterarchive_write_set_format_gnutar(struct archive *_a) 174251881Speter{ 175251881Speter struct archive_write *a = (struct archive_write *)_a; 176251881Speter struct gnutar *gnutar; 177251881Speter 178251881Speter gnutar = (struct gnutar *)calloc(1, sizeof(*gnutar)); 179251881Speter if (gnutar == NULL) { 180251881Speter archive_set_error(&a->archive, ENOMEM, "Can't allocate gnutar data"); 181251881Speter return (ARCHIVE_FATAL); 182251881Speter } 183251881Speter a->format_data = gnutar; 184251881Speter a->format_name = "gnutar"; 185251881Speter a->format_options = archive_write_gnutar_options; 186251881Speter a->format_write_header = archive_write_gnutar_header; 187251881Speter a->format_write_data = archive_write_gnutar_data; 188251881Speter a->format_close = archive_write_gnutar_close; 189251881Speter a->format_free = archive_write_gnutar_free; 190251881Speter a->format_finish_entry = archive_write_gnutar_finish_entry; 191251881Speter a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR; 192251881Speter a->archive.archive_format_name = "GNU tar"; 193251881Speter return (ARCHIVE_OK); 194251881Speter} 195251881Speter 196251881Speterstatic int 197251881Speterarchive_write_gnutar_options(struct archive_write *a, const char *key, 198251881Speter const char *val) 199251881Speter{ 200251881Speter struct gnutar *gnutar = (struct gnutar *)a->format_data; 201251881Speter int ret = ARCHIVE_FAILED; 202251881Speter 203251881Speter if (strcmp(key, "hdrcharset") == 0) { 204251881Speter if (val == NULL || val[0] == 0) 205251881Speter archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 206251881Speter "%s: hdrcharset option needs a character-set name", 207251881Speter a->format_name); 208251881Speter else { 209251881Speter gnutar->opt_sconv = archive_string_conversion_to_charset( 210251881Speter &a->archive, val, 0); 211251881Speter if (gnutar->opt_sconv != NULL) 212251881Speter ret = ARCHIVE_OK; 213251881Speter else 214251881Speter ret = ARCHIVE_FATAL; 215251881Speter } 216251881Speter } else 217251881Speter archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 218251881Speter "%s: unknown keyword ``%s''", a->format_name, key); 219251881Speter 220251881Speter return (ret); 221251881Speter} 222251881Speter 223251881Speterstatic int 224251881Speterarchive_write_gnutar_close(struct archive_write *a) 225251881Speter{ 226251881Speter return (__archive_write_nulls(a, 512*2)); 227251881Speter} 228251881Speter 229251881Speterstatic int 230251881Speterarchive_write_gnutar_free(struct archive_write *a) 231251881Speter{ 232251881Speter struct gnutar *gnutar; 233251881Speter 234251881Speter gnutar = (struct gnutar *)a->format_data; 235251881Speter free(gnutar); 236251881Speter a->format_data = NULL; 237251881Speter return (ARCHIVE_OK); 238251881Speter} 239251881Speter 240251881Speterstatic int 241251881Speterarchive_write_gnutar_finish_entry(struct archive_write *a) 242251881Speter{ 243251881Speter struct gnutar *gnutar; 244251881Speter int ret; 245251881Speter 246251881Speter gnutar = (struct gnutar *)a->format_data; 247251881Speter ret = __archive_write_nulls(a, 248251881Speter gnutar->entry_bytes_remaining + gnutar->entry_padding); 249251881Speter gnutar->entry_bytes_remaining = gnutar->entry_padding = 0; 250251881Speter return (ret); 251251881Speter} 252251881Speter 253251881Speterstatic ssize_t 254251881Speterarchive_write_gnutar_data(struct archive_write *a, const void *buff, size_t s) 255251881Speter{ 256251881Speter struct gnutar *gnutar; 257251881Speter int ret; 258251881Speter 259251881Speter gnutar = (struct gnutar *)a->format_data; 260251881Speter if (s > gnutar->entry_bytes_remaining) 261251881Speter s = gnutar->entry_bytes_remaining; 262251881Speter ret = __archive_write_output(a, buff, s); 263251881Speter gnutar->entry_bytes_remaining -= s; 264251881Speter if (ret != ARCHIVE_OK) 265251881Speter return (ret); 266251881Speter return (s); 267251881Speter} 268251881Speter 269251881Speterstatic int 270251881Speterarchive_write_gnutar_header(struct archive_write *a, 271251881Speter struct archive_entry *entry) 272251881Speter{ 273251881Speter char buff[512]; 274251881Speter int r, ret, ret2 = ARCHIVE_OK; 275251881Speter int tartype; 276251881Speter struct gnutar *gnutar; 277251881Speter struct archive_string_conv *sconv; 278251881Speter 279251881Speter gnutar = (struct gnutar *)a->format_data; 280251881Speter 281251881Speter /* Setup default string conversion. */ 282251881Speter if (gnutar->opt_sconv == NULL) { 283251881Speter if (!gnutar->init_default_conversion) { 284251881Speter gnutar->sconv_default = 285251881Speter archive_string_default_conversion_for_write( 286251881Speter &(a->archive)); 287251881Speter gnutar->init_default_conversion = 1; 288251881Speter } 289251881Speter sconv = gnutar->sconv_default; 290251881Speter } else 291251881Speter sconv = gnutar->opt_sconv; 292251881Speter 293251881Speter /* Only regular files (not hardlinks) have data. */ 294251881Speter if (archive_entry_hardlink(entry) != NULL || 295251881Speter archive_entry_symlink(entry) != NULL || 296251881Speter !(archive_entry_filetype(entry) == AE_IFREG)) 297251881Speter archive_entry_set_size(entry, 0); 298251881Speter 299251881Speter if (AE_IFDIR == archive_entry_filetype(entry)) { 300251881Speter const char *p; 301251881Speter char *t; 302251881Speter /* 303251881Speter * Ensure a trailing '/'. Modify the entry so 304251881Speter * the client sees the change. 305251881Speter */ 306251881Speter p = archive_entry_pathname(entry); 307251881Speter if (p[strlen(p) - 1] != '/') { 308251881Speter t = (char *)malloc(strlen(p) + 2); 309251881Speter if (t == NULL) { 310251881Speter archive_set_error(&a->archive, ENOMEM, 311251881Speter "Can't allocate gnutar data"); 312251881Speter return(ARCHIVE_FATAL); 313251881Speter } 314251881Speter strcpy(t, p); 315251881Speter strcat(t, "/"); 316251881Speter archive_entry_copy_pathname(entry, t); 317251881Speter free(t); 318251881Speter } 319251881Speter } 320251881Speter 321251881Speter r = archive_entry_pathname_l(entry, &(gnutar->pathname), 322251881Speter &(gnutar->pathname_length), sconv); 323251881Speter if (r != 0) { 324251881Speter if (errno == ENOMEM) { 325251881Speter archive_set_error(&a->archive, ENOMEM, 326251881Speter "Can't allocate memory for Pathame"); 327251881Speter return (ARCHIVE_FATAL); 328251881Speter } 329251881Speter archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 330251881Speter "Can't translate pathname '%s' to %s", 331251881Speter archive_entry_pathname(entry), 332251881Speter archive_string_conversion_charset_name(sconv)); 333251881Speter ret2 = ARCHIVE_WARN; 334251881Speter } 335251881Speter r = archive_entry_uname_l(entry, &(gnutar->uname), 336251881Speter &(gnutar->uname_length), sconv); 337251881Speter if (r != 0) { 338251881Speter if (errno == ENOMEM) { 339251881Speter archive_set_error(&a->archive, ENOMEM, 340251881Speter "Can't allocate memory for Uname"); 341251881Speter return (ARCHIVE_FATAL); 342251881Speter } 343251881Speter archive_set_error(&a->archive, 344251881Speter ARCHIVE_ERRNO_FILE_FORMAT, 345251881Speter "Can't translate uname '%s' to %s", 346251881Speter archive_entry_uname(entry), 347251881Speter archive_string_conversion_charset_name(sconv)); 348251881Speter ret2 = ARCHIVE_WARN; 349251881Speter } 350251881Speter r = archive_entry_gname_l(entry, &(gnutar->gname), 351251881Speter &(gnutar->gname_length), sconv); 352251881Speter if (r != 0) { 353251881Speter if (errno == ENOMEM) { 354251881Speter archive_set_error(&a->archive, ENOMEM, 355251881Speter "Can't allocate memory for Gname"); 356251881Speter return (ARCHIVE_FATAL); 357251881Speter } 358251881Speter archive_set_error(&a->archive, 359251881Speter ARCHIVE_ERRNO_FILE_FORMAT, 360251881Speter "Can't translate gname '%s' to %s", 361251881Speter archive_entry_gname(entry), 362251881Speter archive_string_conversion_charset_name(sconv)); 363251881Speter ret2 = ARCHIVE_WARN; 364251881Speter } 365251881Speter 366251881Speter /* If linkname is longer than 100 chars we need to add a 'K' header. */ 367251881Speter r = archive_entry_hardlink_l(entry, &(gnutar->linkname), 368251881Speter &(gnutar->linkname_length), sconv); 369251881Speter if (r != 0) { 370251881Speter if (errno == ENOMEM) { 371251881Speter archive_set_error(&a->archive, ENOMEM, 372251881Speter "Can't allocate memory for Linkname"); 373251881Speter return (ARCHIVE_FATAL); 374251881Speter } 375251881Speter archive_set_error(&a->archive, 376251881Speter ARCHIVE_ERRNO_FILE_FORMAT, 377251881Speter "Can't translate linkname '%s' to %s", 378251881Speter archive_entry_hardlink(entry), 379251881Speter archive_string_conversion_charset_name(sconv)); 380251881Speter ret2 = ARCHIVE_WARN; 381251881Speter } 382251881Speter if (gnutar->linkname_length == 0) { 383251881Speter r = archive_entry_symlink_l(entry, &(gnutar->linkname), 384251881Speter &(gnutar->linkname_length), sconv); 385251881Speter if (r != 0) { 386251881Speter if (errno == ENOMEM) { 387251881Speter archive_set_error(&a->archive, ENOMEM, 388251881Speter "Can't allocate memory for Linkname"); 389251881Speter return (ARCHIVE_FATAL); 390251881Speter } 391251881Speter archive_set_error(&a->archive, 392251881Speter ARCHIVE_ERRNO_FILE_FORMAT, 393251881Speter "Can't translate linkname '%s' to %s", 394251881Speter archive_entry_hardlink(entry), 395251881Speter archive_string_conversion_charset_name(sconv)); 396251881Speter ret2 = ARCHIVE_WARN; 397251881Speter } 398251881Speter } 399251881Speter if (gnutar->linkname_length > GNUTAR_linkname_size) { 400251881Speter size_t todo = gnutar->linkname_length; 401251881Speter struct archive_entry *temp = archive_entry_new2(&a->archive); 402251881Speter 403251881Speter /* Uname/gname here don't really matter since no one reads them; 404251881Speter * these are the values that GNU tar happens to use on FreeBSD. */ 405251881Speter archive_entry_set_uname(temp, "root"); 406251881Speter archive_entry_set_gname(temp, "wheel"); 407251881Speter 408251881Speter archive_entry_set_pathname(temp, "././@LongLink"); 409251881Speter archive_entry_set_size(temp, gnutar->linkname_length + 1); 410251881Speter ret = archive_format_gnutar_header(a, buff, temp, 'K'); 411251881Speter if (ret < ARCHIVE_WARN) 412251881Speter return (ret); 413251881Speter ret = __archive_write_output(a, buff, 512); 414251881Speter if(ret < ARCHIVE_WARN) 415251881Speter return (ret); 416251881Speter archive_entry_free(temp); 417251881Speter /* Write as many 512 bytes blocks as needed to write full name. */ 418251881Speter ret = __archive_write_output(a, gnutar->linkname, todo); 419251881Speter if(ret < ARCHIVE_WARN) 420251881Speter return (ret); 421251881Speter ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo)); 422251881Speter if (ret < ARCHIVE_WARN) 423251881Speter return (ret); 424251881Speter } 425251881Speter 426251881Speter /* If pathname is longer than 100 chars we need to add an 'L' header. */ 427251881Speter if (gnutar->pathname_length > GNUTAR_name_size) { 428251881Speter const char *pathname = gnutar->pathname; 429251881Speter size_t todo = gnutar->pathname_length; 430251881Speter struct archive_entry *temp = archive_entry_new2(&a->archive); 431251881Speter 432251881Speter /* Uname/gname here don't really matter since no one reads them; 433251881Speter * these are the values that GNU tar happens to use on FreeBSD. */ 434251881Speter archive_entry_set_uname(temp, "root"); 435251881Speter archive_entry_set_gname(temp, "wheel"); 436251881Speter 437251881Speter archive_entry_set_pathname(temp, "././@LongLink"); 438251881Speter archive_entry_set_size(temp, gnutar->pathname_length + 1); 439251881Speter ret = archive_format_gnutar_header(a, buff, temp, 'L'); 440251881Speter if (ret < ARCHIVE_WARN) 441251881Speter return (ret); 442251881Speter ret = __archive_write_output(a, buff, 512); 443251881Speter if(ret < ARCHIVE_WARN) 444251881Speter return (ret); 445251881Speter archive_entry_free(temp); 446251881Speter /* Write as many 512 bytes blocks as needed to write full name. */ 447251881Speter ret = __archive_write_output(a, pathname, todo); 448251881Speter if(ret < ARCHIVE_WARN) 449251881Speter return (ret); 450251881Speter ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo)); 451251881Speter if (ret < ARCHIVE_WARN) 452251881Speter return (ret); 453251881Speter } 454251881Speter 455251881Speter if (archive_entry_hardlink(entry) != NULL) { 456251881Speter tartype = '1'; 457251881Speter } else 458251881Speter switch (archive_entry_filetype(entry)) { 459251881Speter case AE_IFREG: tartype = '0' ; break; 460251881Speter case AE_IFLNK: tartype = '2' ; break; 461251881Speter case AE_IFCHR: tartype = '3' ; break; 462251881Speter case AE_IFBLK: tartype = '4' ; break; 463251881Speter case AE_IFDIR: tartype = '5' ; break; 464251881Speter case AE_IFIFO: tartype = '6' ; break; 465251881Speter case AE_IFSOCK: 466251881Speter archive_set_error(&a->archive, 467251881Speter ARCHIVE_ERRNO_FILE_FORMAT, 468251881Speter "tar format cannot archive socket"); 469251881Speter return (ARCHIVE_FAILED); 470251881Speter default: 471251881Speter archive_set_error(&a->archive, 472251881Speter ARCHIVE_ERRNO_FILE_FORMAT, 473251881Speter "tar format cannot archive this (mode=0%lo)", 474251881Speter (unsigned long)archive_entry_mode(entry)); 475251881Speter return (ARCHIVE_FAILED); 476251881Speter } 477251881Speter 478251881Speter ret = archive_format_gnutar_header(a, buff, entry, tartype); 479251881Speter if (ret < ARCHIVE_WARN) 480251881Speter return (ret); 481251881Speter if (ret2 < ret) 482251881Speter ret = ret2; 483251881Speter ret2 = __archive_write_output(a, buff, 512); 484251881Speter if (ret2 < ARCHIVE_WARN) 485251881Speter return (ret2); 486251881Speter if (ret2 < ret) 487251881Speter ret = ret2; 488251881Speter 489251881Speter gnutar->entry_bytes_remaining = archive_entry_size(entry); 490251881Speter gnutar->entry_padding = 0x1ff & (-(int64_t)gnutar->entry_bytes_remaining); 491251881Speter return (ret); 492251881Speter} 493251881Speter 494251881Speterstatic int 495251881Speterarchive_format_gnutar_header(struct archive_write *a, char h[512], 496251881Speter struct archive_entry *entry, int tartype) 497251881Speter{ 498251881Speter unsigned int checksum; 499251881Speter int i, ret; 500251881Speter size_t copy_length; 501251881Speter const char *p; 502251881Speter struct gnutar *gnutar; 503251881Speter 504251881Speter gnutar = (struct gnutar *)a->format_data; 505251881Speter 506251881Speter ret = 0; 507251881Speter 508251881Speter /* 509251881Speter * The "template header" already includes the signature, 510251881Speter * various end-of-field markers, and other required elements. 511251881Speter */ 512251881Speter memcpy(h, &template_header, 512); 513251881Speter 514251881Speter /* 515251881Speter * Because the block is already null-filled, and strings 516251881Speter * are allowed to exactly fill their destination (without null), 517251881Speter * I use memcpy(dest, src, strlen()) here a lot to copy strings. 518251881Speter */ 519251881Speter 520251881Speter if (tartype == 'K' || tartype == 'L') { 521251881Speter p = archive_entry_pathname(entry); 522251881Speter copy_length = strlen(p); 523251881Speter } else { 524251881Speter p = gnutar->pathname; 525251881Speter copy_length = gnutar->pathname_length; 526251881Speter } 527251881Speter if (copy_length > GNUTAR_name_size) 528251881Speter copy_length = GNUTAR_name_size; 529251881Speter memcpy(h + GNUTAR_name_offset, p, copy_length); 530251881Speter 531251881Speter if ((copy_length = gnutar->linkname_length) > 0) { 532251881Speter if (copy_length > GNUTAR_linkname_size) 533251881Speter copy_length = GNUTAR_linkname_size; 534251881Speter memcpy(h + GNUTAR_linkname_offset, gnutar->linkname, 535251881Speter copy_length); 536251881Speter } 537251881Speter 538251881Speter /* TODO: How does GNU tar handle unames longer than GNUTAR_uname_size? */ 539251881Speter if (tartype == 'K' || tartype == 'L') { 540251881Speter p = archive_entry_uname(entry); 541251881Speter copy_length = strlen(p); 542251881Speter } else { 543251881Speter p = gnutar->uname; 544251881Speter copy_length = gnutar->uname_length; 545251881Speter } 546251881Speter if (copy_length > 0) { 547251881Speter if (copy_length > GNUTAR_uname_size) 548251881Speter copy_length = GNUTAR_uname_size; 549251881Speter memcpy(h + GNUTAR_uname_offset, p, copy_length); 550251881Speter } 551251881Speter 552251881Speter /* TODO: How does GNU tar handle gnames longer than GNUTAR_gname_size? */ 553251881Speter if (tartype == 'K' || tartype == 'L') { 554251881Speter p = archive_entry_gname(entry); 555251881Speter copy_length = strlen(p); 556251881Speter } else { 557251881Speter p = gnutar->gname; 558251881Speter copy_length = gnutar->gname_length; 559251881Speter } 560251881Speter if (copy_length > 0) { 561251881Speter if (strlen(p) > GNUTAR_gname_size) 562251881Speter copy_length = GNUTAR_gname_size; 563251881Speter memcpy(h + GNUTAR_gname_offset, p, copy_length); 564251881Speter } 565251881Speter 566251881Speter /* By truncating the mode here, we ensure it always fits. */ 567251881Speter format_octal(archive_entry_mode(entry) & 07777, 568251881Speter h + GNUTAR_mode_offset, GNUTAR_mode_size); 569251881Speter 570251881Speter /* TODO: How does GNU tar handle large UIDs? */ 571251881Speter if (format_octal(archive_entry_uid(entry), 572251881Speter h + GNUTAR_uid_offset, GNUTAR_uid_size)) { 573251881Speter archive_set_error(&a->archive, ERANGE, 574251881Speter "Numeric user ID %jd too large", 575251881Speter (intmax_t)archive_entry_uid(entry)); 576251881Speter ret = ARCHIVE_FAILED; 577251881Speter } 578251881Speter 579251881Speter /* TODO: How does GNU tar handle large GIDs? */ 580251881Speter if (format_octal(archive_entry_gid(entry), 581251881Speter h + GNUTAR_gid_offset, GNUTAR_gid_size)) { 582251881Speter archive_set_error(&a->archive, ERANGE, 583251881Speter "Numeric group ID %jd too large", 584251881Speter (intmax_t)archive_entry_gid(entry)); 585251881Speter ret = ARCHIVE_FAILED; 586251881Speter } 587251881Speter 588251881Speter /* GNU tar supports base-256 here, so should never overflow. */ 589251881Speter if (format_number(archive_entry_size(entry), h + GNUTAR_size_offset, 590251881Speter GNUTAR_size_size, GNUTAR_size_max_size)) { 591251881Speter archive_set_error(&a->archive, ERANGE, 592251881Speter "File size out of range"); 593251881Speter ret = ARCHIVE_FAILED; 594251881Speter } 595251881Speter 596251881Speter /* Shouldn't overflow before 2106, since mtime field is 33 bits. */ 597251881Speter format_octal(archive_entry_mtime(entry), 598251881Speter h + GNUTAR_mtime_offset, GNUTAR_mtime_size); 599251881Speter 600251881Speter if (archive_entry_filetype(entry) == AE_IFBLK 601251881Speter || archive_entry_filetype(entry) == AE_IFCHR) { 602251881Speter if (format_octal(archive_entry_rdevmajor(entry), 603251881Speter h + GNUTAR_rdevmajor_offset, 604251881Speter GNUTAR_rdevmajor_size)) { 605251881Speter archive_set_error(&a->archive, ERANGE, 606251881Speter "Major device number too large"); 607251881Speter ret = ARCHIVE_FAILED; 608251881Speter } 609251881Speter 610251881Speter if (format_octal(archive_entry_rdevminor(entry), 611251881Speter h + GNUTAR_rdevminor_offset, 612251881Speter GNUTAR_rdevminor_size)) { 613251881Speter archive_set_error(&a->archive, ERANGE, 614251881Speter "Minor device number too large"); 615251881Speter ret = ARCHIVE_FAILED; 616251881Speter } 617251881Speter } 618251881Speter 619251881Speter h[GNUTAR_typeflag_offset] = tartype; 620251881Speter 621251881Speter checksum = 0; 622251881Speter for (i = 0; i < 512; i++) 623251881Speter checksum += 255 & (unsigned int)h[i]; 624251881Speter h[GNUTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */ 625251881Speter /* h[GNUTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */ 626251881Speter format_octal(checksum, h + GNUTAR_checksum_offset, 6); 627251881Speter return (ret); 628251881Speter} 629251881Speter 630251881Speter/* 631251881Speter * Format a number into a field, falling back to base-256 if necessary. 632251881Speter */ 633251881Speterstatic int 634251881Speterformat_number(int64_t v, char *p, int s, int maxsize) 635251881Speter{ 636251881Speter int64_t limit = ((int64_t)1 << (s*3)); 637251881Speter 638251881Speter if (v < limit) 639251881Speter return (format_octal(v, p, s)); 640251881Speter return (format_256(v, p, maxsize)); 641251881Speter} 642251881Speter 643251881Speter/* 644251881Speter * Format a number into the specified field using base-256. 645251881Speter */ 646251881Speterstatic int 647251881Speterformat_256(int64_t v, char *p, int s) 648251881Speter{ 649251881Speter p += s; 650251881Speter while (s-- > 0) { 651251881Speter *--p = (char)(v & 0xff); 652251881Speter v >>= 8; 653251881Speter } 654251881Speter *p |= 0x80; /* Set the base-256 marker bit. */ 655251881Speter return (0); 656251881Speter} 657251881Speter 658251881Speter/* 659251881Speter * Format a number into the specified field using octal. 660251881Speter */ 661251881Speterstatic int 662251881Speterformat_octal(int64_t v, char *p, int s) 663251881Speter{ 664251881Speter int len = s; 665251881Speter 666251881Speter /* Octal values can't be negative, so use 0. */ 667251881Speter if (v < 0) 668251881Speter v = 0; 669251881Speter 670251881Speter p += s; /* Start at the end and work backwards. */ 671251881Speter while (s-- > 0) { 672251881Speter *--p = (char)('0' + (v & 7)); 673251881Speter v >>= 3; 674251881Speter } 675251881Speter 676251881Speter if (v == 0) 677251881Speter return (0); 678251881Speter 679251881Speter /* If it overflowed, fill field with max value. */ 680251881Speter while (len-- > 0) 681251881Speter *p++ = '7'; 682251881Speter 683251881Speter return (-1); 684251881Speter} 685251881Speter