| 353 |
set_next_block_after (pointer); |
set_next_block_after (pointer); |
| 354 |
} |
} |
| 355 |
|
|
| 356 |
/* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */ |
/* Write a "private" header */ |
| 357 |
|
static union block * |
| 358 |
|
start_private_header (const char *name, size_t size) |
| 359 |
|
{ |
| 360 |
|
time_t t; |
| 361 |
|
union block *header = find_next_block (); |
| 362 |
|
|
| 363 |
|
memset (header->buffer, 0, sizeof (union block)); |
| 364 |
|
|
| 365 |
|
strncpy (header->header.name, name, NAME_FIELD_SIZE); |
| 366 |
|
header->header.name[NAME_FIELD_SIZE - 1] = '\0'; |
| 367 |
|
OFF_TO_CHARS (size, header->header.size); |
| 368 |
|
|
| 369 |
|
time (&t); |
| 370 |
|
TIME_TO_CHARS (t, header->header.mtime); |
| 371 |
|
MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode); |
| 372 |
|
UID_TO_CHARS (getuid (), header->header.uid); |
| 373 |
|
GID_TO_CHARS (getgid (), header->header.gid); |
| 374 |
|
MAJOR_TO_CHARS (0, header->header.devmajor); |
| 375 |
|
MAJOR_TO_CHARS (0, header->header.devminor); |
| 376 |
|
strncpy (header->header.magic, TMAGIC, TMAGLEN); |
| 377 |
|
strncpy (header->header.version, TVERSION, TVERSLEN); |
| 378 |
|
return header; |
| 379 |
|
} |
| 380 |
|
|
| 381 |
/* FIXME: Cross recursion between start_header and write_long! */ |
/* Create a new header and store there at most NAME_FIELD_SIZE bytes of |
| 382 |
|
the file name */ |
| 383 |
|
|
| 384 |
static union block *start_header (const char *, struct tar_stat_info *); |
static union block * |
| 385 |
|
write_short_name (struct tar_stat_info *st) |
| 386 |
|
{ |
| 387 |
|
union block *header = find_next_block (); |
| 388 |
|
memset (header->buffer, 0, sizeof (union block)); |
| 389 |
|
|
| 390 |
|
strncpy (header->header.name, st->file_name, NAME_FIELD_SIZE); |
| 391 |
|
header->header.name[NAME_FIELD_SIZE - 1] = '\0'; |
| 392 |
|
return header; |
| 393 |
|
} |
| 394 |
|
|
| 395 |
|
/* Write a GNUTYPE_LONGLINK or GNUTYPE_LONGNAME block. */ |
| 396 |
static void |
static void |
| 397 |
write_long (const char *p, char type) |
write_gnu_long_link (const char *p, char type) |
| 398 |
{ |
{ |
| 399 |
size_t size = strlen (p) + 1; |
size_t size = strlen (p) + 1; |
| 400 |
size_t bufsize; |
size_t bufsize; |
| 401 |
union block *header; |
union block *header; |
|
struct tar_stat_info foo; |
|
|
|
|
|
memset (&foo, 0, sizeof foo); |
|
|
foo.stat.st_size = size; |
|
| 402 |
|
|
| 403 |
header = start_header ("././@LongLink", &foo); |
header = start_private_header ("././@LongLink", size); |
| 404 |
header->header.typeflag = type; |
header->header.typeflag = type; |
| 405 |
finish_header (header, -1); |
finish_header (header, -1); |
| 406 |
|
|
| 422 |
set_next_block_after (header + (size - 1) / BLOCKSIZE); |
set_next_block_after (header + (size - 1) / BLOCKSIZE); |
| 423 |
} |
} |
| 424 |
|
|
| 425 |
|
static size_t |
| 426 |
|
split_long_name (const char *name, size_t length) |
| 427 |
|
{ |
| 428 |
|
size_t i; |
| 429 |
|
|
| 430 |
|
if (length > PREFIX_FIELD_SIZE) |
| 431 |
|
length = PREFIX_FIELD_SIZE+2; |
| 432 |
|
for (i = length - 1; i > 0; i--) |
| 433 |
|
if (ISSLASH (name[i])) |
| 434 |
|
break; |
| 435 |
|
return i; |
| 436 |
|
} |
| 437 |
|
|
| 438 |
|
static union block * |
| 439 |
|
write_ustar_long_name (const char *name) |
| 440 |
|
{ |
| 441 |
|
size_t length = strlen (name); |
| 442 |
|
size_t i; |
| 443 |
|
union block *header; |
| 444 |
|
|
| 445 |
|
if (length > PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1) |
| 446 |
|
{ |
| 447 |
|
WARN ((0, 0, _("%s: file name is too long (max %d); not dumped"), |
| 448 |
|
quotearg_colon (name), |
| 449 |
|
PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1)); |
| 450 |
|
return NULL; |
| 451 |
|
} |
| 452 |
|
|
| 453 |
|
i = split_long_name (name, length); |
| 454 |
|
if (i == 0) |
| 455 |
|
{ |
| 456 |
|
WARN ((0, 0, |
| 457 |
|
_("%s: file name is too long (cannot be split); not dumped"), |
| 458 |
|
quotearg_colon (name), |
| 459 |
|
PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1)); |
| 460 |
|
return NULL; |
| 461 |
|
} |
| 462 |
|
|
| 463 |
|
header = find_next_block (); |
| 464 |
|
memset (header->buffer, 0, sizeof (header->buffer)); |
| 465 |
|
memcpy (header->header.prefix, name, i); |
| 466 |
|
memcpy (header->header.name, name + i + 1, length - i); |
| 467 |
|
|
| 468 |
|
return header; |
| 469 |
|
} |
| 470 |
|
|
| 471 |
/* Write a long link name, depending on the current archive format */ |
/* Write a long link name, depending on the current archive format */ |
| 472 |
static void |
static void |
| 473 |
write_long_link (struct tar_stat_info *st) |
write_long_link (struct tar_stat_info *st) |
| 474 |
{ |
{ |
| 475 |
if (archive_format == POSIX_FORMAT) |
switch (archive_format) |
| 476 |
xheader_store ("linkpath", st); |
{ |
| 477 |
else |
case POSIX_FORMAT: |
| 478 |
write_long (st->link_name, GNUTYPE_LONGNAME); |
xheader_store ("linkpath", st); |
| 479 |
|
break; |
| 480 |
|
|
| 481 |
|
case V7_FORMAT: /* old V7 tar format */ |
| 482 |
|
case USTAR_FORMAT: |
| 483 |
|
case STAR_FORMAT: |
| 484 |
|
WARN ((0, 0, |
| 485 |
|
_("%s: link name is too long; not dumped"), |
| 486 |
|
quotearg_colon (st->link_name))); |
| 487 |
|
break; |
| 488 |
|
|
| 489 |
|
case OLDGNU_FORMAT: |
| 490 |
|
case GNU_FORMAT: |
| 491 |
|
write_gnu_long_link (st->link_name, GNUTYPE_LONGLINK); |
| 492 |
|
break; |
| 493 |
|
|
| 494 |
|
default: |
| 495 |
|
abort(); /*FIXME*/ |
| 496 |
|
} |
| 497 |
} |
} |
| 498 |
|
|
| 499 |
/* NOTE: Cross recursion between start_header and write_extended */ |
static union block * |
| 500 |
|
write_long_name (struct tar_stat_info *st) |
| 501 |
|
{ |
| 502 |
|
switch (archive_format) |
| 503 |
|
{ |
| 504 |
|
case POSIX_FORMAT: |
| 505 |
|
xheader_store ("path", st); |
| 506 |
|
break; |
| 507 |
|
|
| 508 |
|
case V7_FORMAT: |
| 509 |
|
case USTAR_FORMAT: |
| 510 |
|
case STAR_FORMAT: |
| 511 |
|
return write_ustar_long_name (st->file_name); |
| 512 |
|
|
| 513 |
|
case OLDGNU_FORMAT: |
| 514 |
|
case GNU_FORMAT: |
| 515 |
|
write_gnu_long_link (st->file_name, GNUTYPE_LONGNAME); |
| 516 |
|
break; |
| 517 |
|
|
| 518 |
|
default: |
| 519 |
|
abort(); /*FIXME*/ |
| 520 |
|
} |
| 521 |
|
return write_short_name (st); |
| 522 |
|
} |
| 523 |
|
|
| 524 |
static union block * |
static union block * |
| 525 |
write_extended (union block *old_header, char type) |
write_extended (union block *old_header, char type) |
| 530 |
char *p; |
char *p; |
| 531 |
|
|
| 532 |
if (extended_header.buffer || extended_header.stk == NULL) |
if (extended_header.buffer || extended_header.stk == NULL) |
| 533 |
return old_header; /* Prevent recursion */ |
return old_header; |
| 534 |
|
|
| 535 |
xheader_finish (&extended_header); |
xheader_finish (&extended_header); |
| 536 |
size = extended_header.size; |
size = extended_header.size; |
|
memset (&foo, 0, sizeof foo); |
|
|
foo.stat.st_mode = S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; |
|
|
time (&foo.stat.st_ctime); |
|
|
foo.stat.st_atime = foo.stat.st_ctime; |
|
|
foo.stat.st_mtime = foo.stat.st_ctime; |
|
|
foo.stat.st_size = size; |
|
| 537 |
|
|
| 538 |
memcpy (hp.buffer, old_header, sizeof (hp)); |
memcpy (hp.buffer, old_header, sizeof (hp)); |
| 539 |
|
|
| 540 |
header = start_header ("././@PaxHeader", &foo); |
header = start_private_header ("././@PaxHeader", size); |
| 541 |
header->header.typeflag = type; |
header->header.typeflag = type; |
| 542 |
|
|
| 543 |
finish_header (header, -1); |
finish_header (header, -1); |
| 560 |
set_next_block_after (header); |
set_next_block_after (header); |
| 561 |
} |
} |
| 562 |
while (size > 0); |
while (size > 0); |
| 563 |
|
|
| 564 |
xheader_destroy (&extended_header); |
xheader_destroy (&extended_header); |
| 565 |
header = find_next_block (); |
header = find_next_block (); |
| 566 |
memcpy (header, &hp.buffer, sizeof (hp.buffer)); |
memcpy (header, &hp.buffer, sizeof (hp.buffer)); |
| 567 |
return header; |
return header; |
| 568 |
} |
} |
| 569 |
|
|
| 570 |
|
static union block * |
| 571 |
|
write_header_name (struct tar_stat_info *st) |
| 572 |
|
{ |
| 573 |
|
if (NAME_FIELD_SIZE <= strlen (st->file_name)) |
| 574 |
|
return write_long_name (st); |
| 575 |
|
else |
| 576 |
|
return write_short_name (st); |
| 577 |
|
} |
| 578 |
|
|
| 579 |
|
|
| 580 |
/* Header handling. */ |
/* Header handling. */ |
| 581 |
|
|
| 588 |
union block *header; |
union block *header; |
| 589 |
|
|
| 590 |
name = safer_name_suffix (name, 0); |
name = safer_name_suffix (name, 0); |
| 591 |
|
if (name[0] == '.' && name[1] == 0) /*FIXME!!!*/ |
| 592 |
|
return NULL; |
| 593 |
assign_string (&st->file_name, name); |
assign_string (&st->file_name, name); |
| 594 |
|
|
| 595 |
if (sizeof header->header.name <= strlen (name)) |
header = write_header_name (st); |
| 596 |
{ |
if (!header) |
| 597 |
if (archive_format == POSIX_FORMAT) |
return NULL; |
|
xheader_store ("path", st); |
|
|
else |
|
|
write_long (name, GNUTYPE_LONGNAME); |
|
|
} |
|
|
|
|
|
header = find_next_block (); |
|
|
memset (header->buffer, 0, sizeof (union block)); |
|
| 598 |
|
|
| 599 |
assign_string (¤t_stat_info.file_name, name); |
assign_string (¤t_stat_info.file_name, name); |
| 600 |
|
|
|
strncpy (header->header.name, name, NAME_FIELD_SIZE); |
|
|
header->header.name[NAME_FIELD_SIZE - 1] = '\0'; |
|
|
|
|
| 601 |
/* Override some stat fields, if requested to do so. */ |
/* Override some stat fields, if requested to do so. */ |
| 602 |
|
|
| 603 |
if (owner_option != (uid_t) -1) |
if (owner_option != (uid_t) -1) |
| 631 |
above, thus making GNU tar both a universal donor and a universal |
above, thus making GNU tar both a universal donor and a universal |
| 632 |
acceptor for Paul's test. */ |
acceptor for Paul's test. */ |
| 633 |
|
|
| 634 |
if (archive_format == V7_FORMAT) |
if (archive_format == V7_FORMAT || archive_format == USTAR_FORMAT) |
| 635 |
MODE_TO_CHARS (st->stat.st_mode & MODE_ALL, header->header.mode); |
MODE_TO_CHARS (st->stat.st_mode & MODE_ALL, header->header.mode); |
| 636 |
else |
else |
| 637 |
MODE_TO_CHARS (st->stat.st_mode, header->header.mode); |
MODE_TO_CHARS (st->stat.st_mode, header->header.mode); |
| 701 |
break; |
break; |
| 702 |
|
|
| 703 |
case POSIX_FORMAT: |
case POSIX_FORMAT: |
| 704 |
case GNU_FORMAT: |
case USTAR_FORMAT: |
| 705 |
|
case GNU_FORMAT: /*FIXME?*/ |
| 706 |
strncpy (header->header.magic, TMAGIC, TMAGLEN); |
strncpy (header->header.magic, TMAGIC, TMAGLEN); |
| 707 |
strncpy (header->header.version, TVERSION, TVERSLEN); |
strncpy (header->header.version, TVERSION, TVERSLEN); |
| 708 |
break; |
break; |
| 1227 |
files, we'd better put the / on the name. */ |
files, we'd better put the / on the name. */ |
| 1228 |
|
|
| 1229 |
header = start_header (namebuf, ¤t_stat_info); |
header = start_header (namebuf, ¤t_stat_info); |
| 1230 |
|
if (!header) |
| 1231 |
|
return; |
| 1232 |
|
|
| 1233 |
if (incremental_option) |
if (incremental_option) |
| 1234 |
header->header.typeflag = GNUTYPE_DUMPDIR; |
header->header.typeflag = GNUTYPE_DUMPDIR; |
| 1235 |
else /* if (standard_option) */ |
else /* if (standard_option) */ |
| 1363 |
|
|
| 1364 |
current_stat_info.stat.st_size = 0; |
current_stat_info.stat.st_size = 0; |
| 1365 |
header = start_header (p, ¤t_stat_info); |
header = start_header (p, ¤t_stat_info); |
| 1366 |
|
if (!header) |
| 1367 |
|
return; |
| 1368 |
strncpy (header->header.linkname, link_name, NAME_FIELD_SIZE); |
strncpy (header->header.linkname, link_name, NAME_FIELD_SIZE); |
| 1369 |
|
|
| 1370 |
/* Force null termination. */ |
/* Force null termination. */ |
| 1441 |
|
|
| 1442 |
block_ordinal = current_block_ordinal (); |
block_ordinal = current_block_ordinal (); |
| 1443 |
header = start_header (p, ¤t_stat_info); |
header = start_header (p, ¤t_stat_info); |
| 1444 |
|
if (!header) |
| 1445 |
|
return; |
| 1446 |
header->header.typeflag = GNUTYPE_SPARSE; |
header->header.typeflag = GNUTYPE_SPARSE; |
| 1447 |
header_moved = 1; |
header_moved = 1; |
| 1448 |
|
|
| 1514 |
{ |
{ |
| 1515 |
block_ordinal = current_block_ordinal (); |
block_ordinal = current_block_ordinal (); |
| 1516 |
header = start_header (p, ¤t_stat_info); |
header = start_header (p, ¤t_stat_info); |
| 1517 |
|
if (!header) |
| 1518 |
|
return; |
| 1519 |
} |
} |
| 1520 |
|
|
| 1521 |
/* Mark contiguous files, if we support them. */ |
/* Mark contiguous files, if we support them. */ |
| 1522 |
|
|
| 1523 |
if (archive_format != V7_FORMAT && S_ISCTG (current_stat_info.stat.st_mode)) |
if (archive_format != V7_FORMAT |
| 1524 |
|
&& S_ISCTG (current_stat_info.stat.st_mode)) |
| 1525 |
header->header.typeflag = CONTTYPE; |
header->header.typeflag = CONTTYPE; |
| 1526 |
|
|
| 1527 |
isextended = header->oldgnu_header.isextended; |
if (archive_format == GNU_FORMAT || archive_format == OLDGNU_FORMAT) |
| 1528 |
|
isextended = header->oldgnu_header.isextended; |
| 1529 |
|
else |
| 1530 |
|
isextended = 0; |
| 1531 |
|
if (isextended) |
| 1532 |
|
abort(); |
| 1533 |
save_typeflag = header->header.typeflag; |
save_typeflag = header->header.typeflag; |
| 1534 |
finish_header (header, block_ordinal); |
finish_header (header, block_ordinal); |
| 1535 |
if (isextended) |
if (isextended) |
| 1705 |
block_ordinal = current_block_ordinal (); |
block_ordinal = current_block_ordinal (); |
| 1706 |
current_stat_info.stat.st_size = 0; /* force 0 size on symlink */ |
current_stat_info.stat.st_size = 0; /* force 0 size on symlink */ |
| 1707 |
header = start_header (p, ¤t_stat_info); |
header = start_header (p, ¤t_stat_info); |
| 1708 |
|
if (!header) |
| 1709 |
|
return; |
| 1710 |
strncpy (header->header.linkname, buffer, NAME_FIELD_SIZE); |
strncpy (header->header.linkname, buffer, NAME_FIELD_SIZE); |
| 1711 |
header->header.linkname[NAME_FIELD_SIZE - 1] = '\0'; |
header->header.linkname[NAME_FIELD_SIZE - 1] = '\0'; |
| 1712 |
header->header.typeflag = SYMTYPE; |
header->header.typeflag = SYMTYPE; |
| 1747 |
block_ordinal = current_block_ordinal (); |
block_ordinal = current_block_ordinal (); |
| 1748 |
current_stat_info.stat.st_size = 0; /* force 0 size */ |
current_stat_info.stat.st_size = 0; /* force 0 size */ |
| 1749 |
header = start_header (p, ¤t_stat_info); |
header = start_header (p, ¤t_stat_info); |
| 1750 |
|
if (!header) |
| 1751 |
|
return; |
| 1752 |
header->header.typeflag = type; |
header->header.typeflag = type; |
| 1753 |
|
|
| 1754 |
if (type != FIFOTYPE) |
if (type != FIFOTYPE) |