X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2Fbuffer.c;h=e590e12834280f52400b3d2a797c7106b0033d39;hb=3af9cc0f1550e8c882f1a017727d41b54674c2d5;hp=13e1c139048603bc2e6d5a339b83247754e3a705;hpb=a0fb51e136d3df620eb3189683aae90b25bd8dd7;p=chaz%2Ftar diff --git a/src/buffer.c b/src/buffer.c index 13e1c13..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. @@ -26,7 +26,6 @@ #include #include -#include #include #include @@ -75,9 +74,6 @@ static int read_error_count; /* Have we hit EOF yet? */ static bool hit_eof; -/* Checkpointing counter */ -static unsigned checkpoint; - static bool read_full_records = false; /* We're reading, but we just read the last block and it's time to update. @@ -202,10 +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_bzip2, + ct_lzma, + ct_lzop }; struct zip_magic @@ -218,10 +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", "-J" }, /* FIXME: ???? */ + { ct_lzop, 4, "\211LZO", "lzop", "--lzop" }, }; #define NMAGIC (sizeof(magic)/sizeof(magic[0])) @@ -231,26 +233,30 @@ 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 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 */ - find_next_block (); - + *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; @@ -270,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); @@ -282,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; } @@ -499,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; @@ -551,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; } @@ -585,43 +621,13 @@ _open_archive (enum access_mode wanted_access) } } -static void -do_checkpoint (bool write) -{ - if (checkpoint_option && !(++checkpoint % checkpoint_option)) - { - switch (checkpoint_style) - { - case checkpoint_dot: - fputc ('.', stdlis); - fflush (stdlis); - break; - - case checkpoint_text: - if (write) - /* TRANSLATORS: This is a ``checkpoint of write operation'', - *not* ``Writing a checkpoint''. - E.g. in Spanish ``Punto de comprobaci@'on de escritura'', - *not* ``Escribiendo un punto de comprobaci@'on'' */ - WARN ((0, 0, _("Write checkpoint %u"), checkpoint)); - else - /* TRANSLATORS: This is a ``checkpoint of read operation'', - *not* ``Reading a checkpoint''. - E.g. in Spanish ``Punto de comprobaci@'on de lectura'', - *not* ``Leyendo un punto de comprobaci@'on'' */ - WARN ((0, 0, _("Read checkpoint %u"), checkpoint)); - break; - } - } -} - /* Perform a write to flush the buffer. */ ssize_t _flush_write (void) { ssize_t status; - do_checkpoint (true); + checkpoint_run (true); if (tape_length_option && tape_length_option <= bytes_written) { errno = ENOSPC; @@ -631,7 +637,7 @@ _flush_write (void) status = record_size; else status = sys_write_archive_buffer (); - + return status; } @@ -853,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); @@ -1041,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) @@ -1132,22 +1138,22 @@ try_new_volume () { size_t status; union block *header; - int access; + enum access_mode acc; switch (subcommand_option) { case APPEND_SUBCOMMAND: case CAT_SUBCOMMAND: case UPDATE_SUBCOMMAND: - access = ACCESS_UPDATE; + acc = ACCESS_UPDATE; break; default: - access = ACCESS_READ; + acc = ACCESS_READ; break; } - if (!new_volume (access)) + if (!new_volume (acc)) return true; while ((status = rmtread (archive, record_start->buffer, record_size)) @@ -1244,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; } } @@ -1460,7 +1474,7 @@ simple_flush_read (void) { size_t status; /* result from system call */ - do_checkpoint (false); + checkpoint_run (false); /* Clear the count of errors. This only applies to a single call to flush_read. */ @@ -1519,7 +1533,7 @@ _gnu_flush_read (void) { size_t status; /* result from system call */ - do_checkpoint (false); + checkpoint_run (false); /* Clear the count of errors. This only applies to a single call to flush_read. */ @@ -1585,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; } @@ -1601,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; @@ -1617,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 (); @@ -1632,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) @@ -1646,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 (); }