X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fbuffer.c;h=be0b3784e02897f3c1cd4b8173a5349f584f144f;hb=c9a7297a8a135c0afd8f984b91578a822ba3b04c;hp=783dd6ef6afd6e6eb9277e634c97049f27a8d810;hpb=c027e039249b82c86eb947cae09a28b50dde30de;p=chaz%2Ftar diff --git a/src/buffer.c b/src/buffer.c index 783dd6e..be0b378 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -1,13 +1,13 @@ /* Buffer management for tar. Copyright (C) 1988, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, - 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-25. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any later + Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but @@ -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. @@ -121,6 +117,15 @@ static off_t save_totsize; /* total size of file we are writing, only static off_t save_sizeleft; /* where we are in the file we are writing, only valid if save_name is nonzero */ + +static struct tar_stat_info dummy; + +void +buffer_write_global_xheader () +{ + xheader_write_global (&dummy.xhdr); +} + void mv_begin (struct tar_stat_info *st) { @@ -193,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 @@ -209,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])) @@ -222,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; @@ -261,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); @@ -273,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; } @@ -436,16 +471,6 @@ _open_archive (enum access_mode wanted_access) { int backed_up_flag = 0; - if (index_file_name) - { - stdlis = freopen (index_file_name, "w", stdout); - if (! stdlis) - open_error (index_file_name); - close_stdout_set_file_name (index_file_name); - } - else - stdlis = to_stdout_option ? stderr : stdout; - if (record_size == 0) FATAL_ERROR ((0, 0, _("Invalid value for record_size"))); @@ -485,7 +510,8 @@ _open_archive (enum access_mode wanted_access) break; } - if (wanted_access == ACCESS_WRITE + if (!index_file_name + && wanted_access == ACCESS_WRITE && strcmp (archive_name_array[0], "-") == 0) stdlis = stderr; } @@ -499,28 +525,33 @@ _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; case ACCESS_WRITE: archive = STDOUT_FILENO; - stdlis = stderr; + if (!index_file_name) + stdlis = stderr; break; case ACCESS_UPDATE: archive = STDIN_FILENO; - stdlis = stderr; write_archive_to_stdout = true; record_end = record_start; /* set up for 1st record = # 0 */ + if (!index_file_name) + stdlis = stderr; break; } } @@ -549,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; } @@ -583,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; @@ -629,7 +637,7 @@ _flush_write (void) status = record_size; else status = sys_write_archive_buffer (); - + return status; } @@ -851,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); @@ -1036,9 +1044,10 @@ new_volume (enum access_mode mode) assign_string (&volume_label, NULL); assign_string (&continued_file_name, NULL); continued_file_size = continued_file_offset = 0; - + 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) @@ -1129,23 +1138,24 @@ try_new_volume () { size_t status; union block *header; - struct tar_stat_info dummy; - + enum access_mode acc; + switch (subcommand_option) { case APPEND_SUBCOMMAND: case CAT_SUBCOMMAND: case UPDATE_SUBCOMMAND: - if (!new_volume (ACCESS_UPDATE)) - return true; + acc = ACCESS_UPDATE; break; default: - if (!new_volume (ACCESS_READ)) - return true; + acc = ACCESS_READ; break; } + if (!new_volume (acc)) + return true; + while ((status = rmtread (archive, record_start->buffer, record_size)) == SAFE_READ_ERROR) archive_read_error (); @@ -1240,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; } } @@ -1299,7 +1317,7 @@ static void _write_volume_label (const char *str) { if (archive_format == POSIX_FORMAT) - xheader_store ("GNU.volume.label", NULL, str); + xheader_store ("GNU.volume.label", &dummy, str); else { union block *label = find_next_block (); @@ -1416,9 +1434,9 @@ add_multi_volume_header (void) if (archive_format == POSIX_FORMAT) { off_t d = real_s_totsize - real_s_sizeleft; - xheader_store ("GNU.volume.filename", NULL, real_s_name); - xheader_store ("GNU.volume.size", NULL, &real_s_sizeleft); - xheader_store ("GNU.volume.offset", NULL, &d); + xheader_store ("GNU.volume.filename", &dummy, real_s_name); + xheader_store ("GNU.volume.size", &dummy, &real_s_sizeleft); + xheader_store ("GNU.volume.offset", &dummy, &d); } else gnu_add_multi_volume_header (); @@ -1456,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. */ @@ -1515,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. */ @@ -1597,15 +1615,22 @@ _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; - xheader_destroy (&extended_header); + tar_stat_destroy (&dummy); increase_volume_number (); prev_written += bytes_written; @@ -1613,6 +1638,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 (); @@ -1623,7 +1649,9 @@ _gnu_flush_write (size_t buffer_level) if (real_s_name) add_multi_volume_header (); - write_extended (true, NULL, find_next_block ()); + write_extended (true, &dummy, find_next_block ()); + tar_stat_destroy (&dummy); + if (real_s_name) add_chunk_header (); header = find_next_block ();