Просмотр исходного кода

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.
Sergey Poznyakoff 15 лет назад
Родитель
Сommit
cef4d5e838
5 измененных файлов с 69 добавлено и 18 удалено
  1. 6 1
      NEWS
  2. 11 1
      doc/tar.texi
  3. 35 2
      src/buffer.c
  4. 1 0
      src/common.h
  5. 16 14
      src/tar.c

+ 6 - 1
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>
 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
 reported only if the archive is read from a device (as opposed
 to regular files and pipes).
 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'
 * New command line option `--warning'
 
 
 The `--warning' command line option allows to suppress or enable
 The `--warning' command line option allows to suppress or enable

+ 11 - 1
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
 the permissions specified in the archive.  This is the default behavior
 for ordinary users.
 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}
 @opsummary{no-unquote}
 @item --no-unquote
 @item --no-unquote
 Treat all input file or member names literally, do not interpret
 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
 Assume that the archive media supports seeks to arbitrary
 locations.  Usually @command{tar} determines automatically whether
 locations.  Usually @command{tar} determines automatically whether
 the archive can be seeked or not.  This option is intended for use
 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}
 @opsummary{show-defaults}
 @item --show-defaults
 @item --show-defaults

+ 35 - 2
src/buffer.c

@@ -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
 /* Open an archive named archive_name_array[0]. Detect if it is
    a compressed archive of known type and use corresponding decompression
    a compressed archive of known type and use corresponding decompression
    program if so */
    program if so */
@@ -295,7 +326,7 @@ open_compressed_archive ()
                 ERROR ((0, 0, _("This does not look like a tar archive")));
                 ERROR ((0, 0, _("This does not look like a tar archive")));
               set_comression_program_by_suffix (archive_name_array[0], NULL);
               set_comression_program_by_suffix (archive_name_array[0], NULL);
               if (!use_compress_program_option)
               if (!use_compress_program_option)
-                return archive;
+		return archive;
               break;
               break;
 
 
             default:
             default:
@@ -306,7 +337,7 @@ open_compressed_archive ()
       
       
       /* FD is not needed any more */
       /* FD is not needed any more */
       rmtclose (archive);
       rmtclose (archive);
-
+      
       hit_eof = false; /* It might have been set by find_next_block in
       hit_eof = false; /* It might have been set by find_next_block in
                           check_compressed_archive */
                           check_compressed_archive */
 
 
@@ -565,6 +596,7 @@ _open_archive (enum access_mode wanted_access)
       {
       {
       case ACCESS_READ:
       case ACCESS_READ:
         archive = open_compressed_archive ();
         archive = open_compressed_archive ();
+	guess_seekable_archive ();
         break;
         break;
 
 
       case ACCESS_WRITE:
       case ACCESS_WRITE:
@@ -1098,6 +1130,7 @@ new_volume (enum access_mode mode)
       case ACCESS_READ:
       case ACCESS_READ:
         archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
         archive = rmtopen (*archive_name_cursor, O_RDONLY, MODE_RW,
                            rsh_command_option);
                            rsh_command_option);
+	guess_seekable_archive ();
         break;
         break;
 
 
       case ACCESS_WRITE:
       case ACCESS_WRITE:

+ 1 - 0
src/common.h

@@ -354,6 +354,7 @@ struct name
 GLOBAL dev_t ar_dev;
 GLOBAL dev_t ar_dev;
 GLOBAL ino_t ar_ino;
 GLOBAL ino_t ar_ino;
 
 
+GLOBAL int seek_option;
 GLOBAL bool seekable_archive;
 GLOBAL bool seekable_archive;
 
 
 GLOBAL dev_t root_device;
 GLOBAL dev_t root_device;

+ 16 - 14
src/tar.c

@@ -291,6 +291,7 @@ enum
   NO_RECURSION_OPTION,
   NO_RECURSION_OPTION,
   NO_SAME_OWNER_OPTION,
   NO_SAME_OWNER_OPTION,
   NO_SAME_PERMISSIONS_OPTION,
   NO_SAME_PERMISSIONS_OPTION,
+  NO_SEEK_OPTION,
   NO_UNQUOTE_OPTION,
   NO_UNQUOTE_OPTION,
   NO_WILDCARDS_MATCH_SLASH_OPTION,
   NO_WILDCARDS_MATCH_SLASH_OPTION,
   NO_WILDCARDS_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?]
    [q  alias for --occurrence=1 =/= this would better be used for quiet?]
 
 
    y  per-file gzip compression
    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[] = {
 static struct argp_option options[] = {
 #define GRID 10
 #define GRID 10
@@ -420,6 +426,8 @@ static struct argp_option options[] = {
       " NUMBER defaults to 1"), GRID+1 },
       " NUMBER defaults to 1"), GRID+1 },
   {"seek", 'n', NULL, 0,
   {"seek", 'n', NULL, 0,
    N_("archive is seekable"), GRID+1 },
    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,
   {"no-check-device", NO_CHECK_DEVICE_OPTION, NULL, 0,
    N_("do not check device numbers when creating incremental archives"),
    N_("do not check device numbers when creating incremental archives"),
    GRID+1 },
    GRID+1 },
@@ -1457,9 +1465,13 @@ parse_opt (int key, char *arg, struct argp_state *state)
       break;
       break;
 
 
     case 'n':
     case 'n':
-      seekable_archive = true;
+      seek_option = 1;
       break;
       break;
 
 
+    case NO_SEEK_OPTION:
+      seek_option = 0;
+      break;
+      
     case 'N':
     case 'N':
       after_date_option = true;
       after_date_option = true;
       /* Fall through.  */
       /* Fall through.  */
@@ -2147,6 +2159,8 @@ decode_options (int argc, char **argv)
   check_device_option = true;
   check_device_option = true;
 
 
   incremental_level = -1;
   incremental_level = -1;
+
+  seek_option = -1;
   
   
   /* Convert old-style tar call by exploding option element and rearranging
   /* Convert old-style tar call by exploding option element and rearranging
      options accordingly.  */
      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 (archive_names == 0)
     {
     {
       /* If no archive file name given, try TAPE from the environment, or
       /* If no archive file name given, try TAPE from the environment, or