1228753Smm/*- 2228753Smm * Copyright (c) 2003-2007 Tim Kientzle 3228753Smm * All rights reserved. 4228753Smm * 5228753Smm * Redistribution and use in source and binary forms, with or without 6228753Smm * modification, are permitted provided that the following conditions 7228753Smm * are met: 8228753Smm * 1. Redistributions of source code must retain the above copyright 9228753Smm * notice, this list of conditions and the following disclaimer. 10228753Smm * 2. Redistributions in binary form must reproduce the above copyright 11228753Smm * notice, this list of conditions and the following disclaimer in the 12228753Smm * documentation and/or other materials provided with the distribution. 13228753Smm * 14228753Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15228753Smm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16228753Smm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17228753Smm * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18228753Smm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19228753Smm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20228753Smm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21228753Smm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22228753Smm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23228753Smm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24228753Smm */ 25228753Smm 26228753Smm#include "archive_platform.h" 27229592Smm__FBSDID("$FreeBSD$"); 28228753Smm 29228753Smm 30228753Smm#ifdef HAVE_ERRNO_H 31228753Smm#include <errno.h> 32228753Smm#endif 33228753Smm#include <stdio.h> 34228753Smm#ifdef HAVE_STDLIB_H 35228753Smm#include <stdlib.h> 36228753Smm#endif 37228753Smm#ifdef HAVE_STRING_H 38228753Smm#include <string.h> 39228753Smm#endif 40228753Smm 41228753Smm#include "archive.h" 42228753Smm#include "archive_entry.h" 43228753Smm#include "archive_private.h" 44228753Smm#include "archive_write_private.h" 45228753Smm 46228753Smmstruct ustar { 47228753Smm uint64_t entry_bytes_remaining; 48228753Smm uint64_t entry_padding; 49228753Smm}; 50228753Smm 51228753Smm/* 52228753Smm * Define structure of POSIX 'ustar' tar header. 53228753Smm */ 54228753Smm#define USTAR_name_offset 0 55228753Smm#define USTAR_name_size 100 56228753Smm#define USTAR_mode_offset 100 57228753Smm#define USTAR_mode_size 6 58228753Smm#define USTAR_mode_max_size 8 59228753Smm#define USTAR_uid_offset 108 60228753Smm#define USTAR_uid_size 6 61228753Smm#define USTAR_uid_max_size 8 62228753Smm#define USTAR_gid_offset 116 63228753Smm#define USTAR_gid_size 6 64228753Smm#define USTAR_gid_max_size 8 65228753Smm#define USTAR_size_offset 124 66228753Smm#define USTAR_size_size 11 67228753Smm#define USTAR_size_max_size 12 68228753Smm#define USTAR_mtime_offset 136 69228753Smm#define USTAR_mtime_size 11 70228753Smm#define USTAR_mtime_max_size 11 71228753Smm#define USTAR_checksum_offset 148 72228753Smm#define USTAR_checksum_size 8 73228753Smm#define USTAR_typeflag_offset 156 74228753Smm#define USTAR_typeflag_size 1 75228753Smm#define USTAR_linkname_offset 157 76228753Smm#define USTAR_linkname_size 100 77228753Smm#define USTAR_magic_offset 257 78228753Smm#define USTAR_magic_size 6 79228753Smm#define USTAR_version_offset 263 80228753Smm#define USTAR_version_size 2 81228753Smm#define USTAR_uname_offset 265 82228753Smm#define USTAR_uname_size 32 83228753Smm#define USTAR_gname_offset 297 84228753Smm#define USTAR_gname_size 32 85228753Smm#define USTAR_rdevmajor_offset 329 86228753Smm#define USTAR_rdevmajor_size 6 87228753Smm#define USTAR_rdevmajor_max_size 8 88228753Smm#define USTAR_rdevminor_offset 337 89228753Smm#define USTAR_rdevminor_size 6 90228753Smm#define USTAR_rdevminor_max_size 8 91228753Smm#define USTAR_prefix_offset 345 92228753Smm#define USTAR_prefix_size 155 93228753Smm#define USTAR_padding_offset 500 94228753Smm#define USTAR_padding_size 12 95228753Smm 96228753Smm/* 97228753Smm * A filled-in copy of the header for initialization. 98228753Smm */ 99228753Smmstatic const char template_header[] = { 100228753Smm /* name: 100 bytes */ 101228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 102228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 103228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 104228753Smm 0,0,0,0, 105228753Smm /* Mode, space-null termination: 8 bytes */ 106228753Smm '0','0','0','0','0','0', ' ','\0', 107228753Smm /* uid, space-null termination: 8 bytes */ 108228753Smm '0','0','0','0','0','0', ' ','\0', 109228753Smm /* gid, space-null termination: 8 bytes */ 110228753Smm '0','0','0','0','0','0', ' ','\0', 111228753Smm /* size, space termation: 12 bytes */ 112228753Smm '0','0','0','0','0','0','0','0','0','0','0', ' ', 113228753Smm /* mtime, space termation: 12 bytes */ 114228753Smm '0','0','0','0','0','0','0','0','0','0','0', ' ', 115228753Smm /* Initial checksum value: 8 spaces */ 116228753Smm ' ',' ',' ',' ',' ',' ',' ',' ', 117228753Smm /* Typeflag: 1 byte */ 118228753Smm '0', /* '0' = regular file */ 119228753Smm /* Linkname: 100 bytes */ 120228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 121228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 122228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 123228753Smm 0,0,0,0, 124228753Smm /* Magic: 6 bytes, Version: 2 bytes */ 125228753Smm 'u','s','t','a','r','\0', '0','0', 126228753Smm /* Uname: 32 bytes */ 127228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 128228753Smm /* Gname: 32 bytes */ 129228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 130228753Smm /* rdevmajor + space/null padding: 8 bytes */ 131228753Smm '0','0','0','0','0','0', ' ','\0', 132228753Smm /* rdevminor + space/null padding: 8 bytes */ 133228753Smm '0','0','0','0','0','0', ' ','\0', 134228753Smm /* Prefix: 155 bytes */ 135228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 136228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 137228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 138228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 139228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0, 140228753Smm /* Padding: 12 bytes */ 141228753Smm 0,0,0,0,0,0,0,0, 0,0,0,0 142228753Smm}; 143228753Smm 144228753Smmstatic ssize_t archive_write_ustar_data(struct archive_write *a, const void *buff, 145228753Smm size_t s); 146228753Smmstatic int archive_write_ustar_destroy(struct archive_write *); 147228753Smmstatic int archive_write_ustar_finish(struct archive_write *); 148228753Smmstatic int archive_write_ustar_finish_entry(struct archive_write *); 149228753Smmstatic int archive_write_ustar_header(struct archive_write *, 150228753Smm struct archive_entry *entry); 151228753Smmstatic int format_256(int64_t, char *, int); 152228753Smmstatic int format_number(int64_t, char *, int size, int max, int strict); 153228753Smmstatic int format_octal(int64_t, char *, int); 154228753Smmstatic int write_nulls(struct archive_write *a, size_t); 155228753Smm 156228753Smm/* 157228753Smm * Set output format to 'ustar' format. 158228753Smm */ 159228753Smmint 160228753Smmarchive_write_set_format_ustar(struct archive *_a) 161228753Smm{ 162228753Smm struct archive_write *a = (struct archive_write *)_a; 163228753Smm struct ustar *ustar; 164228753Smm 165228753Smm /* If someone else was already registered, unregister them. */ 166228753Smm if (a->format_destroy != NULL) 167228753Smm (a->format_destroy)(a); 168228753Smm 169228753Smm /* Basic internal sanity test. */ 170228753Smm if (sizeof(template_header) != 512) { 171228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal: template_header wrong size: %d should be 512", (int)sizeof(template_header)); 172228753Smm return (ARCHIVE_FATAL); 173228753Smm } 174228753Smm 175228753Smm ustar = (struct ustar *)malloc(sizeof(*ustar)); 176228753Smm if (ustar == NULL) { 177228753Smm archive_set_error(&a->archive, ENOMEM, "Can't allocate ustar data"); 178228753Smm return (ARCHIVE_FATAL); 179228753Smm } 180228753Smm memset(ustar, 0, sizeof(*ustar)); 181228753Smm a->format_data = ustar; 182228753Smm 183228753Smm a->pad_uncompressed = 1; /* Mimic gtar in this respect. */ 184228753Smm a->format_name = "ustar"; 185228753Smm a->format_write_header = archive_write_ustar_header; 186228753Smm a->format_write_data = archive_write_ustar_data; 187228753Smm a->format_finish = archive_write_ustar_finish; 188228753Smm a->format_destroy = archive_write_ustar_destroy; 189228753Smm a->format_finish_entry = archive_write_ustar_finish_entry; 190228753Smm a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR; 191228753Smm a->archive.archive_format_name = "POSIX ustar"; 192228753Smm return (ARCHIVE_OK); 193228753Smm} 194228753Smm 195228753Smmstatic int 196228753Smmarchive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) 197228753Smm{ 198228753Smm char buff[512]; 199228753Smm int ret, ret2; 200228753Smm struct ustar *ustar; 201228753Smm 202228753Smm ustar = (struct ustar *)a->format_data; 203228753Smm 204228753Smm /* Only regular files (not hardlinks) have data. */ 205228753Smm if (archive_entry_hardlink(entry) != NULL || 206228753Smm archive_entry_symlink(entry) != NULL || 207228753Smm !(archive_entry_filetype(entry) == AE_IFREG)) 208228753Smm archive_entry_set_size(entry, 0); 209228753Smm 210228753Smm if (AE_IFDIR == archive_entry_filetype(entry)) { 211228753Smm const char *p; 212228753Smm char *t; 213228753Smm /* 214228753Smm * Ensure a trailing '/'. Modify the entry so 215228753Smm * the client sees the change. 216228753Smm */ 217228753Smm p = archive_entry_pathname(entry); 218228753Smm if (p[strlen(p) - 1] != '/') { 219228753Smm t = (char *)malloc(strlen(p) + 2); 220228753Smm if (t == NULL) { 221228753Smm archive_set_error(&a->archive, ENOMEM, 222228753Smm "Can't allocate ustar data"); 223228753Smm return(ARCHIVE_FATAL); 224228753Smm } 225228753Smm strcpy(t, p); 226228753Smm strcat(t, "/"); 227228753Smm archive_entry_copy_pathname(entry, t); 228228753Smm free(t); 229228753Smm } 230228753Smm } 231228753Smm 232228753Smm ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1); 233228753Smm if (ret < ARCHIVE_WARN) 234228753Smm return (ret); 235228753Smm ret2 = (a->compressor.write)(a, buff, 512); 236228753Smm if (ret2 < ARCHIVE_WARN) 237228753Smm return (ret2); 238228753Smm if (ret2 < ret) 239228753Smm ret = ret2; 240228753Smm 241228753Smm ustar->entry_bytes_remaining = archive_entry_size(entry); 242228753Smm ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining); 243228753Smm return (ret); 244228753Smm} 245228753Smm 246228753Smm/* 247228753Smm * Format a basic 512-byte "ustar" header. 248228753Smm * 249228753Smm * Returns -1 if format failed (due to field overflow). 250228753Smm * Note that this always formats as much of the header as possible. 251228753Smm * If "strict" is set to zero, it will extend numeric fields as 252228753Smm * necessary (overwriting terminators or using base-256 extensions). 253228753Smm * 254228753Smm * This is exported so that other 'tar' formats can use it. 255228753Smm */ 256228753Smmint 257228753Smm__archive_write_format_header_ustar(struct archive_write *a, char h[512], 258228753Smm struct archive_entry *entry, int tartype, int strict) 259228753Smm{ 260228753Smm unsigned int checksum; 261228753Smm int i, ret; 262228753Smm size_t copy_length; 263228753Smm const char *p, *pp; 264228753Smm int mytartype; 265228753Smm 266228753Smm ret = 0; 267228753Smm mytartype = -1; 268228753Smm /* 269228753Smm * The "template header" already includes the "ustar" 270228753Smm * signature, various end-of-field markers and other required 271228753Smm * elements. 272228753Smm */ 273228753Smm memcpy(h, &template_header, 512); 274228753Smm 275228753Smm /* 276228753Smm * Because the block is already null-filled, and strings 277228753Smm * are allowed to exactly fill their destination (without null), 278228753Smm * I use memcpy(dest, src, strlen()) here a lot to copy strings. 279228753Smm */ 280228753Smm 281228753Smm pp = archive_entry_pathname(entry); 282228753Smm if (strlen(pp) <= USTAR_name_size) 283228753Smm memcpy(h + USTAR_name_offset, pp, strlen(pp)); 284228753Smm else { 285228753Smm /* Store in two pieces, splitting at a '/'. */ 286228753Smm p = strchr(pp + strlen(pp) - USTAR_name_size - 1, '/'); 287228753Smm /* 288228753Smm * Look for the next '/' if we chose the first character 289228753Smm * as the separator. (ustar format doesn't permit 290228753Smm * an empty prefix.) 291228753Smm */ 292228753Smm if (p == pp) 293228753Smm p = strchr(p + 1, '/'); 294228753Smm /* Fail if the name won't fit. */ 295228753Smm if (!p) { 296228753Smm /* No separator. */ 297228753Smm archive_set_error(&a->archive, ENAMETOOLONG, 298228753Smm "Pathname too long"); 299228753Smm ret = ARCHIVE_FAILED; 300228753Smm } else if (p[1] == '\0') { 301228753Smm /* 302228753Smm * The only feasible separator is a final '/'; 303228753Smm * this would result in a non-empty prefix and 304228753Smm * an empty name, which POSIX doesn't 305228753Smm * explicity forbid, but it just feels wrong. 306228753Smm */ 307228753Smm archive_set_error(&a->archive, ENAMETOOLONG, 308228753Smm "Pathname too long"); 309228753Smm ret = ARCHIVE_FAILED; 310228753Smm } else if (p > pp + USTAR_prefix_size) { 311228753Smm /* Prefix is too long. */ 312228753Smm archive_set_error(&a->archive, ENAMETOOLONG, 313228753Smm "Pathname too long"); 314228753Smm ret = ARCHIVE_FAILED; 315228753Smm } else { 316228753Smm /* Copy prefix and remainder to appropriate places */ 317228753Smm memcpy(h + USTAR_prefix_offset, pp, p - pp); 318228753Smm memcpy(h + USTAR_name_offset, p + 1, pp + strlen(pp) - p - 1); 319228753Smm } 320228753Smm } 321228753Smm 322228753Smm p = archive_entry_hardlink(entry); 323228753Smm if (p != NULL) 324228753Smm mytartype = '1'; 325228753Smm else 326228753Smm p = archive_entry_symlink(entry); 327228753Smm if (p != NULL && p[0] != '\0') { 328228753Smm copy_length = strlen(p); 329228753Smm if (copy_length > USTAR_linkname_size) { 330228753Smm archive_set_error(&a->archive, ENAMETOOLONG, 331228753Smm "Link contents too long"); 332228753Smm ret = ARCHIVE_FAILED; 333228753Smm copy_length = USTAR_linkname_size; 334228753Smm } 335228753Smm memcpy(h + USTAR_linkname_offset, p, copy_length); 336228753Smm } 337228753Smm 338228753Smm p = archive_entry_uname(entry); 339228753Smm if (p != NULL && p[0] != '\0') { 340228753Smm copy_length = strlen(p); 341228753Smm if (copy_length > USTAR_uname_size) { 342228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 343228753Smm "Username too long"); 344228753Smm ret = ARCHIVE_FAILED; 345228753Smm copy_length = USTAR_uname_size; 346228753Smm } 347228753Smm memcpy(h + USTAR_uname_offset, p, copy_length); 348228753Smm } 349228753Smm 350228753Smm p = archive_entry_gname(entry); 351228753Smm if (p != NULL && p[0] != '\0') { 352228753Smm copy_length = strlen(p); 353228753Smm if (strlen(p) > USTAR_gname_size) { 354228753Smm archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 355228753Smm "Group name too long"); 356228753Smm ret = ARCHIVE_FAILED; 357228753Smm copy_length = USTAR_gname_size; 358228753Smm } 359228753Smm memcpy(h + USTAR_gname_offset, p, copy_length); 360228753Smm } 361228753Smm 362228753Smm if (format_number(archive_entry_mode(entry) & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) { 363228753Smm archive_set_error(&a->archive, ERANGE, "Numeric mode too large"); 364228753Smm ret = ARCHIVE_FAILED; 365228753Smm } 366228753Smm 367228753Smm if (format_number(archive_entry_uid(entry), h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) { 368228753Smm archive_set_error(&a->archive, ERANGE, "Numeric user ID too large"); 369228753Smm ret = ARCHIVE_FAILED; 370228753Smm } 371228753Smm 372228753Smm if (format_number(archive_entry_gid(entry), h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) { 373228753Smm archive_set_error(&a->archive, ERANGE, "Numeric group ID too large"); 374228753Smm ret = ARCHIVE_FAILED; 375228753Smm } 376228753Smm 377228753Smm if (format_number(archive_entry_size(entry), h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) { 378228753Smm archive_set_error(&a->archive, ERANGE, "File size out of range"); 379228753Smm ret = ARCHIVE_FAILED; 380228753Smm } 381228753Smm 382228753Smm if (format_number(archive_entry_mtime(entry), h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) { 383228753Smm archive_set_error(&a->archive, ERANGE, 384228753Smm "File modification time too large"); 385228753Smm ret = ARCHIVE_FAILED; 386228753Smm } 387228753Smm 388228753Smm if (archive_entry_filetype(entry) == AE_IFBLK 389228753Smm || archive_entry_filetype(entry) == AE_IFCHR) { 390228753Smm if (format_number(archive_entry_rdevmajor(entry), h + USTAR_rdevmajor_offset, 391228753Smm USTAR_rdevmajor_size, USTAR_rdevmajor_max_size, strict)) { 392228753Smm archive_set_error(&a->archive, ERANGE, 393228753Smm "Major device number too large"); 394228753Smm ret = ARCHIVE_FAILED; 395228753Smm } 396228753Smm 397228753Smm if (format_number(archive_entry_rdevminor(entry), h + USTAR_rdevminor_offset, 398228753Smm USTAR_rdevminor_size, USTAR_rdevminor_max_size, strict)) { 399228753Smm archive_set_error(&a->archive, ERANGE, 400228753Smm "Minor device number too large"); 401228753Smm ret = ARCHIVE_FAILED; 402228753Smm } 403228753Smm } 404228753Smm 405228753Smm if (tartype >= 0) { 406228753Smm h[USTAR_typeflag_offset] = tartype; 407228753Smm } else if (mytartype >= 0) { 408228753Smm h[USTAR_typeflag_offset] = mytartype; 409228753Smm } else { 410228753Smm switch (archive_entry_filetype(entry)) { 411228753Smm case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break; 412228753Smm case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break; 413228753Smm case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break; 414228753Smm case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break; 415228753Smm case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break; 416228753Smm case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break; 417228753Smm case AE_IFSOCK: 418228753Smm archive_set_error(&a->archive, 419228753Smm ARCHIVE_ERRNO_FILE_FORMAT, 420228753Smm "tar format cannot archive socket"); 421228753Smm return (ARCHIVE_FAILED); 422228753Smm default: 423228753Smm archive_set_error(&a->archive, 424228753Smm ARCHIVE_ERRNO_FILE_FORMAT, 425228753Smm "tar format cannot archive this (mode=0%lo)", 426228753Smm (unsigned long)archive_entry_mode(entry)); 427228753Smm ret = ARCHIVE_FAILED; 428228753Smm } 429228753Smm } 430228753Smm 431228753Smm checksum = 0; 432228753Smm for (i = 0; i < 512; i++) 433228753Smm checksum += 255 & (unsigned int)h[i]; 434228753Smm h[USTAR_checksum_offset + 6] = '\0'; /* Can't be pre-set in the template. */ 435228753Smm /* h[USTAR_checksum_offset + 7] = ' '; */ /* This is pre-set in the template. */ 436228753Smm format_octal(checksum, h + USTAR_checksum_offset, 6); 437228753Smm return (ret); 438228753Smm} 439228753Smm 440228753Smm/* 441228753Smm * Format a number into a field, with some intelligence. 442228753Smm */ 443228753Smmstatic int 444228753Smmformat_number(int64_t v, char *p, int s, int maxsize, int strict) 445228753Smm{ 446228753Smm int64_t limit; 447228753Smm 448228753Smm limit = ((int64_t)1 << (s*3)); 449228753Smm 450228753Smm /* "Strict" only permits octal values with proper termination. */ 451228753Smm if (strict) 452228753Smm return (format_octal(v, p, s)); 453228753Smm 454228753Smm /* 455228753Smm * In non-strict mode, we allow the number to overwrite one or 456228753Smm * more bytes of the field termination. Even old tar 457228753Smm * implementations should be able to handle this with no 458228753Smm * problem. 459228753Smm */ 460228753Smm if (v >= 0) { 461228753Smm while (s <= maxsize) { 462228753Smm if (v < limit) 463228753Smm return (format_octal(v, p, s)); 464228753Smm s++; 465228753Smm limit <<= 3; 466228753Smm } 467228753Smm } 468228753Smm 469228753Smm /* Base-256 can handle any number, positive or negative. */ 470228753Smm return (format_256(v, p, maxsize)); 471228753Smm} 472228753Smm 473228753Smm/* 474228753Smm * Format a number into the specified field using base-256. 475228753Smm */ 476228753Smmstatic int 477228753Smmformat_256(int64_t v, char *p, int s) 478228753Smm{ 479228753Smm p += s; 480228753Smm while (s-- > 0) { 481228753Smm *--p = (char)(v & 0xff); 482228753Smm v >>= 8; 483228753Smm } 484228753Smm *p |= 0x80; /* Set the base-256 marker bit. */ 485228753Smm return (0); 486228753Smm} 487228753Smm 488228753Smm/* 489228753Smm * Format a number into the specified field. 490228753Smm */ 491228753Smmstatic int 492228753Smmformat_octal(int64_t v, char *p, int s) 493228753Smm{ 494228753Smm int len; 495228753Smm 496228753Smm len = s; 497228753Smm 498228753Smm /* Octal values can't be negative, so use 0. */ 499228753Smm if (v < 0) { 500228753Smm while (len-- > 0) 501228753Smm *p++ = '0'; 502228753Smm return (-1); 503228753Smm } 504228753Smm 505228753Smm p += s; /* Start at the end and work backwards. */ 506228753Smm while (s-- > 0) { 507228753Smm *--p = (char)('0' + (v & 7)); 508228753Smm v >>= 3; 509228753Smm } 510228753Smm 511228753Smm if (v == 0) 512228753Smm return (0); 513228753Smm 514228753Smm /* If it overflowed, fill field with max value. */ 515228753Smm while (len-- > 0) 516228753Smm *p++ = '7'; 517228753Smm 518228753Smm return (-1); 519228753Smm} 520228753Smm 521228753Smmstatic int 522228753Smmarchive_write_ustar_finish(struct archive_write *a) 523228753Smm{ 524228753Smm int r; 525228753Smm 526228753Smm if (a->compressor.write == NULL) 527228753Smm return (ARCHIVE_OK); 528228753Smm 529228753Smm r = write_nulls(a, 512*2); 530228753Smm return (r); 531228753Smm} 532228753Smm 533228753Smmstatic int 534228753Smmarchive_write_ustar_destroy(struct archive_write *a) 535228753Smm{ 536228753Smm struct ustar *ustar; 537228753Smm 538228753Smm ustar = (struct ustar *)a->format_data; 539228753Smm free(ustar); 540228753Smm a->format_data = NULL; 541228753Smm return (ARCHIVE_OK); 542228753Smm} 543228753Smm 544228753Smmstatic int 545228753Smmarchive_write_ustar_finish_entry(struct archive_write *a) 546228753Smm{ 547228753Smm struct ustar *ustar; 548228753Smm int ret; 549228753Smm 550228753Smm ustar = (struct ustar *)a->format_data; 551228753Smm ret = write_nulls(a, 552228753Smm ustar->entry_bytes_remaining + ustar->entry_padding); 553228753Smm ustar->entry_bytes_remaining = ustar->entry_padding = 0; 554228753Smm return (ret); 555228753Smm} 556228753Smm 557228753Smmstatic int 558228753Smmwrite_nulls(struct archive_write *a, size_t padding) 559228753Smm{ 560228753Smm int ret; 561228753Smm size_t to_write; 562228753Smm 563228753Smm while (padding > 0) { 564228753Smm to_write = padding < a->null_length ? padding : a->null_length; 565228753Smm ret = (a->compressor.write)(a, a->nulls, to_write); 566228753Smm if (ret != ARCHIVE_OK) 567228753Smm return (ret); 568228753Smm padding -= to_write; 569228753Smm } 570228753Smm return (ARCHIVE_OK); 571228753Smm} 572228753Smm 573228753Smmstatic ssize_t 574228753Smmarchive_write_ustar_data(struct archive_write *a, const void *buff, size_t s) 575228753Smm{ 576228753Smm struct ustar *ustar; 577228753Smm int ret; 578228753Smm 579228753Smm ustar = (struct ustar *)a->format_data; 580228753Smm if (s > ustar->entry_bytes_remaining) 581228753Smm s = ustar->entry_bytes_remaining; 582228753Smm ret = (a->compressor.write)(a, buff, s); 583228753Smm ustar->entry_bytes_remaining -= s; 584228753Smm if (ret != ARCHIVE_OK) 585228753Smm return (ret); 586228753Smm return (s); 587228753Smm} 588