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:
7
NEWS
7
NEWS
@@ -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
|
||||
|
||||
12
doc/tar.texi
12
doc/tar.texi
@@ -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
|
||||
|
||||
37
src/buffer.c
37
src/buffer.c
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
30
src/tar.c
30
src/tar.c
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user