Hi, I'm attaching patch for bug in tar for --posix && --sparse options.
Could you please consider applying?

Reproduce:
    1. Create sparse file of "shrunken" size (real data) >= 8^11 bytes.
    2. tar --posix --sparse -cf /dev/null ThatBigFile
    3. Tar fails with:
    tar: value [BIG_NUMBER] out of off_t range 0..8589934591
    tar: Exiting with failure status due to previous errors

Simple test:

    $ cat script
    #!/bin/bash

    COUNT=1 # 1000 * 2 * 10M ~> ~ 20GB

    if ! test -z "$2"; then
        COUNT=$2
    fi

    for i in `seq 0 $(( $COUNT - 1))`; do
        dd if=/dev/urandom of=$1 bs=4K count=$(( 256 * 10 )) \
            seek=$(( $i * 2 * 256 * 10 )) 2> /dev/null
        echo $i
    done

    $ ./script BIGFILE 1000

Sorry that I haven't written test.  I was unable to use genfile utility to
produce such files.  Is the 'dd' utility used as above ^^ ok for portability
reasons?

Pavel

>From ce21d1046792a3a918ef85037a28216350511a06 Mon Sep 17 00:00:00 2001
From: Pavel Raiskup <[email protected]>
Date: Fri, 25 Jan 2013 13:24:23 +0100
Subject: [PATCH] sparse: Fix bug in POSIX_FORMAT

Archive the file size correctly (and do not fail) when the shrunken size of
file is >= 8^11 (8589934592) bytes.  In that case use the 'size' posix
extended header instead of using the size into header field which has not
enough capacity.

* src/common.h: Generalize macros from create.c.
* src/create.c: Move macros to common.h.
* src/sparse.c: Use "size" field when shrunken size >= 8^11 bytes.
---
 src/common.h | 11 +++++++++++
 src/create.c | 11 -----------
 src/sparse.c | 11 ++++++++++-
 3 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/src/common.h b/src/common.h
index 4f7c19f..d8d7638 100644
--- a/src/common.h
+++ b/src/common.h
@@ -493,6 +493,17 @@ void exclusion_tag_warning (const char *dirname, const char *tagname,
 enum exclusion_tag_type check_exclusion_tags (struct tar_stat_info const *st,
 					      const char **tag_file_name);
 
+/* The maximum uintmax_t value that can be represented with DIGITS digits,
+   assuming that each digit is BITS_PER_DIGIT wide.  */
+#define MAX_VAL_WITH_DIGITS(digits, bits_per_digit) \
+   ((digits) * (bits_per_digit) < sizeof (uintmax_t) * CHAR_BIT \
+    ? ((uintmax_t) 1 << ((digits) * (bits_per_digit))) - 1 \
+    : (uintmax_t) -1)
+
+/* The maximum uintmax_t value that can be represented with octal
+   -   digits and a trailing NUL in BUFFER.  */
+#define MAX_OCTAL_VAL(buffer) MAX_VAL_WITH_DIGITS (sizeof (buffer) - 1, LG_8)
+
 #define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where))
 #define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where))
 
diff --git a/src/create.c b/src/create.c
index e14e13d..ad9db70 100644
--- a/src/create.c
+++ b/src/create.c
@@ -121,17 +121,6 @@ cachedir_file_p (int fd)
 }
 
 
-/* The maximum uintmax_t value that can be represented with DIGITS digits,
-   assuming that each digit is BITS_PER_DIGIT wide.  */
-#define MAX_VAL_WITH_DIGITS(digits, bits_per_digit) \
-   ((digits) * (bits_per_digit) < sizeof (uintmax_t) * CHAR_BIT \
-    ? ((uintmax_t) 1 << ((digits) * (bits_per_digit))) - 1 \
-    : (uintmax_t) -1)
-
-/* The maximum uintmax_t value that can be represented with octal
-   digits and a trailing NUL in BUFFER.  */
-#define MAX_OCTAL_VAL(buffer) MAX_VAL_WITH_DIGITS (sizeof (buffer) - 1, LG_8)
-
 /* Convert VALUE to an octal representation suitable for tar headers.
    Output to buffer WHERE with size SIZE.
    The result is undefined if SIZE is 0 or if VALUE is too large to fit.  */
diff --git a/src/sparse.c b/src/sparse.c
index b93cdc2..1f3b0b5 100644
--- a/src/sparse.c
+++ b/src/sparse.c
@@ -987,6 +987,7 @@ pax_dump_header_1 (struct tar_sparse_file *file)
   size_t i;
   char nbuf[UINTMAX_STRSIZE_BOUND];
   off_t size = 0;
+  off_t shrunken_size = 0;
   struct sp_array *map = file->stat_info->sparse_map;
   char *save_file_name = file->stat_info->file_name;
 
@@ -1034,8 +1035,16 @@ pax_dump_header_1 (struct tar_sparse_file *file)
     file->stat_info->file_name[NAME_FIELD_SIZE] = 0;
 
   blk = start_header (file->stat_info);
+
   /* Store the effective (shrunken) file size */
-  OFF_TO_CHARS (file->stat_info->archive_file_size, blk->header.size);
+  shrunken_size = file->stat_info->archive_file_size;
+  if (MAX_OCTAL_VAL (blk->header.size) < shrunken_size)
+    {
+      xheader_store ("size", file->stat_info, NULL);
+      shrunken_size = 0;
+    }
+  OFF_TO_CHARS (shrunken_size, blk->header.size);
+
   finish_header (file->stat_info, blk, block_ordinal);
   free (file->stat_info->file_name);
   file->stat_info->file_name = save_file_name;
-- 
1.7.11.7

Reply via email to