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