Changeset 21018
- Timestamp:
- 2011/07/06 16:53:50 (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/version-2_11-dev/data/module/Tar.php
r20116 r21018 1 1 <?php 2 /* vim: set ts=4 sw=4: */ 3 // +----------------------------------------------------------------------+ 4 // | PHP Version 4 | 5 // +----------------------------------------------------------------------+ 6 // | Copyright (c) 1997-2003 The PHP Group | 7 // +----------------------------------------------------------------------+ 8 // | This source file is subject to version 3.0 of the PHP license, | 9 // | that is bundled with this package in the file LICENSE, and is | 10 // | available through the world-wide-web at the following url: | 11 // | http://www.php.net/license/3_0.txt. | 12 // | If you did not receive a copy of the PHP license and are unable to | 13 // | obtain it through the world-wide-web, please send a note to | 14 // | license@php.net so we can mail you a copy immediately. | 15 // +----------------------------------------------------------------------+ 16 // | Author: Vincent Blavet <vincent@phpconcept.net> | 17 // +----------------------------------------------------------------------+ 18 // 19 // $Id$ 2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4 /** 5 * File::CSV 6 * 7 * PHP versions 4 and 5 8 * 9 * Copyright (c) 1997-2008, 10 * Vincent Blavet <vincent@phpconcept.net> 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions are met: 15 * 16 * * Redistributions of source code must retain the above copyright notice, 17 * this list of conditions and the following disclaimer. 18 * * Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * 34 * @category File_Formats 35 * @package Archive_Tar 36 * @author Vincent Blavet <vincent@phpconcept.net> 37 * @copyright 1997-2008 The Authors 38 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 39 * @version CVS: $Id$ 40 * @link http://pear.php.net/package/Archive_Tar 41 */ 20 42 21 43 if(!defined('TAR_PHP_DIR')) { 22 44 $TAR_PHP_DIR = realpath(dirname( __FILE__)); 23 define("TAR_PHP_DIR", $TAR_PHP_DIR); 45 define("TAR_PHP_DIR", $TAR_PHP_DIR); 24 46 } 25 47 26 48 require_once TAR_PHP_DIR . '/PEAR.php'; 27 49 28 29 50 define ('ARCHIVE_TAR_ATT_SEPARATOR', 90001); 51 define ('ARCHIVE_TAR_END_BLOCK', pack("a512", '')); 30 52 31 53 /** … … 33 55 * 34 56 * @author Vincent Blavet <vincent@phpconcept.net> 35 * @version $Revision: 4772 $ 36 * @package Archive 57 * @version $Revision: 295988 $ 58 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 59 * @package Archive_Tar 37 60 */ 38 61 class Archive_Tar extends PEAR … … 67 90 */ 68 91 var $_temp_tarname=''; 92 93 /** 94 * @var string regular expression for ignoring files or directories 95 */ 96 var $_ignore_regexp=''; 69 97 70 98 // {{{ constructor … … 123 151 $this->_compress_type = 'bz2'; 124 152 } else { 125 die("Unsupported compression type '$p_compress'\n".153 $this->_error("Unsupported compression type '$p_compress'\n". 126 154 "Supported types are 'gz' and 'bz2'.\n"); 127 155 return false; … … 139 167 } 140 168 if (!extension_loaded($extname)) { 141 die("The extension '$extname' couldn't be found.\n".169 $this->_error("The extension '$extname' couldn't be found.\n". 142 170 "Please make sure your version of PHP was built ". 143 171 "with '$extname' support.\n"); … … 183 211 function create($p_filelist) 184 212 { 185 213 return $this->createModify($p_filelist, '', ''); 186 214 } 187 215 // }}} … … 382 410 { 383 411 $v_result = true; 384 412 385 413 if (!$this->_isArchive()) { 386 414 if (!$this->_openWrite()) { … … 389 417 $this->_close(); 390 418 } 391 419 392 420 if (!$this->_openAppend()) 393 421 return false; … … 529 557 { 530 558 $v_result = true; 531 559 532 560 // ----- Get the number of variable list of arguments 533 561 if (($v_size = func_num_args()) == 0) { 534 562 return true; 535 563 } 536 564 537 565 // ----- Get the arguments 538 566 $v_att_list = &func_get_args(); … … 571 599 // }}} 572 600 601 // {{{ setIgnoreRegexp() 602 /** 603 * This method sets the regular expression for ignoring files and directories 604 * at import, for example: 605 * $arch->setIgnoreRegexp("#CVS|\.svn#"); 606 * @param string $regexp regular expression defining which files or directories to ignore 607 * @access public 608 */ 609 function setIgnoreRegexp($regexp) 610 { 611 $this->_ignore_regexp = $regexp; 612 } 613 // }}} 614 615 // {{{ setIgnoreList() 616 /** 617 * This method sets the regular expression for ignoring all files and directories 618 * matching the filenames in the array list at import, for example: 619 * $arch->setIgnoreList(array('CVS', '.svn', 'bin/tool')); 620 * @param array $list a list of file or directory names to ignore 621 * @access public 622 */ 623 function setIgnoreList($list) 624 { 625 $regexp = str_replace(array('#', '.', '^', '$'), array('\#', '\.', '\^', '\$'), $list); 626 $regexp = '#/'.join('$|/', $list).'#'; 627 $this->setIgnoreRegexp($regexp); 628 } 629 // }}} 630 573 631 // {{{ _error() 574 632 function _error($p_message) … … 594 652 } 595 653 clearstatcache(); 596 return @is_file($p_filename) ;654 return @is_file($p_filename) && !@is_link($p_filename); 597 655 } 598 656 // }}} … … 604 662 $this->_file = @gzopen($this->_tarname, "wb9"); 605 663 else if ($this->_compress_type == 'bz2') 606 $this->_file = @bzopen($this->_tarname, "w b");664 $this->_file = @bzopen($this->_tarname, "w"); 607 665 else if ($this->_compress_type == 'none') 608 666 $this->_file = @fopen($this->_tarname, "wb"); … … 657 715 $this->_file = @gzopen($v_filename, "rb"); 658 716 else if ($this->_compress_type == 'bz2') 659 $this->_file = @bzopen($v_filename, "r b");717 $this->_file = @bzopen($v_filename, "r"); 660 718 else if ($this->_compress_type == 'none') 661 719 $this->_file = @fopen($v_filename, "rb"); … … 678 736 if ($this->_compress_type == 'gz') 679 737 $this->_file = @gzopen($this->_tarname, "r+b"); 680 else if ($this->_compress_type == 'bz2') 681 $this->_file = @bzopen($this->_tarname, "r+b"); 682 else if ($this->_compress_type == 'none') 738 else if ($this->_compress_type == 'bz2') { 739 $this->_error('Unable to open bz2 in read/write mode \'' 740 .$this->_tarname.'\' (limitation of bz2 extension)'); 741 return false; 742 } else if ($this->_compress_type == 'none') 683 743 $this->_file = @fopen($this->_tarname, "r+b"); 684 744 else … … 803 863 804 864 if ($this->_compress_type == 'gz') { 805 @gzseek($this->_file, @gztell($this->_file)+($p_len*512));865 @gzseek($this->_file, gztell($this->_file)+($p_len*512)); 806 866 } 807 867 else if ($this->_compress_type == 'bz2') { … … 810 870 $this->_readBlock(); 811 871 } else if ($this->_compress_type == 'none') 812 @fseek($this->_file, @ftell($this->_file)+($p_len*512));872 @fseek($this->_file, $p_len*512, SEEK_CUR); 813 873 else 814 874 $this->_error('Unknown or missing compression type (' … … 825 885 if (is_resource($this->_file)) { 826 886 // ----- Write the last 0 filled block for end of archive 827 $v_binary_data = pack( "a512", '');887 $v_binary_data = pack('a1024', ''); 828 888 $this->_writeBlock($v_binary_data); 829 889 } … … 862 922 continue; 863 923 924 // ----- ignore files and directories matching the ignore regular expression 925 if ($this->_ignore_regexp && preg_match($this->_ignore_regexp, '/'.$v_filename)) { 926 $this->_warning("File '$v_filename' ignored"); 927 continue; 928 } 929 864 930 if (!file_exists($v_filename)) { 865 931 $this->_warning("File '$v_filename' does not exist"); … … 871 937 return false; 872 938 873 if (@is_dir($v_filename) ) {939 if (@is_dir($v_filename) && !@is_link($v_filename)) { 874 940 if (!($p_hdir = opendir($v_filename))) { 875 941 $this->_warning("Directory '$v_filename' can not be read"); … … 979 1045 980 1046 if (!$this->_writeHeaderBlock($p_filename, strlen($p_string), 981 0, 0, "", 0, 0))1047 time(), 384, "", 0, 0)) 982 1048 return false; 983 1049 … … 1004 1070 } 1005 1071 1006 $v_info = stat($p_filename); 1007 $v_uid = sprintf("%6s ", DecOct($v_info[4])); 1008 $v_gid = sprintf("%6s ", DecOct($v_info[5])); 1009 $v_perms = sprintf("%6s ", DecOct(fileperms($p_filename))); 1010 1011 $v_mtime = sprintf("%11s", DecOct(filemtime($p_filename))); 1012 1013 if (@is_dir($p_filename)) { 1072 $v_info = lstat($p_filename); 1073 $v_uid = sprintf("%07s", DecOct($v_info[4])); 1074 $v_gid = sprintf("%07s", DecOct($v_info[5])); 1075 $v_perms = sprintf("%07s", DecOct($v_info['mode'] & 000777)); 1076 1077 $v_mtime = sprintf("%011s", DecOct($v_info['mtime'])); 1078 1079 $v_linkname = ''; 1080 1081 if (@is_link($p_filename)) { 1082 $v_typeflag = '2'; 1083 $v_linkname = readlink($p_filename); 1084 $v_size = sprintf("%011s", DecOct(0)); 1085 } elseif (@is_dir($p_filename)) { 1014 1086 $v_typeflag = "5"; 1015 $v_size = sprintf("% 11s", DecOct(0));1087 $v_size = sprintf("%011s", DecOct(0)); 1016 1088 } else { 1017 $v_typeflag = ' ';1089 $v_typeflag = '0'; 1018 1090 clearstatcache(); 1019 $v_size = sprintf("%11s ", DecOct(filesize($p_filename))); 1020 } 1021 1022 $v_linkname = ''; 1023 1024 $v_magic = ''; 1025 1026 $v_version = ''; 1027 1028 $v_uname = ''; 1029 1030 $v_gname = ''; 1091 $v_size = sprintf("%011s", DecOct($v_info['size'])); 1092 } 1093 1094 $v_magic = 'ustar '; 1095 1096 $v_version = ' '; 1097 1098 if (function_exists('posix_getpwuid')) 1099 { 1100 $userinfo = posix_getpwuid($v_info[4]); 1101 $groupinfo = posix_getgrgid($v_info[5]); 1102 1103 $v_uname = $userinfo['name']; 1104 $v_gname = $groupinfo['name']; 1105 } 1106 else 1107 { 1108 $v_uname = ''; 1109 $v_gname = ''; 1110 } 1031 1111 1032 1112 $v_devmajor = ''; … … 1036 1116 $v_prefix = ''; 1037 1117 1038 $v_binary_data_first = pack("a100a8a8a8a12 A12",1118 $v_binary_data_first = pack("a100a8a8a8a12a12", 1039 1119 $v_reduce_filename, $v_perms, $v_uid, 1040 1120 $v_gid, $v_size, $v_mtime); … … 1060 1140 1061 1141 // ----- Write the calculated checksum 1062 $v_checksum = sprintf("% 6s ", DecOct($v_checksum));1142 $v_checksum = sprintf("%06s ", DecOct($v_checksum)); 1063 1143 $v_binary_data = pack("a8", $v_checksum); 1064 1144 $this->_writeBlock($v_binary_data, 8); … … 1083 1163 1084 1164 if ($p_type == "5") { 1085 $v_size = sprintf("% 11s", DecOct(0));1165 $v_size = sprintf("%011s", DecOct(0)); 1086 1166 } else { 1087 $v_size = sprintf("% 11s", DecOct($p_size));1088 } 1089 1090 $v_uid = sprintf("% 6s", DecOct($p_uid));1091 $v_gid = sprintf("% 6s", DecOct($p_gid));1092 $v_perms = sprintf("% 6s ", DecOct($p_perms));1167 $v_size = sprintf("%011s", DecOct($p_size)); 1168 } 1169 1170 $v_uid = sprintf("%07s", DecOct($p_uid)); 1171 $v_gid = sprintf("%07s", DecOct($p_gid)); 1172 $v_perms = sprintf("%07s", DecOct($p_perms & 000777)); 1093 1173 1094 1174 $v_mtime = sprintf("%11s", DecOct($p_mtime)); … … 1096 1176 $v_linkname = ''; 1097 1177 1098 $v_magic = ''; 1099 1100 $v_version = ''; 1101 1102 $v_uname = ''; 1103 1104 $v_gname = ''; 1178 $v_magic = 'ustar '; 1179 1180 $v_version = ' '; 1181 1182 if (function_exists('posix_getpwuid')) 1183 { 1184 $userinfo = posix_getpwuid($p_uid); 1185 $groupinfo = posix_getgrgid($p_gid); 1186 1187 $v_uname = $userinfo['name']; 1188 $v_gname = $groupinfo['name']; 1189 } 1190 else 1191 { 1192 $v_uname = ''; 1193 $v_gname = ''; 1194 } 1105 1195 1106 1196 $v_devmajor = ''; … … 1134 1224 1135 1225 // ----- Write the calculated checksum 1136 $v_checksum = sprintf("% 6s ", DecOct($v_checksum));1226 $v_checksum = sprintf("%06s ", DecOct($v_checksum)); 1137 1227 $v_binary_data = pack("a8", $v_checksum); 1138 1228 $this->_writeBlock($v_binary_data, 8); … … 1168 1258 $v_prefix = ''; 1169 1259 1170 $v_binary_data_first = pack("a100a8a8a8a12 A12",1260 $v_binary_data_first = pack("a100a8a8a8a12a12", 1171 1261 '././@LongLink', 0, 0, 0, $v_size, 0); 1172 1262 $v_binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", … … 1191 1281 1192 1282 // ----- Write the calculated checksum 1193 $v_checksum = sprintf("% 6s ", DecOct($v_checksum));1283 $v_checksum = sprintf("%06s ", DecOct($v_checksum)); 1194 1284 $v_binary_data = pack("a8", $v_checksum); 1195 1285 $this->_writeBlock($v_binary_data, 8); … … 1223 1313 } 1224 1314 1315 if (!is_array($v_header)) { 1316 $v_header = array(); 1317 } 1225 1318 // ----- Calculate the checksum 1226 1319 $v_checksum = 0; … … 1256 1349 1257 1350 // ----- Extract the properties 1258 $v_header['filename'] = trim($v_data['filename']); 1351 $v_header['filename'] = $v_data['filename']; 1352 if ($this->_maliciousFilename($v_header['filename'])) { 1353 $this->_error('Malicious .tar detected, file "' . $v_header['filename'] . 1354 '" will not install in desired directory tree'); 1355 return false; 1356 } 1259 1357 $v_header['mode'] = OctDec(trim($v_data['mode'])); 1260 1358 $v_header['uid'] = OctDec(trim($v_data['uid'])); … … 1265 1363 $v_header['size'] = 0; 1266 1364 } 1365 $v_header['link'] = trim($v_data['link']); 1267 1366 /* ----- All these fields are removed form the header because 1268 1367 they do not carry interesting info 1269 $v_header[link] = trim($v_data[link]);1270 1368 $v_header[magic] = trim($v_data[magic]); 1271 1369 $v_header[version] = trim($v_data[version]); … … 1280 1378 // }}} 1281 1379 1380 // {{{ _maliciousFilename() 1381 /** 1382 * Detect and report a malicious file name 1383 * 1384 * @param string $file 1385 * @return bool 1386 * @access private 1387 */ 1388 function _maliciousFilename($file) 1389 { 1390 if (strpos($file, '/../') !== false) { 1391 return true; 1392 } 1393 if (strpos($file, '../') === 0) { 1394 return true; 1395 } 1396 return false; 1397 } 1398 // }}} 1399 1282 1400 // {{{ _readLongHeader() 1283 1401 function _readLongHeader(&$v_header) … … 1291 1409 if (($v_header['size'] % 512) != 0) { 1292 1410 $v_content = $this->_readBlock(); 1293 $v_filename .= $v_content;1411 $v_filename .= trim($v_content); 1294 1412 } 1295 1413 … … 1300 1418 return false; 1301 1419 1420 $v_filename = trim($v_filename); 1302 1421 $v_header['filename'] = $v_filename; 1422 if ($this->_maliciousFilename($v_filename)) { 1423 $this->_error('Malicious .tar detected, file "' . $v_filename . 1424 '" will not install in desired directory tree'); 1425 return false; 1426 } 1303 1427 1304 1428 return true; … … 1501 1625 } 1502 1626 } 1627 } elseif ($v_header['typeflag'] == "2") { 1628 if (@file_exists($v_header['filename'])) { 1629 @unlink($v_header['filename']); 1630 } 1631 if (!@symlink($v_header['link'], $v_header['filename'])) { 1632 $this->_error('Unable to extract symbolic link {' 1633 .$v_header['filename'].'}'); 1634 return false; 1635 } 1503 1636 } else { 1504 1637 if (($v_dest_file = @fopen($v_header['filename'], "wb")) == 0) { … … 1521 1654 // ----- Change the file mode, mtime 1522 1655 @touch($v_header['filename'], $v_header['mtime']); 1523 // To be completed 1524 //chmod($v_header[filename], DecOct($v_header[mode])); 1656 if ($v_header['mode'] & 0111) { 1657 // make file executable, obey umask 1658 $mode = fileperms($v_header['filename']) | (~umask() & 0111); 1659 @chmod($v_header['filename'], $mode); 1660 } 1525 1661 } 1526 1662 … … 1559 1695 1560 1696 $p_list_detail[$v_nb++] = $v_header; 1697 if (is_array($p_file_list) && (count($p_list_detail) == count($p_file_list))) { 1698 return true; 1699 } 1561 1700 } 1562 1701 } … … 1571 1710 if (filesize($this->_tarname) == 0) 1572 1711 return $this->_openWrite(); 1573 1712 1574 1713 if ($this->_compress) { 1575 1714 $this->_close(); … … 1585 1724 $v_temp_tar = @gzopen($this->_tarname.".tmp", "rb"); 1586 1725 elseif ($this->_compress_type == 'bz2') 1587 $v_temp_tar = @bzopen($this->_tarname.".tmp", "r b");1588 1726 $v_temp_tar = @bzopen($this->_tarname.".tmp", "r"); 1727 1589 1728 if ($v_temp_tar == 0) { 1590 1729 $this->_error('Unable to open file \''.$this->_tarname … … 1600 1739 1601 1740 if ($this->_compress_type == 'gz') { 1602 $v_buffer = @gzread($v_temp_tar, 512); 1603 1604 // ----- Read the following blocks but not the last one 1605 if (!@gzeof($v_temp_tar)) { 1606 do{ 1607 $v_binary_data = pack("a512", $v_buffer); 1608 $this->_writeBlock($v_binary_data); 1609 $v_buffer = @gzread($v_temp_tar, 512); 1610 1611 } while (!@gzeof($v_temp_tar)); 1741 while (!@gzeof($v_temp_tar)) { 1742 $v_buffer = @gzread($v_temp_tar, 512); 1743 if ($v_buffer == ARCHIVE_TAR_END_BLOCK) { 1744 // do not copy end blocks, we will re-make them 1745 // after appending 1746 continue; 1747 } 1748 $v_binary_data = pack("a512", $v_buffer); 1749 $this->_writeBlock($v_binary_data); 1612 1750 } 1613 1751 … … 1615 1753 } 1616 1754 elseif ($this->_compress_type == 'bz2') { 1617 $v_buffered_lines = array(); 1618 $v_buffered_lines[] = @bzread($v_temp_tar, 512); 1619 1620 // ----- Read the following blocks but not the last one 1621 while (strlen($v_buffered_lines[] 1622 = @bzread($v_temp_tar, 512)) > 0) { 1623 $v_binary_data = pack("a512", 1624 array_shift($v_buffered_lines)); 1755 while (strlen($v_buffer = @bzread($v_temp_tar, 512)) > 0) { 1756 if ($v_buffer == ARCHIVE_TAR_END_BLOCK) { 1757 continue; 1758 } 1759 $v_binary_data = pack("a512", $v_buffer); 1625 1760 $this->_writeBlock($v_binary_data); 1626 1761 } … … 1636 1771 } else { 1637 1772 // ----- For not compressed tar, just add files before the last 1638 // 512 bytes block1773 // one or two 512 bytes block 1639 1774 if (!$this->_openReadWrite()) 1640 1775 return false; … … 1642 1777 clearstatcache(); 1643 1778 $v_size = filesize($this->_tarname); 1644 fseek($this->_file, $v_size-512); 1779 1780 // We might have zero, one or two end blocks. 1781 // The standard is two, but we should try to handle 1782 // other cases. 1783 fseek($this->_file, $v_size - 1024); 1784 if (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { 1785 fseek($this->_file, $v_size - 1024); 1786 } 1787 elseif (fread($this->_file, 512) == ARCHIVE_TAR_END_BLOCK) { 1788 fseek($this->_file, $v_size - 512); 1789 } 1645 1790 } 1646 1791 … … 1654 1799 if (!$this->_openAppend()) 1655 1800 return false; 1656 1801 1657 1802 if ($this->_addList($p_filelist, $p_add_dir, $p_remove_dir)) 1658 1803 $this->_writeFooter(); … … 1676 1821 function _dirCheck($p_dir) 1677 1822 { 1823 clearstatcache(); 1678 1824 if ((@is_dir($p_dir)) || ($p_dir == '')) 1679 1825 return true; … … 1699 1845 1700 1846 /** 1701 * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", 1847 * Compress path by changing for example "/dir/foo/../bar" to "/dir/bar", 1702 1848 * rand emove double slashes. 1703 1849 * … … 1749 1895 function _translateWinPath($p_path, $p_remove_disk_letter=true) 1750 1896 { 1751 if ( OS_WINDOWS) {1897 if (defined('OS_WINDOWS') && OS_WINDOWS) { 1752 1898 // ----- Look for potential disk letter 1753 1899 if ( ($p_remove_disk_letter)
Note: See TracChangeset
for help on using the changeset viewer.