]> Dogcows Code - chaz/tar/commitdiff
Automatic detection of seekable archives.
authorSergey Poznyakoff <gray@gnu.org.ua>
Tue, 8 Sep 2009 07:27:57 +0000 (10:27 +0300)
committerSergey Poznyakoff <gray@gnu.org.ua>
Tue, 8 Sep 2009 07:27:57 +0000 (10:27 +0300)
* 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.

NEWS
doc/tar.texi
src/buffer.c
src/common.h
src/tar.c

diff --git a/NEWS b/NEWS
index 5e796b2ba4625c54a41f295a2bf6e2bd2c2702ea..bf02a24b7e0614682d86b7a3c7a3dae224df2cba 100644 (file)
--- a/NEWS
+++ b/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>
 
 \f
@@ -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
index 7154dfd06bc68b878e82d576582b5ce4c38e7be4..e6093685bfc04e83d082e8c259b5c6a71333df4f 100644 (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
index a01af374c3b4a00d77992d057e739f4274757c75..dd9768244066de22f4c8408ffe70b0c2687eccba 100644 (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:
index f2cdf2b3d334784119a441b511e0e50fae2e0433..196c1188c713100a0c4c6985e2e549e13e4c4c74 100644 (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;
index 3aa52871ba084848d9bb99d1d932e77c00ef652d..583edc90ea6f549e883186d097f10c496a97bd8e 100644 (file)
--- a/src/tar.c
+++ b/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
This page took 0.041739 seconds and 4 git commands to generate.