diff --git a/doc/tar.texi b/doc/tar.texi
index fe09c12..1cc8a8a 100644
--- a/doc/tar.texi
+++ b/doc/tar.texi
@@ -2606,6 +2606,13 @@ widely used version control systems.
 
 @xref{exclude}.
 
+@opsummary{export-headers}
+@item --export-headers
+@itemx -Q
+
+During extraction with @option{--to-stdout} (@option{-O}), the extracted files'
+headers will also be written.  @xref{Writing to Standard Output}.
+
 @opsummary{file}
 @item --file=@var{archive}
 @itemx -f @var{archive}
@@ -3398,6 +3405,8 @@ them with the equivalent long option.
 
 @item -P @tab @ref{--absolute-names}.
 
+@item -Q @tab @ref{--export-headers}.
+
 @item -R @tab @ref{--block-number}.
 
 @item -S @tab @ref{--sparse}.
@@ -5118,7 +5127,9 @@ conjunction with @option{--extract} (@option{--get}, @option{-x}).  This option
 extracting files to send them through a pipe, and do not need to
 preserve them in the file system.  If you extract multiple members,
 they appear on standard output concatenated, in the order they are
-found in the archive.
+found in the archive.  Alternatively, the @option{--export-headers}
+(@option{-Q}) modifier will preserve archive information so a subset of the
+archive can be piped to another program.
 
 @table @option
 @opindex to-stdout
@@ -5150,6 +5161,23 @@ tar -xOzf foo.tgz bigfile1 bigfile2 | process
 However, @option{--to-command} may be more convenient for use with
 multiple files. See the next section.
 
+@table @option
+@opindex export-headers
+@item --export-headers
+@itemx -Q
+Writes the headers of extracted files when using @option{--get} (@option{-x})
+with @option{--to-stdout} (@option{-O}) or @option{--to-command}.
+@end table
+
+This is meant to be used in conjunction with a list of files to be extracted.
+The extracted files are left in archive format, thereby creating a subset of the
+input archive.  This can be especially useful for extracting part of an archive
+across a network. For example:
+
+@smallexample
+tar -xOQf foo.tar file1 file2 | ssh user@@server tar -x
+@end smallexample
+
 @node Writing to an External Program
 @unnumberedsubsubsec Writing to an External Program
 
diff --git a/src/common.h b/src/common.h
index 9897b46..7b73b2f 100644
--- a/src/common.h
+++ b/src/common.h
@@ -264,6 +264,7 @@ GLOBAL bool starting_file_option;
 GLOBAL tarlong tape_length_option;
 
 GLOBAL bool to_stdout_option;
+GLOBAL bool export_headers_option;
 
 GLOBAL bool totals_option;
 
@@ -479,6 +480,8 @@ void verify_volume (void);
 void extr_init (void);
 void extract_archive (void);
 void extract_finish (void);
+void clear_long_header();
+void append_long_header(const void *buffer, size_t size);
 bool rename_directory (char *src, char *dst);
 
 /* Module delete.c.  */
diff --git a/src/create.c b/src/create.c
index a925160..c605fb4 100644
diff --git a/src/extract.c b/src/extract.c
index 63f3525..aeabed3 100644
--- a/src/extract.c
+++ b/src/extract.c
@@ -762,6 +762,70 @@ open_output_file (char *file_name, int typeflag, mode_t mode)
   return fd;
 }
 
+static void
+auto_null_pad(int fd, int size)
+{
+  int to_pad = size % BLOCKSIZE;
+  if (to_pad)
+    {
+      to_pad = BLOCKSIZE - to_pad;
+      char *zero_padding = calloc(1, to_pad);
+      write(fd, zero_padding, to_pad);
+      free(zero_padding);
+    }
+}
+
+static int
+open_output_pipe(const char *file_name)
+{
+  if (to_stdout_option)
+    return STDOUT_FILENO;
+  else if (to_command_option)
+    {
+      char *file_name2 = strdup(file_name);
+      int fd = sys_exec_command (file_name2, 'f', &current_stat_info);
+      free(file_name2);
+      if (fd < 0)
+        {
+          skip_member ();
+          return -1;
+        }
+      else return fd;
+    }
+}
+
+static struct
+{
+  void *buffer;
+  ssize_t size;
+} long_header;
+
+void clear_long_header()
+{
+  free(long_header.buffer);
+  long_header.buffer = NULL;
+  long_header.size = 0;
+}
+
+void append_long_header(const void *buffer, size_t size)
+{
+  if (!long_header.buffer)
+    long_header.buffer = malloc(size);
+  else
+    long_header.buffer = realloc(long_header.buffer, long_header.size + size);
+
+  memcpy(long_header.buffer + long_header.size, buffer, size);
+  long_header.size += size;
+}
+
+static void
+export_header(int fd)
+{
+  write(fd, long_header.buffer, long_header.size);
+  auto_null_pad(fd, long_header.size);
+  clear_long_header();
+}
+
 static int
 extract_file (char *file_name, int typeflag)
 {
@@ -777,18 +841,12 @@ extract_file (char *file_name, int typeflag)
     0 < same_owner_option ? mode & (S_IRWXG | S_IRWXO) : 0;
 
   /* FIXME: deal with protection issues.  */
-
-  if (to_stdout_option)
-    fd = STDOUT_FILENO;
-  else if (to_command_option)
-    {
-      fd = sys_exec_command (file_name, 'f', &current_stat_info);
-      if (fd < 0)
+  if (EXTRACT_OVER_PIPE)
 	{
-	  skip_member ();
+      fd = open_output_pipe(file_name);
+      if (to_command_option && fd == -1)
 	  return 0;
 	}
-    }
   else
     {
       int recover = RECOVER_NO;
@@ -809,6 +867,11 @@ extract_file (char *file_name, int typeflag)
     }
 
   mv_begin (&current_stat_info);
+
+  /*(normally taken care of in prepare_to_extract)*/
+  if (to_command_option && export_headers_option)
+    export_header(fd);
+
   if (current_stat_info.is_sparse)
     sparse_extract_file (fd, &current_stat_info, &size);
   else
@@ -846,6 +909,10 @@ extract_file (char *file_name, int typeflag)
 	  }
       }
 
+  /*pad output if headers were exported to retain archive format*/
+  if (export_headers_option)
+    auto_null_pad(fd, current_stat_info.archive_file_size);
+
   skip_file (size);
 
   mv_end ();
@@ -1100,15 +1167,13 @@ extract_failure (char *file_name, int typeflag)
 
 typedef int (*tar_extractor_t) (char *file_name, int typeflag);
 
-
-
 /* Prepare to extract a file. Find extractor function.
    Return zero if extraction should not proceed.  */
 
 static int
 prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
 {
-  int rc = 1;
+  int rc = 1, fd = -1;
 
   if (EXTRACT_OVER_PIPE)
     rc = 0;
@@ -1194,6 +1259,23 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
       *fun = extract_file;
     }
 
+  /*send the header to output if applicable*/
+  if (EXTRACT_OVER_PIPE && export_headers_option && *fun != &extract_failure)
+    {
+      if (!to_command_option || !rc)
+        fd = open_output_pipe(file_name);
+
+      if (fd != -1)
+        {
+          export_header(fd);
+          if (to_command_option)
+            {
+              if (close (fd) < 0)
+                close_error (file_name);
+            }
+        }
+    }
+
   /* Determine whether the extraction should proceed */
   if (rc == 0)
     return 0;
diff --git a/src/list.c b/src/list.c
index 98c1e39..16141b5 100644
--- a/src/list.c
+++ b/src/list.c
@@ -195,6 +195,8 @@ read_and (void (*do_something) (void))
     }
   while (!all_names_found (&current_stat_info));
 
+  clear_long_header();
+
   close_archive ();
   names_notfound ();		/* print names not found */
 }
@@ -304,6 +306,9 @@ read_header_primitive (bool raw_extended_headers, struct tar_stat_info *info)
   size_t next_long_name_blocks = 0;
   size_t next_long_link_blocks = 0;
 
+  if (export_headers_option)
+    clear_long_header();
+
   while (1)
     {
       enum read_header status;
@@ -313,8 +318,15 @@ read_header_primitive (bool raw_extended_headers, struct tar_stat_info *info)
       if (!header)
 	return HEADER_END_OF_FILE;
 
+      if (export_headers_option)
+        append_long_header(header, BLOCKSIZE);
+
       if ((status = tar_checksum (header, false)) != HEADER_SUCCESS)
+        {
+          if (export_headers_option)
+            clear_long_header();
 	return status;
+        }
 
       /* Good block.  Decode file size and return.  */
 
@@ -376,6 +388,9 @@ read_header_primitive (bool raw_extended_headers, struct tar_stat_info *info)
 		  if (written > size)
 		    written = size;
 
+		  if (export_headers_option)
+		    append_long_header(data_block, written);
+
 		  memcpy (bp, data_block->buffer, written);
 		  bp += written;
 		  set_next_block_after ((union block *)
diff --git a/src/tar.c b/src/tar.c
index 31537eb..a368ab4 100644
--- a/src/tar.c
+++ b/src/tar.c
@@ -454,6 +454,8 @@ static struct argp_option options[] = {
 
   {"to-stdout", 'O', 0, 0,
    N_("extract files to standard output"), GRID+1 },
+  {"export-headers", 'Q', 0, 0,
+   N_("also extract tar headers when piping"), GRID+1 },
   {"to-command", TO_COMMAND_OPTION, N_("COMMAND"), 0,
    N_("pipe extracted files to another program"), GRID+1 },
   {"ignore-command-error", IGNORE_COMMAND_ERROR_OPTION, 0, 0,
@@ -1453,6 +1455,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
       to_stdout_option = true;
       break;
 
+    case 'Q':
+      export_headers_option = true;
+      break;
+
     case 'p':
       same_permissions_option = true;
       break;
@@ -2335,6 +2341,14 @@ decode_options (int argc, char **argv)
   if (recursive_unlink_option)
     old_files_option = UNLINK_FIRST_OLD_FILES;
 
+  if (export_headers_option)
+    {
+      if (subcommand_option != EXTRACT_SUBCOMMAND)
+	USAGE_ERROR ((0, 0, _("Can only export headers with extraction")));
+      if (!EXTRACT_OVER_PIPE)
+	USAGE_ERROR ((0, 0, _("Cannot export headers to file system")));
+    }
+
 
   if (test_label_option)
     {
