X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2Fbuffer.c;h=e590e12834280f52400b3d2a797c7106b0033d39;hb=3af9cc0f1550e8c882f1a017727d41b54674c2d5;hp=36a0cfddcfeaa2206d98bb4fefc831f46101a1fa;hpb=dfd87ba1d05777ed29fce769996de9fe3010911c;p=chaz%2Ftar diff --git a/src/buffer.c b/src/buffer.c index 36a0cfd..e590e12 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,7 +1,7 @@ /* Buffer management for tar. Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, - 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-25. @@ -198,11 +198,13 @@ compute_duration () /* Compression detection */ enum compress_type { - ct_none, + ct_tar, /* Plain tar file */ + ct_none, /* Unknown compression type */ ct_compress, ct_gzip, ct_bzip2, - ct_lzma + ct_lzma, + ct_lzop }; struct zip_magic @@ -215,11 +217,13 @@ struct zip_magic }; static struct zip_magic const magic[] = { + { ct_tar }, { ct_none, }, { ct_compress, 2, "\037\235", "compress", "-Z" }, { ct_gzip, 2, "\037\213", "gzip", "-z" }, { ct_bzip2, 3, "BZh", "bzip2", "-j" }, - { ct_lzma, 6, "\xFFLZMA", "lzma", "--lzma" }, /* FIXME: ???? */ + { ct_lzma, 6, "\xFFLZMA", "lzma", "-J" }, /* FIXME: ???? */ + { ct_lzop, 4, "\211LZO", "lzop", "--lzop" }, }; #define NMAGIC (sizeof(magic)/sizeof(magic[0])) @@ -229,34 +233,33 @@ static struct zip_magic const magic[] = { /* Check if the file ARCHIVE is a compressed archive. */ enum compress_type -check_compressed_archive () +check_compressed_archive (bool *pshort) { struct zip_magic const *p; bool sfr; - bool short_file = false; + bool temp; + + if (!pshort) + pshort = &temp; /* Prepare global data needed for find_next_block: */ record_end = record_start; /* set up for 1st record = # 0 */ sfr = read_full_records; read_full_records = true; /* Suppress fatal error on reading a partial record */ - if (find_next_block () == 0) - short_file = true; + *pshort = find_next_block () == 0; /* Restore global values */ read_full_records = sfr; if (tar_checksum (record_start, true) == HEADER_SUCCESS) /* Probably a valid header */ - return ct_none; + return ct_tar; - for (p = magic + 1; p < magic + NMAGIC; p++) + for (p = magic + 2; p < magic + NMAGIC; p++) if (memcmp (record_start->buffer, p->magic, p->length) == 0) return p->type; - if (short_file) - ERROR ((0, 0, _("This does not look like a tar archive"))); - return ct_none; } @@ -273,11 +276,32 @@ open_compressed_archive () if (!multi_volume_option) { - enum compress_type type = check_compressed_archive (); + if (!use_compress_program_option) + { + bool shortfile; + enum compress_type type = check_compressed_archive (&shortfile); - if (type == ct_none) - return archive; + switch (type) + { + case ct_tar: + if (shortfile) + ERROR ((0, 0, _("This does not look like a tar archive"))); + return archive; + + case ct_none: + if (shortfile) + ERROR ((0, 0, _("This does not look like a tar archive"))); + set_comression_program_by_suffix (archive_name_array[0], NULL); + if (!use_compress_program_option) + return archive; + break; + default: + use_compress_program_option = compress_program (type); + break; + } + } + /* FD is not needed any more */ rmtclose (archive); @@ -285,7 +309,6 @@ open_compressed_archive () check_compressed_archive */ /* Open compressed archive */ - use_compress_program_option = compress_program (type); child_pid = sys_child_open_for_uncompress (); read_full_records = true; } @@ -502,15 +525,18 @@ _open_archive (enum access_mode wanted_access) { case ACCESS_READ: { + bool shortfile; enum compress_type type; archive = STDIN_FILENO; - type = check_compressed_archive (); - if (type != ct_none) + type = check_compressed_archive (&shortfile); + if (type != ct_tar && type != ct_none) FATAL_ERROR ((0, 0, _("Archive is compressed. Use %s option"), compress_option (type))); + if (shortfile) + ERROR ((0, 0, _("This does not look like a tar archive"))); } break; @@ -554,9 +580,16 @@ _open_archive (enum access_mode wanted_access) O_RDWR | O_CREAT | O_BINARY, MODE_RW, rsh_command_option); - if (check_compressed_archive () != ct_none) - FATAL_ERROR ((0, 0, - _("Cannot update compressed archives"))); + switch (check_compressed_archive (NULL)) + { + case ct_none: + case ct_tar: + break; + + default: + FATAL_ERROR ((0, 0, + _("Cannot update compressed archives"))); + } break; } @@ -826,7 +859,7 @@ close_archive (void) verify_volume (); if (rmtclose (archive) != 0) - close_warn (*archive_name_cursor); + close_error (*archive_name_cursor); sys_wait_for_child (child_pid); @@ -1014,7 +1047,7 @@ new_volume (enum access_mode mode) current_block = record_start; if (rmtclose (archive) != 0) - close_warn (*archive_name_cursor); + close_error (*archive_name_cursor); archive_name_cursor++; if (archive_name_cursor == archive_name_array + archive_names) @@ -1217,7 +1250,15 @@ try_new_volume () if (real_s_totsize - real_s_sizeleft != continued_file_offset) { - WARN ((0, 0, _("This volume is out of sequence"))); + char totsizebuf[UINTMAX_STRSIZE_BOUND]; + char s1buf[UINTMAX_STRSIZE_BOUND]; + char s2buf[UINTMAX_STRSIZE_BOUND]; + + WARN ((0, 0, _("This volume is out of sequence (%s - %s != %s)"), + STRINGIFY_BIGINT (real_s_totsize, totsizebuf), + STRINGIFY_BIGINT (real_s_sizeleft, s1buf), + STRINGIFY_BIGINT (continued_file_offset, s2buf))); + return false; } } @@ -1558,13 +1599,15 @@ _gnu_flush_write (size_t buffer_level) char *copy_ptr; size_t copy_size; size_t bufsize; - + tarlong wrt; + status = _flush_write (); if (status != record_size && !multi_volume_option) archive_write_error (status); else { - records_written++; + if (status) + records_written++; bytes_written += status; } @@ -1574,11 +1617,18 @@ _gnu_flush_write (size_t buffer_level) return; } + if (status % BLOCKSIZE) + { + ERROR ((0, 0, _("write did not end on a block boundary"))); + archive_write_error (status); + } + /* In multi-volume mode. */ /* ENXIO is for the UNIX PC. */ if (status < 0 && errno != ENOSPC && errno != EIO && errno != ENXIO) archive_write_error (status); + real_s_sizeleft -= status; if (!new_volume (ACCESS_WRITE)) return; @@ -1590,6 +1640,7 @@ _gnu_flush_write (size_t buffer_level) copy_ptr = record_start->buffer + status; copy_size = buffer_level - status; + /* Switch to the next buffer */ record_index = !record_index; init_buffer (); @@ -1605,6 +1656,7 @@ _gnu_flush_write (size_t buffer_level) if (real_s_name) add_chunk_header (); + wrt = bytes_written; header = find_next_block (); bufsize = available_space_after (header); while (bufsize < copy_size) @@ -1619,6 +1671,16 @@ _gnu_flush_write (size_t buffer_level) memcpy (header->buffer, copy_ptr, copy_size); memset (header->buffer + copy_size, 0, bufsize - copy_size); set_next_block_after (header + (copy_size - 1) / BLOCKSIZE); + if (multi_volume_option && wrt < bytes_written) + { + /* The value of bytes_written has changed while moving data; + that means that flush_archive was executed at least once in + between, and, as a consequence, copy_size bytes were not written + to disk. We need to update sizeleft variables to compensate for + that. */ + save_sizeleft += copy_size; + multi_volume_sync (); + } find_next_block (); }