X-Git-Url: https://git.brokenzipper.com/gitweb?a=blobdiff_plain;f=src%2Fbuffer.c;h=dd9768244066de22f4c8408ffe70b0c2687eccba;hb=2947023d277cb0a787c73721d6190a75444cd65f;hp=c544ee00d85b5b9a862035dadbce8636f57f52c5;hpb=1d79c6734cfbd302e53358760b4c3fe3e7b9be61;p=chaz%2Ftar diff --git a/src/buffer.c b/src/buffer.c index c544ee0..dd97682 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, 2008 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-25. @@ -204,7 +204,8 @@ enum compress_type { ct_gzip, ct_bzip2, ct_lzma, - ct_lzop + ct_lzop, + ct_xz }; struct zip_magic @@ -222,8 +223,9 @@ static struct zip_magic const magic[] = { { 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_lzma, 6, "\xFFLZMA", "lzma", "--lzma" }, /* FIXME: ???? */ { ct_lzop, 4, "\211LZO", "lzop", "--lzop" }, + { ct_xz, 6, "\0xFD7zXZ", "-J" }, }; #define NMAGIC (sizeof(magic)/sizeof(magic[0])) @@ -263,6 +265,37 @@ check_compressed_archive (bool *pshort) return ct_none; } +/* Guess if the archive is seekable. */ +static void +guess_seekable_archive () +{ + struct stat st; + + if (subcommand_option == DELETE_SUBCOMMAND) + { + /* The current code in delete.c is based on the assumption that + skip_member() reads all data from the archive. So, we should + make sure it won't use seeks. On the other hand, the same code + depends on the ability to backspace a record in the archive, + so setting seekable_archive to false is technically incorrect. + However, it is tested only in skip_member(), so it's not a + problem. */ + seekable_archive = false; + } + + if (seek_option != -1) + { + seekable_archive = !!seek_option; + return; + } + + if (!multi_volume_option && !use_compress_program_option + && fstat (archive, &st) == 0) + seekable_archive = S_ISREG (st.st_mode); + else + seekable_archive = false; +} + /* Open an archive named archive_name_array[0]. Detect if it is a compressed archive of known type and use corresponding decompression program if so */ @@ -293,7 +326,7 @@ open_compressed_archive () 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; + return archive; break; default: @@ -304,7 +337,7 @@ open_compressed_archive () /* FD is not needed any more */ rmtclose (archive); - + hit_eof = false; /* It might have been set by find_next_block in check_compressed_archive */ @@ -563,6 +596,7 @@ _open_archive (enum access_mode wanted_access) { case ACCESS_READ: archive = open_compressed_archive (); + guess_seekable_archive (); break; case ACCESS_WRITE: @@ -677,6 +711,19 @@ archive_read_error (void) return; } +static bool +archive_is_dev () +{ + struct stat st; + + if (fstat (archive, &st)) + { + stat_diag (*archive_name_cursor); + return false; + } + return S_ISBLK (st.st_mode) || S_ISCHR (st.st_mode); +} + static void short_read (size_t status) { @@ -686,6 +733,19 @@ short_read (size_t status) more = record_start->buffer + status; left = record_size - status; + if (left && left % BLOCKSIZE == 0 + && verbose_option + && record_start_block == 0 && status != 0 + && archive_is_dev ()) + { + unsigned long rsize = status / BLOCKSIZE; + WARN ((0, 0, + ngettext ("Record size = %lu block", + "Record size = %lu blocks", + rsize), + rsize)); + } + while (left % BLOCKSIZE != 0 || (left && status && read_full_records)) { @@ -707,26 +767,10 @@ short_read (size_t status) rest)); } - /* User warned us about this. Fix up. */ - left -= status; more += status; } - /* FIXME: for size=0, multi-volume support. On the first record, warn - about the problem. */ - - if (!read_full_records && verbose_option > 1 - && record_start_block == 0 && status != 0) - { - unsigned long rsize = (record_size - left) / BLOCKSIZE; - WARN ((0, 0, - ngettext ("Record size = %lu block", - "Record size = %lu blocks", - rsize), - rsize)); - } - record_end = record_start + (record_size - left) / BLOCKSIZE; records_read++; } @@ -852,8 +896,6 @@ close_archive (void) flush_archive (); } - sys_drain_input_pipe (); - compute_duration (); if (verify_option) verify_volume (); @@ -861,7 +903,7 @@ close_archive (void) if (rmtclose (archive) != 0) close_error (*archive_name_cursor); - sys_wait_for_child (child_pid); + sys_wait_for_child (child_pid, hit_eof); tar_stat_destroy (¤t_stat_info); if (save_name) @@ -1088,6 +1130,7 @@ new_volume (enum access_mode mode) case ACCESS_READ: archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW, rsh_command_option); + guess_seekable_archive (); break; case ACCESS_WRITE: @@ -1324,7 +1367,7 @@ _write_volume_label (const char *str) memset (label, 0, BLOCKSIZE); - strcpy (label->header.name, volume_label_option); + strcpy (label->header.name, str); assign_string (¤t_stat_info.file_name, label->header.name); current_stat_info.had_trailing_slash = @@ -1571,6 +1614,9 @@ _gnu_flush_read (void) { while (!try_new_volume ()) ; + if (current_block == record_end) + /* Necessary for blocking_factor == 1 */ + flush_archive(); return; } else if (status == SAFE_READ_ERROR)