]> granicus.if.org Git - php/commitdiff
- Sync with pear/Archive_Tar/Archive/Tar.php CVS 1.11
authorVincent Blavet <vblavet@php.net>
Wed, 28 May 2003 06:01:04 +0000 (06:01 +0000)
committerVincent Blavet <vblavet@php.net>
Wed, 28 May 2003 06:01:04 +0000 (06:01 +0000)
- Support for bz2 compression
- Add new methods AddString() and extractInString()

pear/Archive/Tar.php

index ff20b7eb5680f41b9032890b31eb3e0977766667..9f695375b90483e11b7de27c6c510858046e7720 100644 (file)
@@ -39,6 +39,11 @@ class Archive_Tar extends PEAR
     */
     var $_compress=false;
 
+    /**
+    * @var string Type of compression : 'none', 'gz' or 'bz2'
+    */
+    var $_compress_type='none';
+
     /**
     * @var file descriptor
     */
@@ -64,41 +69,61 @@ class Archive_Tar extends PEAR
     function Archive_Tar($p_tarname, $p_compress = null)
     {
         $this->PEAR();
+        $this->_compress = false;
+        $this->_compress_type = 'none';
         if ($p_compress === null) {
             if (@file_exists($p_tarname)) {
-                if ($fp = @fopen($p_tarname, "r")) {
+                if ($fp = @fopen($p_tarname, "rb")) {
                     // look for gzip magic cookie
                     $data = fread($fp, 2);
+                    fclose($fp);
                     if ($data == "\37\213") {
-                        $p_compress = true;
+                        $this->_compress = true;
+                        $this->_compress_type = 'gz';
+                    // No sure it's enought for a magic code ....
+                    } elseif ($data == "BZ") {
+                        $this->_compress = true;
+                        $this->_compress_type = 'bz2';
                     }
                 }
             } else {
                 // probably a remote file or some file accessible
                 // through a stream interface
                 if (substr($p_tarname, -2) == 'gz') {
-                    $p_compress = true;
+                    $this->_compress = true;
+                    $this->_compress_type = 'gz';
+                } elseif ((substr($p_tarname, -3) == 'bz2') ||
+                          (substr($p_tarname, -2) == 'bz')) {
+                    $this->_compress = true;
+                    $this->_compress_type = 'bz2';
                 }
             }
+        } else {
+            if ($p_compress == 'gz') {
+                $this->_compress = true;
+                $this->_compress_type = 'gz';
+            } else if ($p_compress == 'bz2') {
+                $this->_compress = true;
+                $this->_compress_type = 'bz2';
+            }
         }
         $this->_tarname = $p_tarname;
-        if ($p_compress) { // assert zlib extension support
-            $extname = 'zlib';
+        if ($this->_compress) { // assert zlib or bz2 extension support
+            if ($this->_compress_type == 'gz')
+                $extname = 'zlib';
+            else if ($this->_compress_type == 'bz2')
+                $extname = 'bz2';
+
             if (!extension_loaded($extname)) {
-                if (OS_WINDOWS) {
-                    @dl("php_$extname.dll");
-                } else {
-                    @dl("$extname.so");
-                }
+                PEAR::loadExtension($extname);
             }
             if (!extension_loaded($extname)) {
                 die("The extension '$extname' couldn't be found.\n".
-                    "Please make sure your version of PHP was built".
+                    "Please make sure your version of PHP was built ".
                     "with '$extname' support.\n");
                 return false;
             }
         }
-        $this->_compress = (bool)$p_compress;
     }
     // }}}
 
@@ -311,6 +336,43 @@ class Archive_Tar extends PEAR
     }
     // }}}
 
+    // {{{ addString()
+    /**
+    * This method add a single string as a file at the
+    * end of the existing archive. If the archive does not yet exists it
+    * is created.
+    *
+    * @param string     $p_filename     A string which contains the full filename path
+    *                                   that will be associated with the string.
+    * @param string     $p_string       The content of the file added in the archive.
+    * @return                           true on success, false on error.
+    * @access public
+    */
+    function addString($p_filename, $p_string)
+    {
+        $v_result = true;
+
+        if (!@is_file($this->_tarname)) {
+            if (!$this->_openWrite()) {
+                return false;
+            }
+            $this->_close();
+        }
+        
+        if (!$this->_openAppend())
+            return false;
+
+        // Need to check the get back to the temporary file ? ....
+        $v_result = $this->_addString($p_filename, $p_string);
+
+        $this->_writeFooter();
+
+        $this->_close();
+
+        return $v_result;
+    }
+    // }}}
+
     // {{{ extractModify()
     /**
     * This method extract all the content of the archive in the directory
@@ -358,6 +420,27 @@ class Archive_Tar extends PEAR
     }
     // }}}
 
+    // {{{ extractInString()
+    /**
+    * This method extract from the archive one file identified by $p_filename.
+    * The return value is a string with the file content, or NULL on error.
+    * @param string $p_filename     The path of the file to extract in a string.
+    * @return                       a string with the file content or NULL.
+    * @access public
+    */
+    function extractInString($p_filename)
+    {
+        if ($this->_openRead()) {
+            $v_result = $this->_extractInString($p_filename);
+            $this->_close();
+        } else {
+            $v_result = NULL;
+        }
+
+        return $v_result;
+    }
+    // }}}
+
     // {{{ extractList()
     /**
     * This method extract from the archive only the files indicated in the
@@ -417,10 +500,14 @@ class Archive_Tar extends PEAR
     // {{{ _openWrite()
     function _openWrite()
     {
-        if ($this->_compress)
-            $this->_file = @gzopen($this->_tarname, "w");
+        if ($this->_compress_type == 'gz')
+            $this->_file = @gzopen($this->_tarname, "wb");
+        else if ($this->_compress_type == 'bz2')
+            $this->_file = @bzopen($this->_tarname, "wb");
+        else if ($this->_compress_type == 'none')
+            $this->_file = @fopen($this->_tarname, "wb");
         else
-            $this->_file = @fopen($this->_tarname, "w");
+            $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 
         if ($this->_file == 0) {
             $this->_error('Unable to open in write mode \''.$this->_tarname.'\'');
@@ -462,10 +549,14 @@ class Archive_Tar extends PEAR
           // ----- File to open if the normal Tar file
           $v_filename = $this->_tarname;
 
-        if ($this->_compress)
+        if ($this->_compress_type == 'gz')
             $this->_file = @gzopen($v_filename, "rb");
-        else
+        else if ($this->_compress_type == 'bz2')
+            $this->_file = @bzopen($v_filename, "rb");
+        else if ($this->_compress_type == 'none')
             $this->_file = @fopen($v_filename, "rb");
+        else
+            $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 
         if ($this->_file == 0) {
             $this->_error('Unable to open in read mode \''.$v_filename.'\'');
@@ -479,10 +570,14 @@ class Archive_Tar extends PEAR
     // {{{ _openReadWrite()
     function _openReadWrite()
     {
-        if ($this->_compress)
+        if ($this->_compress_type == 'gz')
             $this->_file = @gzopen($this->_tarname, "r+b");
-        else
+        else if ($this->_compress_type == 'bz2')
+            $this->_file = @bzopen($this->_tarname, "r+b");
+        else if ($this->_compress_type == 'none')
             $this->_file = @fopen($this->_tarname, "r+b");
+        else
+            $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 
         if ($this->_file == 0) {
             $this->_error('Unable to open in read/write mode \''.$this->_tarname.'\'');
@@ -497,10 +592,14 @@ class Archive_Tar extends PEAR
     function _close()
     {
         if (isset($this->_file)) {
-            if ($this->_compress)
+            if ($this->_compress_type == 'gz')
                 @gzclose($this->_file);
-            else
+            else if ($this->_compress_type == 'bz2')
+                @bzclose($this->_file);
+            else if ($this->_compress_type == 'none')
                 @fclose($this->_file);
+            else
+                $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
 
             $this->_file = 0;
         }
@@ -536,16 +635,87 @@ class Archive_Tar extends PEAR
     }
     // }}}
 
+    // {{{ _writeBlock()
+    function _writeBlock($p_binary_data, $p_len=null)
+    {
+      if ($this->_file) {
+          if ($p_len === null) {
+              if ($this->_compress_type == 'gz')
+                  @gzputs($this->_file, $p_binary_data);
+              else if ($this->_compress_type == 'bz2')
+                  @bzwrite($this->_file, $p_binary_data);
+              else if ($this->_compress_type == 'none')
+                  @fputs($this->_file, $p_binary_data);
+              else
+                  $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
+          } else {
+              if ($this->_compress_type == 'gz')
+                  @gzputs($this->_file, $p_binary_data, $p_len);
+              else if ($this->_compress_type == 'bz2')
+                  @bzwrite($this->_file, $p_binary_data, $p_len);
+              else if ($this->_compress_type == 'none')
+                  @fputs($this->_file, $p_binary_data, $p_len);
+              else
+                  $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
+
+          }
+      }
+      return true;
+    }
+    // }}}
+
+    // {{{ _readBlock()
+    function _readBlock($p_len=null)
+    {
+      $v_block = null;
+      if ($this->_file) {
+          if ($p_len === null)
+              $p_len = 512;
+              
+          if ($this->_compress_type == 'gz')
+              $v_block = @gzread($this->_file, 512);
+          else if ($this->_compress_type == 'bz2')
+              $v_block = @bzread($this->_file, 512);
+          else if ($this->_compress_type == 'none')
+              $v_block = @fread($this->_file, 512);
+          else
+              $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
+
+      }
+      return $v_block;
+    }
+    // }}}
+
+    // {{{ _jumpBlock()
+    function _jumpBlock($p_len=null)
+    {
+      if ($this->_file) {
+          if ($p_len === null)
+              $p_len = 1;
+
+          if ($this->_compress_type == 'gz')
+              @gzseek($this->_file, @gztell($this->_file)+($p_len*512));
+          else if ($this->_compress_type == 'bz2') {
+              // ----- Replace missing bztell() and bzseek()
+              for ($i=0; $i<$p_len; $i++)
+                  $this->_readBlock();
+          } else if ($this->_compress_type == 'none')
+              @fseek($this->_file, @ftell($this->_file)+($p_len*512));
+          else
+              $this->_error('Unknown or missing compression type ('.$this->_compress_type.')');
+
+      }
+      return true;
+    }
+    // }}}
+
     // {{{ _writeFooter()
     function _writeFooter()
     {
       if ($this->_file) {
           // ----- Write the last 0 filled block for end of archive
           $v_binary_data = pack("a512", '');
-          if ($this->_compress)
-            @gzputs($this->_file, $v_binary_data);
-          else
-            @fputs($this->_file, $v_binary_data);
+          $this->_writeBlock($v_binary_data);
       }
       return true;
     }
@@ -661,10 +831,7 @@ class Archive_Tar extends PEAR
 
           while (($v_buffer = fread($v_file, 512)) != '') {
               $v_binary_data = pack("a512", "$v_buffer");
-              if ($this->_compress)
-                  @gzputs($this->_file, $v_binary_data);
-              else
-                  @fputs($this->_file, $v_binary_data);
+              $this->_writeBlock($v_binary_data);
           }
 
           fclose($v_file);
@@ -679,6 +846,35 @@ class Archive_Tar extends PEAR
     }
     // }}}
 
+    // {{{ _addString()
+    function _addString($p_filename, $p_string)
+    {
+      if (!$this->_file) {
+          $this->_error('Invalid file descriptor');
+          return false;
+      }
+
+      if ($p_filename == '') {
+          $this->_error('Invalid file name');
+          return false;
+      }
+
+      // ----- Calculate the stored filename
+      $p_filename = $this->_translateWinPath($p_filename, false);;
+
+      if (!$this->_writeHeaderBlock($p_filename, strlen($p_string), 0, 0, "", 0, 0))
+          return false;
+
+      $i=0;
+      while (($v_buffer = substr($p_string, (($i++)*512), 512)) != '') {
+          $v_binary_data = pack("a512", $v_buffer);
+          $this->_writeBlock($v_binary_data);
+      }
+
+      return true;
+    }
+    // }}}
+
     // {{{ _writeHeader()
     function _writeHeader($p_filename, $p_stored_filename)
     {
@@ -687,7 +883,7 @@ class Archive_Tar extends PEAR
         $v_reduce_filename = $this->_pathReduction($p_stored_filename);
 
         if (strlen($v_reduce_filename) > 99) {
-          if (!$this->_writeLongHeader($p_stored_filename))
+          if (!$this->_writeLongHeader($v_reduce_filename))
             return false;
         }
 
@@ -739,24 +935,83 @@ class Archive_Tar extends PEAR
             $v_checksum += ord(substr($v_binary_data_last,$j,1));
 
         // ----- Write the first 148 bytes of the header in the archive
-        if ($this->_compress)
-            @gzputs($this->_file, $v_binary_data_first, 148);
-        else
-            @fputs($this->_file, $v_binary_data_first, 148);
+        $this->_writeBlock($v_binary_data_first, 148);
 
         // ----- Write the calculated checksum
         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
         $v_binary_data = pack("a8", $v_checksum);
-        if ($this->_compress)
-          @gzputs($this->_file, $v_binary_data, 8);
-        else
-          @fputs($this->_file, $v_binary_data, 8);
+        $this->_writeBlock($v_binary_data, 8);
 
         // ----- Write the last 356 bytes of the header in the archive
-        if ($this->_compress)
-            @gzputs($this->_file, $v_binary_data_last, 356);
-        else
-            @fputs($this->_file, $v_binary_data_last, 356);
+        $this->_writeBlock($v_binary_data_last, 356);
+
+        return true;
+    }
+    // }}}
+
+    // {{{ _writeHeaderBlock()
+    function _writeHeaderBlock($p_filename, $p_size, $p_mtime=0, $p_perms=0, $p_type='', $p_uid=0, $p_gid=0)
+    {
+        $p_filename = $this->_pathReduction($p_filename);
+
+        if (strlen($p_filename) > 99) {
+          if (!$this->_writeLongHeader($p_filename))
+            return false;
+        }
+
+        if ($p_type == "5") {
+          $v_size = sprintf("%11s ", DecOct(0));
+        } else {
+          $v_size = sprintf("%11s ", DecOct($p_size));
+        }
+
+        $v_uid = sprintf("%6s ", DecOct($p_uid));
+        $v_gid = sprintf("%6s ", DecOct($p_gid));
+        $v_perms = sprintf("%6s ", DecOct($p_perms));
+
+        $v_mtime = sprintf("%11s", DecOct($p_mtime));
+
+        $v_linkname = '';
+
+        $v_magic = '';
+
+        $v_version = '';
+
+        $v_uname = '';
+
+        $v_gname = '';
+
+        $v_devmajor = '';
+
+        $v_devminor = '';
+
+        $v_prefix = '';
+
+        $v_binary_data_first = pack("a100a8a8a8a12A12", $p_filename, $v_perms, $v_uid, $v_gid, $v_size, $v_mtime);
+        $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", $p_type, $v_linkname, $v_magic, $v_version, $v_uname, $v_gname, $v_devmajor, $v_devminor, $v_prefix, '');
+
+        // ----- Calculate the checksum
+        $v_checksum = 0;
+        // ..... First part of the header
+        for ($i=0; $i<148; $i++)
+            $v_checksum += ord(substr($v_binary_data_first,$i,1));
+        // ..... Ignore the checksum value and replace it by ' ' (space)
+        for ($i=148; $i<156; $i++)
+            $v_checksum += ord(' ');
+        // ..... Last part of the header
+        for ($i=156, $j=0; $i<512; $i++, $j++)
+            $v_checksum += ord(substr($v_binary_data_last,$j,1));
+
+        // ----- Write the first 148 bytes of the header in the archive
+        $this->_writeBlock($v_binary_data_first, 148);
+
+        // ----- Write the calculated checksum
+        $v_checksum = sprintf("%6s ", DecOct($v_checksum));
+        $v_binary_data = pack("a8", $v_checksum);
+        $this->_writeBlock($v_binary_data, 8);
+
+        // ----- Write the last 356 bytes of the header in the archive
+        $this->_writeBlock($v_binary_data_last, 356);
 
         return true;
     }
@@ -801,33 +1056,21 @@ class Archive_Tar extends PEAR
             $v_checksum += ord(substr($v_binary_data_last,$j,1));
 
         // ----- Write the first 148 bytes of the header in the archive
-        if ($this->_compress)
-            @gzputs($this->_file, $v_binary_data_first, 148);
-        else
-            @fputs($this->_file, $v_binary_data_first, 148);
+        $this->_writeBlock($v_binary_data_first, 148);
 
         // ----- Write the calculated checksum
         $v_checksum = sprintf("%6s ", DecOct($v_checksum));
         $v_binary_data = pack("a8", $v_checksum);
-        if ($this->_compress)
-          @gzputs($this->_file, $v_binary_data, 8);
-        else
-          @fputs($this->_file, $v_binary_data, 8);
+        $this->_writeBlock($v_binary_data, 8);
 
         // ----- Write the last 356 bytes of the header in the archive
-        if ($this->_compress)
-            @gzputs($this->_file, $v_binary_data_last, 356);
-        else
-            @fputs($this->_file, $v_binary_data_last, 356);
+        $this->_writeBlock($v_binary_data_last, 356);
 
         // ----- Write the filename as content of the block
         $i=0;
         while (($v_buffer = substr($p_filename, (($i++)*512), 512)) != '') {
             $v_binary_data = pack("a512", "$v_buffer");
-            if ($this->_compress)
-                @gzputs($this->_file, $v_binary_data);
-            else
-                @fputs($this->_file, $v_binary_data);
+            $this->_writeBlock($v_binary_data);
         }
 
         return true;
@@ -871,7 +1114,7 @@ class Archive_Tar extends PEAR
             if (($v_checksum == 256) && ($v_header['checksum'] == 0))
                 return true;
 
-            $this->_error('Invalid checksum : '.$v_checksum.' calculated, '.$v_header['checksum'].' expected');
+            $this->_error('Invalid checksum for file "'.$v_data['filename'].'" : '.$v_checksum.' calculated, '.$v_header['checksum'].' expected');
             return false;
         }
 
@@ -905,25 +1148,16 @@ class Archive_Tar extends PEAR
       $v_filename = '';
       $n = floor($v_header['size']/512);
       for ($i=0; $i<$n; $i++) {
-        if ($this->_compress)
-          $v_content = @gzread($this->_file, 512);
-        else
-          $v_content = @fread($this->_file, 512);
+        $v_content = $this->_readBlock();
         $v_filename .= $v_content;
       }
       if (($v_header['size'] % 512) != 0) {
-        if ($this->_compress)
-          $v_content = @gzread($this->_file, 512);
-        else
-          $v_content = @fread($this->_file, 512);
+        $v_content = $this->_readBlock();
         $v_filename .= $v_content;
       }
 
       // ----- Read the next header
-      if ($this->_compress)
-        $v_binary_data = @gzread($this->_file, 512);
-      else
-        $v_binary_data = @fread($this->_file, 512);
+      $v_binary_data = $this->_readBlock();
 
       if (!$this->_readHeader($v_binary_data, $v_header))
         return false;
@@ -934,6 +1168,56 @@ class Archive_Tar extends PEAR
     }
     // }}}
 
+    // {{{ _extractInString()
+    /**
+    * This method extract from the archive one file identified by $p_filename.
+    * The return value is a string with the file content, or NULL on error.
+    * @param string $p_filename     The path of the file to extract in a string.
+    * @return                       a string with the file content or NULL.
+    * @access private
+    */
+    function _extractInString($p_filename)
+    {
+        $v_result_str = "";
+
+        While (strlen($v_binary_data = $this->_readBlock()) != 0)
+        {
+          if (!$this->_readHeader($v_binary_data, $v_header))
+            return NULL;
+
+          if ($v_header['filename'] == '')
+            continue;
+
+          // ----- Look for long filename
+          if ($v_header['typeflag'] == 'L') {
+            if (!$this->_readLongHeader($v_header))
+              return NULL;
+          }
+
+          if ($v_header['filename'] == $p_filename) {
+              if ($v_header['typeflag'] == "5") {
+                  $this->_error('Unable to extract in string a directory entry {'.$v_header['filename'].'}');
+                  return NULL;
+              } else {
+                  $n = floor($v_header['size']/512);
+                  for ($i=0; $i<$n; $i++) {
+                      $v_result_str .= $this->_readBlock();
+                  }
+                  if (($v_header['size'] % 512) != 0) {
+                      $v_content = $this->_readBlock();
+                      $v_result_str .= substr($v_content, 0, ($v_header['size'] % 512));
+                  }
+                  return $v_result_str;
+              }
+          } else {
+              $this->_jumpBlock(ceil(($v_header['size']/512)));
+          }
+        }
+
+        return NULL;
+    }
+    // }}}
+
     // {{{ _extractList()
     function _extractList($p_path, &$p_list_detail, $p_mode, $p_file_list, $p_remove_path)
     {
@@ -973,16 +1257,11 @@ class Archive_Tar extends PEAR
 
     clearstatcache();
 
-    While (!($v_end_of_file = ($this->_compress?@gzeof($this->_file):@feof($this->_file))))
+    While (strlen($v_binary_data = $this->_readBlock()) != 0)
     {
       $v_extract_file = FALSE;
       $v_extraction_stopped = 0;
 
-      if ($this->_compress)
-        $v_binary_data = @gzread($this->_file, 512);
-      else
-        $v_binary_data = @fread($this->_file, 512);
-
       if (!$this->_readHeader($v_binary_data, $v_header))
         return false;
 
@@ -1073,17 +1352,11 @@ class Archive_Tar extends PEAR
               } else {
                   $n = floor($v_header['size']/512);
                   for ($i=0; $i<$n; $i++) {
-                      if ($this->_compress)
-                          $v_content = @gzread($this->_file, 512);
-                      else
-                          $v_content = @fread($this->_file, 512);
+                      $v_content = $this->_readBlock();
                       fwrite($v_dest_file, $v_content, 512);
                   }
             if (($v_header['size'] % 512) != 0) {
-              if ($this->_compress)
-                $v_content = @gzread($this->_file, 512);
-              else
-                $v_content = @fread($this->_file, 512);
+              $v_content = $this->_readBlock();
               fwrite($v_dest_file, $v_content, ($v_header['size'] % 512));
             }
 
@@ -1103,24 +1376,18 @@ class Archive_Tar extends PEAR
           }
           }
         } else {
-          // ----- Jump to next file
-          if ($this->_compress)
-              @gzseek($this->_file, @gztell($this->_file)+(ceil(($v_header['size']/512))*512));
-          else
-              @fseek($this->_file, @ftell($this->_file)+(ceil(($v_header['size']/512))*512));
+          $this->_jumpBlock(ceil(($v_header['size']/512)));
         }
       } else {
-        // ----- Jump to next file
-        if ($this->_compress)
-          @gzseek($this->_file, @gztell($this->_file)+(ceil(($v_header['size']/512))*512));
-        else
-          @fseek($this->_file, @ftell($this->_file)+(ceil(($v_header['size']/512))*512));
+          $this->_jumpBlock(ceil(($v_header['size']/512)));
       }
 
+      /* TBC : Seems to be unused ...
       if ($this->_compress)
         $v_end_of_file = @gzeof($this->_file);
       else
         $v_end_of_file = @feof($this->_file);
+        */
 
       if ($v_listing || $v_extract_file || $v_extraction_stopped) {
         // ----- Log extracted files
@@ -1137,9 +1404,12 @@ class Archive_Tar extends PEAR
     }
     // }}}
 
-    // {{{ _append()
-    function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
+    // {{{ _openAppend()
+    function _openAppend()
     {
+        if (filesize($this->_tarname) == 0)
+          return $this->_openWrite();
+          
         if ($this->_compress) {
             $this->_close();
 
@@ -1148,7 +1418,12 @@ class Archive_Tar extends PEAR
                 return false;
             }
 
-            if (($v_temp_tar = @gzopen($this->_tarname.".tmp", "rb")) == 0) {
+            if ($this->_compress_type == 'gz')
+                $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb");
+            elseif ($this->_compress_type == 'bz2')
+                $v_temp_tar = @bzopen($this->_tarname.".tmp", "rb");
+                
+            if ($v_temp_tar == 0) {
                 $this->_error('Unable to open file \''.$this->_tarname.'.tmp\' in binary read mode');
                 @rename($this->_tarname.".tmp", $this->_tarname);
                 return false;
@@ -1159,39 +1434,58 @@ class Archive_Tar extends PEAR
                 return false;
             }
 
-            $v_buffer = @gzread($v_temp_tar, 512);
+            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");
-                    @gzputs($this->_file, $v_binary_data);
-                    $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));
+                }
 
-            if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
-                $this->_writeFooter();
+                @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));
+                    $this->_writeBlock($v_binary_data);
+                }
 
-            $this->_close();
-            @gzclose($v_temp_tar);
+                @bzclose($v_temp_tar);
+            }
 
             if (!@unlink($this->_tarname.".tmp")) {
                 $this->_error('Error while deleting temporary file \''.$this->_tarname.'.tmp\'');
             }
 
-            return true;
-        }
+        } else {
+            // ----- For not compressed tar, just add files before the last 512 bytes block
+            if (!$this->_openReadWrite())
+               return false;
 
-        // ----- For not compressed tar, just add files before the last 512 bytes block
-        if (!$this->_openReadWrite())
-           return false;
+            clearstatcache();
+            $v_size = filesize($this->_tarname);
+            fseek($this->_file, $v_size-512);
+        }
 
-        clearstatcache();
-        $v_size = filesize($this->_tarname);
-        fseek($this->_file, $v_size-512);
+        return true;
+    }
+    // }}}
 
+    // {{{ _append()
+    function _append($p_filelist, $p_add_dir='', $p_remove_dir='')
+    {
+        if (!$this->_openAppend())
+            return false;
+            
         if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir))
            $this->_writeFooter();
 
@@ -1298,4 +1592,4 @@ class Archive_Tar extends PEAR
     // }}}
 
 }
-?>
\ No newline at end of file
+?>