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

7
NEWS
View File

@@ -1,4 +1,4 @@
GNU tar NEWS - User visible changes. 2009-08-08
GNU tar NEWS - User visible changes. 2009-09-08
Please send GNU tar bug reports to <bug-tar@gnu.org>
@@ -10,6 +10,11 @@ When listing or extracting archives, the actual record size is
reported only if the archive is read from a device (as opposed
to regular files and pipes).
* Seekable archives
When a read-only operation (e.g. --list or --extract) is requested
on a regular file, tar attemtps to speed up accesses by using lseek.
* New command line option `--warning'
The `--warning' command line option allows to suppress or enable

View File

@@ -2950,6 +2950,14 @@ When extracting an archive, subtract the user's umask from files from
the permissions specified in the archive. This is the default behavior
for ordinary users.
@opsummary{no-seek}
@item --no-seek
The archive media does not support seeks to arbitrary
locations. Usually @command{tar} determines automatically whether
the archive can be seeked or not. Use this option to disable this
mechanism.
@opsummary{no-unquote}
@item --no-unquote
Treat all input file or member names literally, do not interpret
@@ -3180,7 +3188,9 @@ effect only for ordinary users. @xref{Attributes}.
Assume that the archive media supports seeks to arbitrary
locations. Usually @command{tar} determines automatically whether
the archive can be seeked or not. This option is intended for use
in cases when such recognition fails.
in cases when such recognition fails. It takes effect only if the
archive is open for reading (e.g. with @option{--list} or
@option{--extract} options).
@opsummary{show-defaults}
@item --show-defaults

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:

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;

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