1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * Copyright (c) 2011-2012 Michihiro NAKAJIMA 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "archive_platform.h" 28 __FBSDID("$FreeBSD$"); 29 30 31 #ifdef HAVE_ERRNO_H 32 #include <errno.h> 33 #endif 34 #include <stdio.h> 35 #ifdef HAVE_STDLIB_H 36 #include <stdlib.h> 37 #endif 38 #ifdef HAVE_STRING_H 39 #include <string.h> 40 #endif 41 42 #include "archive.h" 43 #include "archive_entry.h" 44 #include "archive_entry_locale.h" 45 #include "archive_private.h" 46 #include "archive_write_private.h" 47 48 struct v7tar { 49 uint64_t entry_bytes_remaining; 50 uint64_t entry_padding; 51 52 struct archive_string_conv *opt_sconv; 53 struct archive_string_conv *sconv_default; 54 int init_default_conversion; 55 }; 56 57 /* 58 * Define structure of POSIX 'v7tar' tar header. 59 */ 60 #define V7TAR_name_offset 0 61 #define V7TAR_name_size 100 62 #define V7TAR_mode_offset 100 63 #define V7TAR_mode_size 6 64 #define V7TAR_mode_max_size 8 65 #define V7TAR_uid_offset 108 66 #define V7TAR_uid_size 6 67 #define V7TAR_uid_max_size 8 68 #define V7TAR_gid_offset 116 69 #define V7TAR_gid_size 6 70 #define V7TAR_gid_max_size 8 71 #define V7TAR_size_offset 124 72 #define V7TAR_size_size 11 73 #define V7TAR_size_max_size 12 74 #define V7TAR_mtime_offset 136 75 #define V7TAR_mtime_size 11 76 #define V7TAR_mtime_max_size 12 77 #define V7TAR_checksum_offset 148 78 #define V7TAR_checksum_size 8 79 #define V7TAR_typeflag_offset 156 80 #define V7TAR_typeflag_size 1 81 #define V7TAR_linkname_offset 157 82 #define V7TAR_linkname_size 100 83 #define V7TAR_padding_offset 257 84 #define V7TAR_padding_size 255 85 86 /* 87 * A filled-in copy of the header for initialization. 88 */ 89 static const char template_header[] = { 90 /* name: 100 bytes */ 91 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 92 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 93 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 94 0,0,0,0, 95 /* Mode, space-null termination: 8 bytes */ 96 '0','0','0','0','0','0', ' ','\0', 97 /* uid, space-null termination: 8 bytes */ 98 '0','0','0','0','0','0', ' ','\0', 99 /* gid, space-null termination: 8 bytes */ 100 '0','0','0','0','0','0', ' ','\0', 101 /* size, space termination: 12 bytes */ 102 '0','0','0','0','0','0','0','0','0','0','0', ' ', 103 /* mtime, space termination: 12 bytes */ 104 '0','0','0','0','0','0','0','0','0','0','0', ' ', 105 /* Initial checksum value: 8 spaces */ 106 ' ',' ',' ',' ',' ',' ',' ',' ', 107 /* Typeflag: 1 byte */ 108 0, 109 /* Linkname: 100 bytes */ 110 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 111 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 112 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 113 0,0,0,0, 114 /* Padding: 255 bytes */ 115 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 116 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 117 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 118 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 119 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 120 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 121 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 122 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0 123 }; 124 125 static ssize_t archive_write_v7tar_data(struct archive_write *a, const void *buff, 126 size_t s); 127 static int archive_write_v7tar_free(struct archive_write *); 128 static int archive_write_v7tar_close(struct archive_write *); 129 static int archive_write_v7tar_finish_entry(struct archive_write *); 130 static int archive_write_v7tar_header(struct archive_write *, 131 struct archive_entry *entry); 132 static int archive_write_v7tar_options(struct archive_write *, 133 const char *, const char *); 134 static int format_256(int64_t, char *, int); 135 static int format_number(int64_t, char *, int size, int max, int strict); 136 static int format_octal(int64_t, char *, int); 137 static int format_header_v7tar(struct archive_write *, char h[512], 138 struct archive_entry *, int, struct archive_string_conv *); 139 140 /* 141 * Set output format to 'v7tar' format. 142 */ 143 int 144 archive_write_set_format_v7tar(struct archive *_a) 145 { 146 struct archive_write *a = (struct archive_write *)_a; 147 struct v7tar *v7tar; 148 149 archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, 150 ARCHIVE_STATE_NEW, "archive_write_set_format_v7tar"); 151 152 /* If someone else was already registered, unregister them. */ 153 if (a->format_free != NULL) 154 (a->format_free)(a); 155 156 /* Basic internal sanity test. */ 157 if (sizeof(template_header) != 512) { 158 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 159 "Internal: template_header wrong size: %zu should be 512", 160 sizeof(template_header)); 161 return (ARCHIVE_FATAL); 162 } 163 164 v7tar = (struct v7tar *)calloc(1, sizeof(*v7tar)); 165 if (v7tar == NULL) { 166 archive_set_error(&a->archive, ENOMEM, 167 "Can't allocate v7tar data"); 168 return (ARCHIVE_FATAL); 169 } 170 a->format_data = v7tar; 171 a->format_name = "tar (non-POSIX)"; 172 a->format_options = archive_write_v7tar_options; 173 a->format_write_header = archive_write_v7tar_header; 174 a->format_write_data = archive_write_v7tar_data; 175 a->format_close = archive_write_v7tar_close; 176 a->format_free = archive_write_v7tar_free; 177 a->format_finish_entry = archive_write_v7tar_finish_entry; 178 a->archive.archive_format = ARCHIVE_FORMAT_TAR; 179 a->archive.archive_format_name = "tar (non-POSIX)"; 180 return (ARCHIVE_OK); 181 } 182 183 static int 184 archive_write_v7tar_options(struct archive_write *a, const char *key, 185 const char *val) 186 { 187 struct v7tar *v7tar = (struct v7tar *)a->format_data; 188 int ret = ARCHIVE_FAILED; 189 190 if (strcmp(key, "hdrcharset") == 0) { 191 if (val == NULL || val[0] == 0) 192 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 193 "%s: hdrcharset option needs a character-set name", 194 a->format_name); 195 else { 196 v7tar->opt_sconv = archive_string_conversion_to_charset( 197 &a->archive, val, 0); 198 if (v7tar->opt_sconv != NULL) 199 ret = ARCHIVE_OK; 200 else 201 ret = ARCHIVE_FATAL; 202 } 203 return (ret); 204 } 205 206 /* Note: The "warn" return is just to inform the options 207 * supervisor that we didn't handle it. It will generate 208 * a suitable error if no one used this option. */ 209 return (ARCHIVE_WARN); 210 } 211 212 static int 213 archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry) 214 { 215 char buff[512]; 216 int ret, ret2; 217 struct v7tar *v7tar; 218 struct archive_entry *entry_main; 219 struct archive_string_conv *sconv; 220 221 v7tar = (struct v7tar *)a->format_data; 222 223 /* Setup default string conversion. */ 224 if (v7tar->opt_sconv == NULL) { 225 if (!v7tar->init_default_conversion) { 226 v7tar->sconv_default = 227 archive_string_default_conversion_for_write( 228 &(a->archive)); 229 v7tar->init_default_conversion = 1; 230 } 231 sconv = v7tar->sconv_default; 232 } else 233 sconv = v7tar->opt_sconv; 234 235 /* Sanity check. */ 236 if (archive_entry_pathname(entry) == NULL) { 237 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 238 "Can't record entry in tar file without pathname"); 239 return (ARCHIVE_FAILED); 240 } 241 242 /* Only regular files (not hardlinks) have data. */ 243 if (archive_entry_hardlink(entry) != NULL || 244 archive_entry_symlink(entry) != NULL || 245 !(archive_entry_filetype(entry) == AE_IFREG)) 246 archive_entry_set_size(entry, 0); 247 248 if (AE_IFDIR == archive_entry_filetype(entry)) { 249 const char *p; 250 size_t path_length; 251 /* 252 * Ensure a trailing '/'. Modify the entry so 253 * the client sees the change. 254 */ 255 #if defined(_WIN32) && !defined(__CYGWIN__) 256 const wchar_t *wp; 257 258 wp = archive_entry_pathname_w(entry); 259 if (wp != NULL && wp[wcslen(wp) -1] != L'/') { 260 struct archive_wstring ws; 261 262 archive_string_init(&ws); 263 path_length = wcslen(wp); 264 if (archive_wstring_ensure(&ws, 265 path_length + 2) == NULL) { 266 archive_set_error(&a->archive, ENOMEM, 267 "Can't allocate v7tar data"); 268 archive_wstring_free(&ws); 269 return(ARCHIVE_FATAL); 270 } 271 /* Should we keep '\' ? */ 272 if (wp[path_length -1] == L'\\') 273 path_length--; 274 archive_wstrncpy(&ws, wp, path_length); 275 archive_wstrappend_wchar(&ws, L'/'); 276 archive_entry_copy_pathname_w(entry, ws.s); 277 archive_wstring_free(&ws); 278 p = NULL; 279 } else 280 #endif 281 p = archive_entry_pathname(entry); 282 /* 283 * On Windows, this is a backup operation just in 284 * case getting WCS failed. On POSIX, this is a 285 * normal operation. 286 */ 287 if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') { 288 struct archive_string as; 289 290 archive_string_init(&as); 291 path_length = strlen(p); 292 if (archive_string_ensure(&as, 293 path_length + 2) == NULL) { 294 archive_set_error(&a->archive, ENOMEM, 295 "Can't allocate v7tar data"); 296 archive_string_free(&as); 297 return(ARCHIVE_FATAL); 298 } 299 #if defined(_WIN32) && !defined(__CYGWIN__) 300 /* NOTE: This might break the pathname 301 * if the current code page is CP932 and 302 * the pathname includes a character '\' 303 * as a part of its multibyte pathname. */ 304 if (p[strlen(p) -1] == '\\') 305 path_length--; 306 else 307 #endif 308 archive_strncpy(&as, p, path_length); 309 archive_strappend_char(&as, '/'); 310 archive_entry_copy_pathname(entry, as.s); 311 archive_string_free(&as); 312 } 313 } 314 315 #if defined(_WIN32) && !defined(__CYGWIN__) 316 /* Make sure the path separators in pathname, hardlink and symlink 317 * are all slash '/', not the Windows path separator '\'. */ 318 entry_main = __la_win_entry_in_posix_pathseparator(entry); 319 if (entry_main == NULL) { 320 archive_set_error(&a->archive, ENOMEM, 321 "Can't allocate v7tar data"); 322 return(ARCHIVE_FATAL); 323 } 324 if (entry != entry_main) 325 entry = entry_main; 326 else 327 entry_main = NULL; 328 #else 329 entry_main = NULL; 330 #endif 331 ret = format_header_v7tar(a, buff, entry, 1, sconv); 332 if (ret < ARCHIVE_WARN) { 333 archive_entry_free(entry_main); 334 return (ret); 335 } 336 ret2 = __archive_write_output(a, buff, 512); 337 if (ret2 < ARCHIVE_WARN) { 338 archive_entry_free(entry_main); 339 return (ret2); 340 } 341 if (ret2 < ret) 342 ret = ret2; 343 344 v7tar->entry_bytes_remaining = archive_entry_size(entry); 345 v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining); 346 archive_entry_free(entry_main); 347 return (ret); 348 } 349 350 /* 351 * Format a basic 512-byte "v7tar" header. 352 * 353 * Returns -1 if format failed (due to field overflow). 354 * Note that this always formats as much of the header as possible. 355 * If "strict" is set to zero, it will extend numeric fields as 356 * necessary (overwriting terminators or using base-256 extensions). 357 * 358 */ 359 static int 360 format_header_v7tar(struct archive_write *a, char h[512], 361 struct archive_entry *entry, int strict, 362 struct archive_string_conv *sconv) 363 { 364 unsigned int checksum; 365 int i, r, ret; 366 size_t copy_length; 367 const char *p, *pp; 368 int mytartype; 369 370 ret = 0; 371 mytartype = -1; 372 /* 373 * The "template header" already includes the "v7tar" 374 * signature, various end-of-field markers and other required 375 * elements. 376 */ 377 memcpy(h, &template_header, 512); 378 379 /* 380 * Because the block is already null-filled, and strings 381 * are allowed to exactly fill their destination (without null), 382 * I use memcpy(dest, src, strlen()) here a lot to copy strings. 383 */ 384 r = archive_entry_pathname_l(entry, &pp, ©_length, sconv); 385 if (r != 0) { 386 if (errno == ENOMEM) { 387 archive_set_error(&a->archive, ENOMEM, 388 "Can't allocate memory for Pathname"); 389 return (ARCHIVE_FATAL); 390 } 391 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 392 "Can't translate pathname '%s' to %s", 393 pp, archive_string_conversion_charset_name(sconv)); 394 ret = ARCHIVE_WARN; 395 } 396 if (strict && copy_length < V7TAR_name_size) 397 memcpy(h + V7TAR_name_offset, pp, copy_length); 398 else if (!strict && copy_length <= V7TAR_name_size) 399 memcpy(h + V7TAR_name_offset, pp, copy_length); 400 else { 401 /* Prefix is too long. */ 402 archive_set_error(&a->archive, ENAMETOOLONG, 403 "Pathname too long"); 404 ret = ARCHIVE_FAILED; 405 } 406 407 r = archive_entry_hardlink_l(entry, &p, ©_length, sconv); 408 if (r != 0) { 409 if (errno == ENOMEM) { 410 archive_set_error(&a->archive, ENOMEM, 411 "Can't allocate memory for Linkname"); 412 return (ARCHIVE_FATAL); 413 } 414 archive_set_error(&a->archive, 415 ARCHIVE_ERRNO_FILE_FORMAT, 416 "Can't translate linkname '%s' to %s", 417 p, archive_string_conversion_charset_name(sconv)); 418 ret = ARCHIVE_WARN; 419 } 420 if (copy_length > 0) 421 mytartype = '1'; 422 else { 423 r = archive_entry_symlink_l(entry, &p, ©_length, sconv); 424 if (r != 0) { 425 if (errno == ENOMEM) { 426 archive_set_error(&a->archive, ENOMEM, 427 "Can't allocate memory for Linkname"); 428 return (ARCHIVE_FATAL); 429 } 430 archive_set_error(&a->archive, 431 ARCHIVE_ERRNO_FILE_FORMAT, 432 "Can't translate linkname '%s' to %s", 433 p, archive_string_conversion_charset_name(sconv)); 434 ret = ARCHIVE_WARN; 435 } 436 } 437 if (copy_length > 0) { 438 if (copy_length >= V7TAR_linkname_size) { 439 archive_set_error(&a->archive, ENAMETOOLONG, 440 "Link contents too long"); 441 ret = ARCHIVE_FAILED; 442 copy_length = V7TAR_linkname_size; 443 } 444 memcpy(h + V7TAR_linkname_offset, p, copy_length); 445 } 446 447 if (format_number(archive_entry_mode(entry) & 07777, 448 h + V7TAR_mode_offset, V7TAR_mode_size, 449 V7TAR_mode_max_size, strict)) { 450 archive_set_error(&a->archive, ERANGE, 451 "Numeric mode too large"); 452 ret = ARCHIVE_FAILED; 453 } 454 455 if (format_number(archive_entry_uid(entry), 456 h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) { 457 archive_set_error(&a->archive, ERANGE, 458 "Numeric user ID too large"); 459 ret = ARCHIVE_FAILED; 460 } 461 462 if (format_number(archive_entry_gid(entry), 463 h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) { 464 archive_set_error(&a->archive, ERANGE, 465 "Numeric group ID too large"); 466 ret = ARCHIVE_FAILED; 467 } 468 469 if (format_number(archive_entry_size(entry), 470 h + V7TAR_size_offset, V7TAR_size_size, 471 V7TAR_size_max_size, strict)) { 472 archive_set_error(&a->archive, ERANGE, 473 "File size out of range"); 474 ret = ARCHIVE_FAILED; 475 } 476 477 if (format_number(archive_entry_mtime(entry), 478 h + V7TAR_mtime_offset, V7TAR_mtime_size, 479 V7TAR_mtime_max_size, strict)) { 480 archive_set_error(&a->archive, ERANGE, 481 "File modification time too large"); 482 ret = ARCHIVE_FAILED; 483 } 484 485 if (mytartype >= 0) { 486 h[V7TAR_typeflag_offset] = mytartype; 487 } else { 488 switch (archive_entry_filetype(entry)) { 489 case AE_IFREG: case AE_IFDIR: 490 break; 491 case AE_IFLNK: 492 h[V7TAR_typeflag_offset] = '2'; 493 break; 494 case AE_IFCHR: 495 archive_set_error(&a->archive, 496 ARCHIVE_ERRNO_FILE_FORMAT, 497 "tar format cannot archive character device"); 498 return (ARCHIVE_FAILED); 499 case AE_IFBLK: 500 archive_set_error(&a->archive, 501 ARCHIVE_ERRNO_FILE_FORMAT, 502 "tar format cannot archive block device"); 503 return (ARCHIVE_FAILED); 504 case AE_IFIFO: 505 archive_set_error(&a->archive, 506 ARCHIVE_ERRNO_FILE_FORMAT, 507 "tar format cannot archive fifo"); 508 return (ARCHIVE_FAILED); 509 case AE_IFSOCK: 510 archive_set_error(&a->archive, 511 ARCHIVE_ERRNO_FILE_FORMAT, 512 "tar format cannot archive socket"); 513 return (ARCHIVE_FAILED); 514 default: 515 archive_set_error(&a->archive, 516 ARCHIVE_ERRNO_FILE_FORMAT, 517 "tar format cannot archive this (mode=0%lo)", 518 (unsigned long)archive_entry_mode(entry)); 519 ret = ARCHIVE_FAILED; 520 } 521 } 522 523 checksum = 0; 524 for (i = 0; i < 512; i++) 525 checksum += 255 & (unsigned int)h[i]; 526 format_octal(checksum, h + V7TAR_checksum_offset, 6); 527 /* Can't be pre-set in the template. */ 528 h[V7TAR_checksum_offset + 6] = '\0'; 529 return (ret); 530 } 531 532 /* 533 * Format a number into a field, with some intelligence. 534 */ 535 static int 536 format_number(int64_t v, char *p, int s, int maxsize, int strict) 537 { 538 int64_t limit; 539 540 limit = ((int64_t)1 << (s*3)); 541 542 /* "Strict" only permits octal values with proper termination. */ 543 if (strict) 544 return (format_octal(v, p, s)); 545 546 /* 547 * In non-strict mode, we allow the number to overwrite one or 548 * more bytes of the field termination. Even old tar 549 * implementations should be able to handle this with no 550 * problem. 551 */ 552 if (v >= 0) { 553 while (s <= maxsize) { 554 if (v < limit) 555 return (format_octal(v, p, s)); 556 s++; 557 limit <<= 3; 558 } 559 } 560 561 /* Base-256 can handle any number, positive or negative. */ 562 return (format_256(v, p, maxsize)); 563 } 564 565 /* 566 * Format a number into the specified field using base-256. 567 */ 568 static int 569 format_256(int64_t v, char *p, int s) 570 { 571 p += s; 572 while (s-- > 0) { 573 *--p = (char)(v & 0xff); 574 v >>= 8; 575 } 576 *p |= 0x80; /* Set the base-256 marker bit. */ 577 return (0); 578 } 579 580 /* 581 * Format a number into the specified field. 582 */ 583 static int 584 format_octal(int64_t v, char *p, int s) 585 { 586 int len; 587 588 len = s; 589 590 /* Octal values can't be negative, so use 0. */ 591 if (v < 0) { 592 while (len-- > 0) 593 *p++ = '0'; 594 return (-1); 595 } 596 597 p += s; /* Start at the end and work backwards. */ 598 while (s-- > 0) { 599 *--p = (char)('0' + (v & 7)); 600 v >>= 3; 601 } 602 603 if (v == 0) 604 return (0); 605 606 /* If it overflowed, fill field with max value. */ 607 while (len-- > 0) 608 *p++ = '7'; 609 610 return (-1); 611 } 612 613 static int 614 archive_write_v7tar_close(struct archive_write *a) 615 { 616 return (__archive_write_nulls(a, 512*2)); 617 } 618 619 static int 620 archive_write_v7tar_free(struct archive_write *a) 621 { 622 struct v7tar *v7tar; 623 624 v7tar = (struct v7tar *)a->format_data; 625 free(v7tar); 626 a->format_data = NULL; 627 return (ARCHIVE_OK); 628 } 629 630 static int 631 archive_write_v7tar_finish_entry(struct archive_write *a) 632 { 633 struct v7tar *v7tar; 634 int ret; 635 636 v7tar = (struct v7tar *)a->format_data; 637 ret = __archive_write_nulls(a, 638 (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding)); 639 v7tar->entry_bytes_remaining = v7tar->entry_padding = 0; 640 return (ret); 641 } 642 643 static ssize_t 644 archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s) 645 { 646 struct v7tar *v7tar; 647 int ret; 648 649 v7tar = (struct v7tar *)a->format_data; 650 if (s > v7tar->entry_bytes_remaining) 651 s = (size_t)v7tar->entry_bytes_remaining; 652 ret = __archive_write_output(a, buff, s); 653 v7tar->entry_bytes_remaining -= s; 654 if (ret != ARCHIVE_OK) 655 return (ret); 656 return (s); 657 } 658