]> granicus.if.org Git - postgresql/commitdiff
Fix pg_restore to accept POSIX-conformant tar files.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 28 Sep 2012 19:42:22 +0000 (15:42 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 28 Sep 2012 19:42:22 +0000 (15:42 -0400)
Back-patch portions of commit 05b555d12bc2ad0d581f48a12b45174db41dc10d.
We need to patch pg_restore to accept either version of the magic string,
in hopes of avoiding compatibility problems when 9.3 comes out.  I also
fixed pg_dump to write the correct 2-block EOF marker, since that won't
create a compatibility problem with pg_restore and it could help with some
versions of tar.

Brian Weaver and Tom Lane

src/bin/pg_dump/pg_backup_tar.c

index f5ab5f35bf3c4177019bf5da299a2bb52c9d087a..052021d05a5221b3650a98c59855cc7716aefb83 100644 (file)
@@ -872,8 +872,10 @@ _CloseArchive(ArchiveHandle *AH)
 
                tarClose(AH, th);
 
-               /* Add a block of NULLs since it's de-rigeur. */
-               for (i = 0; i < 512; i++)
+               /*
+                * EOF marker for tar files is two blocks of NULLs.
+                */
+               for (i = 0; i < 512 * 2; i++)
                {
                        if (fputc(0, ctx->tarFH) == EOF)
                                die_horribly(AH, modulename,
@@ -1024,11 +1026,16 @@ _tarChecksum(char *header)
        int                     i,
                                sum;
 
-       sum = 0;
+       /*
+        * Per POSIX, the checksum is the simple sum of all bytes in the header,
+        * treating the bytes as unsigned, and treating the checksum field (at
+        * offset 148) as though it contained 8 spaces.
+        */
+       sum = 8 * ' ';                          /* presumed value for checksum field */
        for (i = 0; i < 512; i++)
                if (i < 148 || i >= 156)
                        sum += 0xFF & header[i];
-       return sum + 256;                       /* Assume 8 blanks in checksum field */
+       return sum;
 }
 
 bool
@@ -1042,11 +1049,15 @@ isValidTarHeader(char *header)
        if (sum != chk)
                return false;
 
-       /* POSIX format */
-       if (strncmp(&header[257], "ustar00", 7) == 0)
+       /* POSIX tar format */
+       if (memcmp(&header[257], "ustar\0", 6) == 0 &&
+               memcmp(&header[263], "00", 2) == 0)
+               return true;
+       /* GNU tar format */
+       if (memcmp(&header[257], "ustar  \0", 8) == 0)
                return true;
-       /* older format */
-       if (strncmp(&header[257], "ustar  ", 7) == 0)
+       /* not-quite-POSIX format written by pre-9.3 pg_dump */
+       if (memcmp(&header[257], "ustar00\0", 8) == 0)
                return true;
 
        return false;