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[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 if (entry_main) 334 archive_entry_free(entry_main); 335 return (ret); 336 } 337 ret2 = __archive_write_output(a, buff, 512); 338 if (ret2 < ARCHIVE_WARN) { 339 if (entry_main) 340 archive_entry_free(entry_main); 341 return (ret2); 342 } 343 if (ret2 < ret) 344 ret = ret2; 345 346 v7tar->entry_bytes_remaining = archive_entry_size(entry); 347 v7tar->entry_padding = 0x1ff & (-(int64_t)v7tar->entry_bytes_remaining); 348 if (entry_main) 349 archive_entry_free(entry_main); 350 return (ret); 351 } 352 353 /* 354 * Format a basic 512-byte "v7tar" header. 355 * 356 * Returns -1 if format failed (due to field overflow). 357 * Note that this always formats as much of the header as possible. 358 * If "strict" is set to zero, it will extend numeric fields as 359 * necessary (overwriting terminators or using base-256 extensions). 360 * 361 */ 362 static int 363 format_header_v7tar(struct archive_write *a, char h[512], 364 struct archive_entry *entry, int strict, 365 struct archive_string_conv *sconv) 366 { 367 unsigned int checksum; 368 int i, r, ret; 369 size_t copy_length; 370 const char *p, *pp; 371 int mytartype; 372 373 ret = 0; 374 mytartype = -1; 375 /* 376 * The "template header" already includes the "v7tar" 377 * signature, various end-of-field markers and other required 378 * elements. 379 */ 380 memcpy(h, &template_header, 512); 381 382 /* 383 * Because the block is already null-filled, and strings 384 * are allowed to exactly fill their destination (without null), 385 * I use memcpy(dest, src, strlen()) here a lot to copy strings. 386 */ 387 r = archive_entry_pathname_l(entry, &pp, ©_length, sconv); 388 if (r != 0) { 389 if (errno == ENOMEM) { 390 archive_set_error(&a->archive, ENOMEM, 391 "Can't allocate memory for Pathname"); 392 return (ARCHIVE_FATAL); 393 } 394 archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, 395 "Can't translate pathname '%s' to %s", 396 pp, archive_string_conversion_charset_name(sconv)); 397 ret = ARCHIVE_WARN; 398 } 399 if (strict && copy_length < V7TAR_name_size) 400 memcpy(h + V7TAR_name_offset, pp, copy_length); 401 else if (!strict && copy_length <= V7TAR_name_size) 402 memcpy(h + V7TAR_name_offset, pp, copy_length); 403 else { 404 /* Prefix is too long. */ 405 archive_set_error(&a->archive, ENAMETOOLONG, 406 "Pathname too long"); 407 ret = ARCHIVE_FAILED; 408 } 409 410 r = archive_entry_hardlink_l(entry, &p, ©_length, sconv); 411 if (r != 0) { 412 if (errno == ENOMEM) { 413 archive_set_error(&a->archive, ENOMEM, 414 "Can't allocate memory for Linkname"); 415 return (ARCHIVE_FATAL); 416 } 417 archive_set_error(&a->archive, 418 ARCHIVE_ERRNO_FILE_FORMAT, 419 "Can't translate linkname '%s' to %s", 420 p, archive_string_conversion_charset_name(sconv)); 421 ret = ARCHIVE_WARN; 422 } 423 if (copy_length > 0) 424 mytartype = '1'; 425 else { 426 r = archive_entry_symlink_l(entry, &p, ©_length, sconv); 427 if (r != 0) { 428 if (errno == ENOMEM) { 429 archive_set_error(&a->archive, ENOMEM, 430 "Can't allocate memory for Linkname"); 431 return (ARCHIVE_FATAL); 432 } 433 archive_set_error(&a->archive, 434 ARCHIVE_ERRNO_FILE_FORMAT, 435 "Can't translate linkname '%s' to %s", 436 p, archive_string_conversion_charset_name(sconv)); 437 ret = ARCHIVE_WARN; 438 } 439 } 440 if (copy_length > 0) { 441 if (copy_length >= V7TAR_linkname_size) { 442 archive_set_error(&a->archive, ENAMETOOLONG, 443 "Link contents too long"); 444 ret = ARCHIVE_FAILED; 445 copy_length = V7TAR_linkname_size; 446 } 447 memcpy(h + V7TAR_linkname_offset, p, copy_length); 448 } 449 450 if (format_number(archive_entry_mode(entry) & 07777, 451 h + V7TAR_mode_offset, V7TAR_mode_size, 452 V7TAR_mode_max_size, strict)) { 453 archive_set_error(&a->archive, ERANGE, 454 "Numeric mode too large"); 455 ret = ARCHIVE_FAILED; 456 } 457 458 if (format_number(archive_entry_uid(entry), 459 h + V7TAR_uid_offset, V7TAR_uid_size, V7TAR_uid_max_size, strict)) { 460 archive_set_error(&a->archive, ERANGE, 461 "Numeric user ID too large"); 462 ret = ARCHIVE_FAILED; 463 } 464 465 if (format_number(archive_entry_gid(entry), 466 h + V7TAR_gid_offset, V7TAR_gid_size, V7TAR_gid_max_size, strict)) { 467 archive_set_error(&a->archive, ERANGE, 468 "Numeric group ID too large"); 469 ret = ARCHIVE_FAILED; 470 } 471 472 if (format_number(archive_entry_size(entry), 473 h + V7TAR_size_offset, V7TAR_size_size, 474 V7TAR_size_max_size, strict)) { 475 archive_set_error(&a->archive, ERANGE, 476 "File size out of range"); 477 ret = ARCHIVE_FAILED; 478 } 479 480 if (format_number(archive_entry_mtime(entry), 481 h + V7TAR_mtime_offset, V7TAR_mtime_size, 482 V7TAR_mtime_max_size, strict)) { 483 archive_set_error(&a->archive, ERANGE, 484 "File modification time too large"); 485 ret = ARCHIVE_FAILED; 486 } 487 488 if (mytartype >= 0) { 489 h[V7TAR_typeflag_offset] = mytartype; 490 } else { 491 switch (archive_entry_filetype(entry)) { 492 case AE_IFREG: case AE_IFDIR: 493 break; 494 case AE_IFLNK: 495 h[V7TAR_typeflag_offset] = '2'; 496 break; 497 case AE_IFCHR: 498 archive_set_error(&a->archive, 499 ARCHIVE_ERRNO_FILE_FORMAT, 500 "tar format cannot archive character device"); 501 return (ARCHIVE_FAILED); 502 case AE_IFBLK: 503 archive_set_error(&a->archive, 504 ARCHIVE_ERRNO_FILE_FORMAT, 505 "tar format cannot archive block device"); 506 return (ARCHIVE_FAILED); 507 case AE_IFIFO: 508 archive_set_error(&a->archive, 509 ARCHIVE_ERRNO_FILE_FORMAT, 510 "tar format cannot archive fifo"); 511 return (ARCHIVE_FAILED); 512 case AE_IFSOCK: 513 archive_set_error(&a->archive, 514 ARCHIVE_ERRNO_FILE_FORMAT, 515 "tar format cannot archive socket"); 516 return (ARCHIVE_FAILED); 517 default: 518 archive_set_error(&a->archive, 519 ARCHIVE_ERRNO_FILE_FORMAT, 520 "tar format cannot archive this (mode=0%lo)", 521 (unsigned long)archive_entry_mode(entry)); 522 ret = ARCHIVE_FAILED; 523 } 524 } 525 526 checksum = 0; 527 for (i = 0; i < 512; i++) 528 checksum += 255 & (unsigned int)h[i]; 529 format_octal(checksum, h + V7TAR_checksum_offset, 6); 530 /* Can't be pre-set in the template. */ 531 h[V7TAR_checksum_offset + 6] = '\0'; 532 return (ret); 533 } 534 535 /* 536 * Format a number into a field, with some intelligence. 537 */ 538 static int 539 format_number(int64_t v, char *p, int s, int maxsize, int strict) 540 { 541 int64_t limit; 542 543 limit = ((int64_t)1 << (s*3)); 544 545 /* "Strict" only permits octal values with proper termination. */ 546 if (strict) 547 return (format_octal(v, p, s)); 548 549 /* 550 * In non-strict mode, we allow the number to overwrite one or 551 * more bytes of the field termination. Even old tar 552 * implementations should be able to handle this with no 553 * problem. 554 */ 555 if (v >= 0) { 556 while (s <= maxsize) { 557 if (v < limit) 558 return (format_octal(v, p, s)); 559 s++; 560 limit <<= 3; 561 } 562 } 563 564 /* Base-256 can handle any number, positive or negative. */ 565 return (format_256(v, p, maxsize)); 566 } 567 568 /* 569 * Format a number into the specified field using base-256. 570 */ 571 static int 572 format_256(int64_t v, char *p, int s) 573 { 574 p += s; 575 while (s-- > 0) { 576 *--p = (char)(v & 0xff); 577 v >>= 8; 578 } 579 *p |= 0x80; /* Set the base-256 marker bit. */ 580 return (0); 581 } 582 583 /* 584 * Format a number into the specified field. 585 */ 586 static int 587 format_octal(int64_t v, char *p, int s) 588 { 589 int len; 590 591 len = s; 592 593 /* Octal values can't be negative, so use 0. */ 594 if (v < 0) { 595 while (len-- > 0) 596 *p++ = '0'; 597 return (-1); 598 } 599 600 p += s; /* Start at the end and work backwards. */ 601 while (s-- > 0) { 602 *--p = (char)('0' + (v & 7)); 603 v >>= 3; 604 } 605 606 if (v == 0) 607 return (0); 608 609 /* If it overflowed, fill field with max value. */ 610 while (len-- > 0) 611 *p++ = '7'; 612 613 return (-1); 614 } 615 616 static int 617 archive_write_v7tar_close(struct archive_write *a) 618 { 619 return (__archive_write_nulls(a, 512*2)); 620 } 621 622 static int 623 archive_write_v7tar_free(struct archive_write *a) 624 { 625 struct v7tar *v7tar; 626 627 v7tar = (struct v7tar *)a->format_data; 628 free(v7tar); 629 a->format_data = NULL; 630 return (ARCHIVE_OK); 631 } 632 633 static int 634 archive_write_v7tar_finish_entry(struct archive_write *a) 635 { 636 struct v7tar *v7tar; 637 int ret; 638 639 v7tar = (struct v7tar *)a->format_data; 640 ret = __archive_write_nulls(a, 641 (size_t)(v7tar->entry_bytes_remaining + v7tar->entry_padding)); 642 v7tar->entry_bytes_remaining = v7tar->entry_padding = 0; 643 return (ret); 644 } 645 646 static ssize_t 647 archive_write_v7tar_data(struct archive_write *a, const void *buff, size_t s) 648 { 649 struct v7tar *v7tar; 650 int ret; 651 652 v7tar = (struct v7tar *)a->format_data; 653 if (s > v7tar->entry_bytes_remaining) 654 s = (size_t)v7tar->entry_bytes_remaining; 655 ret = __archive_write_output(a, buff, s); 656 v7tar->entry_bytes_remaining -= s; 657 if (ret != ARCHIVE_OK) 658 return (ret); 659 return (s); 660 } 661