* 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.
-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>
\f
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
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
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
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 */
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:
/* FD is not needed any more */
rmtclose (archive);
-
+
hit_eof = false; /* It might have been set by find_next_block in
check_compressed_archive */
{
case ACCESS_READ:
archive = open_compressed_archive ();
+ guess_seekable_archive ();
break;
case ACCESS_WRITE:
case ACCESS_READ:
archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
rsh_command_option);
+ guess_seekable_archive ();
break;
case ACCESS_WRITE:
GLOBAL dev_t ar_dev;
GLOBAL ino_t ar_ino;
+GLOBAL int seek_option;
GLOBAL bool seekable_archive;
GLOBAL dev_t root_device;
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,
[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
" 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 },
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. */
check_device_option = true;
incremental_level = -1;
+
+ seek_option = -1;
/* Convert old-style tar call by exploding option element and rearranging
options accordingly. */
_("--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