Automatic detection of seekable archives.

* src/buffer.c (guess_seekable_archive): New function.
(_open_archive): Call guess_seekable_archive for archives
open for reading.
(new_volume): Likewise.
* src/common.h (seek_option): New global.
* src/tar.c (options): New option --no-seek.
(parse_opt): --seek and --no-seek set seek_option,
not seekable_archive.
(decode_options): Initialize seek_option to -1.

* NEWS: Update.
* doc/tar.texi: Update.
This commit is contained in:
Sergey Poznyakoff
2009-09-08 10:27:57 +03:00
parent ba954ea1e1
commit cef4d5e838
5 changed files with 69 additions and 18 deletions
+35 -2
View File
@@ -265,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 */
@@ -295,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:
@@ -306,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 */
@@ -565,6 +596,7 @@ _open_archive (enum access_mode wanted_access)
{
case ACCESS_READ:
archive = open_compressed_archive ();
guess_seekable_archive ();
break;
case ACCESS_WRITE:
@@ -1098,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:
+1
View File
@@ -354,6 +354,7 @@ struct name
GLOBAL dev_t ar_dev;
GLOBAL ino_t ar_ino;
GLOBAL int seek_option;
GLOBAL bool seekable_archive;
GLOBAL dev_t root_device;
+16 -14
View File
@@ -291,6 +291,7 @@ enum
NO_RECURSION_OPTION,
NO_SAME_OWNER_OPTION,
NO_SAME_PERMISSIONS_OPTION,
NO_SEEK_OPTION,
NO_UNQUOTE_OPTION,
NO_WILDCARDS_MATCH_SLASH_OPTION,
NO_WILDCARDS_OPTION,
@@ -366,7 +367,12 @@ The version control may be set with --backup or VERSION_CONTROL, values are:\n\n
[q alias for --occurrence=1 =/= this would better be used for quiet?]
y per-file gzip compression
Y per-block gzip compression */
Y per-block gzip compression.
Additionally, the 'n' letter is assigned for option --seek, which
is probably not needed and should be marked as deprecated, so that
-n may become available in the future.
*/
static struct argp_option options[] = {
#define GRID 10
@@ -420,6 +426,8 @@ static struct argp_option options[] = {
" NUMBER defaults to 1"), GRID+1 },
{"seek", 'n', NULL, 0,
N_("archive is seekable"), GRID+1 },
{"no-seek", NO_SEEK_OPTION, NULL, 0,
N_("archive is not seekable"), GRID+1 },
{"no-check-device", NO_CHECK_DEVICE_OPTION, NULL, 0,
N_("do not check device numbers when creating incremental archives"),
GRID+1 },
@@ -1457,9 +1465,13 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 'n':
seekable_archive = true;
seek_option = 1;
break;
case NO_SEEK_OPTION:
seek_option = 0;
break;
case 'N':
after_date_option = true;
/* Fall through. */
@@ -2147,6 +2159,8 @@ decode_options (int argc, char **argv)
check_device_option = true;
incremental_level = -1;
seek_option = -1;
/* Convert old-style tar call by exploding option element and rearranging
options accordingly. */
@@ -2279,18 +2293,6 @@ decode_options (int argc, char **argv)
_("--occurrence cannot be used in the requested operation mode")));
}
if (seekable_archive && 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 (archive_names == 0)
{
/* If no archive file name given, try TAPE from the environment, or