Package home | Report new bug | New search | Development Roadmap Status: Open | Feedback | All | Closed Since Version 1.4.7

Bug #5452 fix for "lone zero block" when untarring packages
Submitted: 2005-09-19 12:54 UTC
From: akorthaus at web dot de Assigned: cellog
Status: Closed Package: Archive_Tar
PHP Version: Irrelevant OS: Linux 2.4.31 (Gentoo)
Roadmaps: (Not assigned)    
Subscription  


 [2005-09-19 12:54 UTC] akorthaus at web dot de
Description: ------------ When extracting tar files created with PEAR::Archive_Tar, tar shows a warning like 'tar: A lone zero block at *'. The reason for the message is that newer GNU Tar implementations expects TWO empty records marking the end of the archive but Archive_Tar is writing only ONE. That is confusing for many users. From tar format definition: "Physically, an archive consists of a series of file entries terminated by an end-of-archive entry, which consists of two 512 blocks of zero bytes" see: http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html#SEC134 I found the solution (from Ant) here: http://issues.apache.org/bugzilla/show_bug.cgi?id=28776 There you can find some interesting links. The same issue was described in http://pear.php.net/bugs/bug.php?id=3694 - but without a solution. The solution is quite simple: $ cvs diff -u -p cvs diff: Diffing . Index: Tar.php =================================================================== RCS file: /repository/pear-core/Archive/Tar.php,v retrieving revision 1.20 diff -u -p -r1.20 Tar.php --- Tar.php 8 Jan 2004 17:33:09 -0000 1.20 +++ Tar.php 19 Sep 2005 12:40:15 -0000 @@ -719,6 +719,7 @@ class Archive_Tar extends PEAR // ----- Write the last 0 filled block for end of archive $v_binary_data = pack("a512", ''); $this->_writeBlock($v_binary_data); + $this->_writeBlock($v_binary_data); } return true; } cvs diff: Diffing docs If you change this, I think the warning will go away for newly created archives, and it should not be a problem with BC, as a zero block is used to finish an old archive.

Comments

 [2005-11-08 17:56 UTC] akorthaus at web dot de
I have posted this on php.pear.dev: http://news.php.net/php.pear.dev/39890 The patch you see here, is against an old version of Archive_Tar, here a patch against CVS Head: Index: Tar.php =================================================================== RCS file: /repository/pear/Archive_Tar/Archive/Tar.php,v retrieving revision 1.29 diff -u -r1.29 Tar.php --- Tar.php 17 Mar 2005 21:02:31 -0000 1.29 +++ Tar.php 8 Nov 2005 16:52:50 -0000 @@ -821,6 +821,7 @@ // ----- Write the last 0 filled block for end of archive $v_binary_data = pack("a512", ''); $this->_writeBlock($v_binary_data); + $this->_writeBlock($v_binary_data); } return true; } I also posted this patch to php.pear.dev: http://news.php.net/php.pear.dev/40401 Please note that the current Archive_Tar implementation is not compliant to POSIX.1 and newer GNU Tar implementations. That's the reason for the warnings people using archives created with Archive_Tar see (e.g. Gentoo users whenever installing a PEAR/PECL package).
 [2005-11-19 14:52 UTC] vblavet at php dot net
This bug has been fixed in CVS. If this was a documentation problem, the fix will appear on pear.php.net by the end of next Sunday (CET). If this was a problem with the pear.php.net website, the change should be live shortly. Otherwise, the fix will appear in the package's next release. Thank you for the report and for helping us make PEAR better.
 [2006-02-09 15:23 UTC] akorthaus at web dot de
Probably a better fix (patch against cvs head): --- Tar.php 20 Nov 2005 14:02:01 -0000 1.33 +++ Tar.php 9 Feb 2006 15:14:04 -0000 @@ -819,8 +819,7 @@ { if (is_resource($this->_file)) { // ----- Write the last 0 filled block for end of archive - $v_binary_data = pack("a512", ''); - $this->_writeBlock($v_binary_data); + $v_binary_data = pack("a1024", ''); $this->_writeBlock($v_binary_data); } return true; should be the same like File_Archive_Writer_Tar::close(): http://cvs.php.net/viewcvs.cgi/pear/File_Archive/Archive/Writer/Tar.php?view=markup&rev=1.19
 [2006-03-03 00:04 UTC] keith at squeegeemedia dot com (Keith Grennan)
This leads to an even worse bug in Archive_Tar. Now Archive_Tar appends the double 512-byte block, but when appending files to existing archives, it expects to find only one 512-byte end block. So when appending to an archive with two blocks, you end up with an end block in the middle of your archive (which totally corrupts it). I triggered this just by running 'pear package' on a package I was building. I think the best behavior is to handle 2, 1 or 0 end blocks gracefully ("A reasonable system should write a block of zeros at the end, but must not assume that such a block exists when reading an archive." - gnu tar manual) I have a patch that does this. It fixed my case, but I don't see any regression tests to make sure it doesn't break anthing else. If you have such a test suite feel free to point me to it. The patch looks right in theory, though :) This is a patch against HEAD (1.3.2). --- Tar.php-dist 2006-03-02 15:38:26.000000000 -0800 +++ Tar.php 2006-03-02 15:46:43.000000000 -0800 @@ -22,6 +22,7 @@ define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001); +define ('ARCHIVE_TAR_END_BLOCK', pack("a512", '')); /** * Creates a (compressed) Tar archive @@ -819,7 +820,7 @@ { if (is_resource($this->_file)) { // ----- Write the last 0 filled block for end of archive - $v_binary_data = pack("a512", ''); + $v_binary_data = ARCHIVE_TAR_END_BLOCK; $this->_writeBlock($v_binary_data); $this->_writeBlock($v_binary_data); } @@ -1598,32 +1599,23 @@ } if ($this->_compress_type == 'gz') { - $v_buffer = @gzread($v_temp_tar, 512); - - // ----- Read the following blocks but not the last one - if (!@gzeof($v_temp_tar)) { - do{ - $v_binary_data = pack("a512", $v_buffer); - $this->_writeBlock($v_binary_data); - $v_buffer = @gzread($v_temp_tar, 512); - - } while (!@gzeof($v_temp_tar)); + while (!@gzeof($v_temp_tar)) { + $v_buffer = @gzread($v_temp_tar, 512); + if ($v_buffer == ARCHIVE_TAR_END_BLOCK) + continue; + $v_binary_data = pack("a512", $v_buffer); + $this->_writeBlock($v_binary_data); } - @gzclose($v_temp_tar); } elseif ($this->_compress_type == 'bz2') { - $v_buffered_lines = array(); - $v_buffered_lines[] = @bzread($v_temp_tar, 512); - // ----- Read the following blocks but not the last one - while (strlen($v_buffered_lines[] - = @bzread($v_temp_tar, 512)) > 0) { - $v_binary_data = pack("a512", - array_shift($v_buffered_lines)); + while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) { + if ($v_buffer == ARCHIVE_TAR_END_BLOCK) + continue; + $v_binary_data = pack("a512", $v_buffer); $this->_writeBlock($v_binary_data); } - @bzclose($v_temp_tar); } @@ -1634,13 +1626,23 @@ } else { // ----- For not compressed tar, just add files before the last - // 512 bytes block + // one or two 512 bytes blocks if (!$this->_openReadWrite()) return false; clearstatcache(); $v_size = filesize($this->_tarname); - fseek($this->_file, $v_size-512); + + // We might have zero, one or two end blocks. + // The standard is two, but we should try to handle + // other cases. + fseek($this->_file, $v_size-1024); + if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { + fseek($this->_file, $v_size-1024); + } + elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { + fseek($this->_file, $v_size-512); + } } return true;
 [2006-12-22 19:20 UTC] cellog (Greg Beaver)
This bug has been fixed in CVS. If this was a documentation problem, the fix will appear on pear.php.net by the end of next Sunday (CET). If this was a problem with the pear.php.net website, the change should be live shortly. Otherwise, the fix will appear in the package's next release. Thank you for the report and for helping us make PEAR better.