]> 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
 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).
 
 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
 * 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.
 
 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
 @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
 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
 
 @opsummary{show-defaults}
 @item --show-defaults
index a01af374c3b4a00d77992d057e739f4274757c75..dd9768244066de22f4c8408ffe70b0c2687eccba 100644 (file)
@@ -265,6 +265,37 @@ check_compressed_archive (bool *pshort)
   return ct_none;
 }
 
   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 */
 /* 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)
                 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:
               break;
 
             default:
@@ -306,7 +337,7 @@ open_compressed_archive ()
       
       /* FD is not needed any more */
       rmtclose (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 */
 
       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 ();
       {
       case ACCESS_READ:
         archive = open_compressed_archive ();
+       guess_seekable_archive ();
         break;
 
       case ACCESS_WRITE:
         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);
       case ACCESS_READ:
         archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
                            rsh_command_option);
+       guess_seekable_archive ();
         break;
 
       case ACCESS_WRITE:
         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 dev_t ar_dev;
 GLOBAL ino_t ar_ino;
 
+GLOBAL int seek_option;
 GLOBAL bool seekable_archive;
 
 GLOBAL dev_t root_device;
 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_RECURSION_OPTION,
   NO_SAME_OWNER_OPTION,
   NO_SAME_PERMISSIONS_OPTION,
+  NO_SEEK_OPTION,
   NO_UNQUOTE_OPTION,
   NO_WILDCARDS_MATCH_SLASH_OPTION,
   NO_WILDCARDS_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
    [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
 
 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 },
       " 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 },
   {"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':
       break;
 
     case 'n':
-      seekable_archive = true;
+      seek_option = 1;
       break;
 
       break;
 
+    case NO_SEEK_OPTION:
+      seek_option = 0;
+      break;
+      
     case 'N':
       after_date_option = true;
       /* Fall through.  */
     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;
   check_device_option = true;
 
   incremental_level = -1;
+
+  seek_option = -1;
   
   /* Convert old-style tar call by exploding option element and rearranging
      options accordingly.  */
   
   /* 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")));
     }
 
                          _("--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
   if (archive_names == 0)
     {
       /* If no archive file name given, try TAPE from the environment, or
This page took 0.047413 seconds and 4 git commands to generate.