PageRenderTime 61ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/Archive/tests/tar/v7_tar_test.php

https://github.com/Yannix/zetacomponents
PHP | 1143 lines | 787 code | 213 blank | 143 comment | 33 complexity | de030bc1fc7aff15f52341ca3a9f6429 MD5 | raw file
  1. <?php
  2. /**
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one
  5. * or more contributor license agreements. See the NOTICE file
  6. * distributed with this work for additional information
  7. * regarding copyright ownership. The ASF licenses this file
  8. * to you under the Apache License, Version 2.0 (the
  9. * "License"); you may not use this file except in compliance
  10. * with the License. You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing,
  15. * software distributed under the License is distributed on an
  16. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  17. * KIND, either express or implied. See the License for the
  18. * specific language governing permissions and limitations
  19. * under the License.
  20. *
  21. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
  22. * @filesource
  23. * @package Archive
  24. * @version //autogen//
  25. * @subpackage Tests
  26. */
  27. require_once( dirname( __FILE__ ) . "/../archive_test_case.php" );
  28. /**
  29. * @package Archive
  30. * @version //autogen//
  31. * @subpackage Tests
  32. */
  33. class ezcArchiveV7TarTest extends ezcArchiveTestCase
  34. {
  35. protected $canWrite = true;
  36. protected $archive;
  37. protected $complexArchive;
  38. protected $file;
  39. protected $complexFile;
  40. protected $tarFormat;
  41. protected $tarMimeFormat;
  42. protected $usersGid;
  43. public function createTempFile( $file )
  44. {
  45. $original = dirname(__FILE__) . "/../data/$file";
  46. $tmpFile = $this->getTempDir() . "/$file";
  47. copy( $original, $tmpFile );
  48. return $tmpFile;
  49. }
  50. protected function setUp()
  51. {
  52. date_default_timezone_set( "UTC" );
  53. $this->tarFormat = "v7";
  54. $this->tarMimeFormat = ezcArchive::TAR_V7;
  55. $this->createTempDir( "ezcArchive_" );
  56. $this->file = $this->createTempFile( "tar_v7_2_textfiles.tar" );
  57. $blockFile = new ezcArchiveBlockFile( $this->file );
  58. $this->archive = new ezcArchiveV7Tar( $blockFile );
  59. unset( $blockFile );
  60. $this->complexFile = $this->createTempFile( "tar_v7_file_dir_symlink_link.tar" );
  61. $blockFile = new ezcArchiveBlockFile( $this->complexFile );
  62. $this->complexArchive = new ezcArchiveV7Tar( $blockFile );
  63. unset( $blockFile );
  64. $this->setUsersGid();
  65. }
  66. protected function setUsersGid()
  67. {
  68. // figure out the GID for "users" for tests
  69. $this->usersGid = 1000; // default
  70. if ( posix_geteuid() === 0 && function_exists( 'posix_getgrnam' ) )
  71. {
  72. $info = posix_getgrnam( 'users' );
  73. $this->usersGid = $info['gid'];
  74. }
  75. }
  76. protected function tearDown()
  77. {
  78. unset( $this->archive );
  79. unset( $this->complexArchive );
  80. $this->removeTempDir();
  81. }
  82. protected function isWindows()
  83. {
  84. return ( substr( php_uname( 's' ), 0, 7 ) == 'Windows' ) ? true : false;
  85. }
  86. // FIXME
  87. // Move method to the archiveTest.
  88. /*
  89. public function testGetEntryFromFile()
  90. {
  91. $this->archive->extractCurrent( $this->getTempDir() );
  92. $entry = ezcArchive::getEntryFromFile( $this->getTempDir() . "/file1.txt" );
  93. $this->assertEquals( $this->getTempDir() . "/file1.txt", $entry->getPath() );
  94. $this->assertTrue( $entry->isFile() );
  95. $this->assertFalse( $entry->isDirectory() );
  96. // Probably okay.
  97. }
  98. // FIXME
  99. // Move method to the archiveTest.
  100. public function testGetEntryFromFilesWithHardlink()
  101. {
  102. $dir = $this->getTempDir();
  103. $this->complexArchive->seek( 4 ); // File.
  104. $this->complexArchive->extractCurrent( $dir );
  105. $this->complexArchive->seek(8); // Hardlink
  106. $this->complexArchive->extractCurrent( $dir );
  107. $entries = ezcArchive::getEntryFromFile( array( $dir . "/files/bla/file3.txt", $dir . "/files/file4.txt" ) );
  108. $this->assertEquals( 2, sizeof( $entries ), "Sizeof the entries array doesn't match." );
  109. $this->assertFalse( $entries[0]->isLink() );
  110. $this->assertTrue( $entries[1]->isLink() );
  111. $this->assertEquals( "$dir/files/bla/file3.txt", $entries[1]->getLink() );
  112. }
  113. */
  114. // FIXME
  115. // Move method to the archiveTest.
  116. /*
  117. public function testRemovePrefix()
  118. {
  119. $dir = $this->getTempDir();
  120. $total = $dir . "/lisa/ekdahl/";
  121. $without = ezcArchive::removePrefix( $total, $dir );
  122. $this->assertEquals( "lisa/ekdahl/", $without );
  123. }
  124. */
  125. public function testOpenArchive()
  126. {
  127. $entry = $this->archive->current();
  128. $this->assertEquals( "file1.txt", $entry->getPath() );
  129. }
  130. public function testEmptyArchive()
  131. {
  132. $file = $this->getTempDir() . "/file_does_not_exist.tar";
  133. $blockFile = new ezcArchiveBlockFile( $file, true );
  134. $archive = new ezcArchiveV7Tar( $blockFile );
  135. $this->assertFalse( $archive->current(), "Archive should be empty, so no file info available" );
  136. $this->assertFalse( $archive->valid(), "Archive should be empty, so no file info available" );
  137. $this->assertFalse( $archive->next(), "Archive should be empty, so no file info available" );
  138. $this->assertFalse( $archive->next(), "Archive should be empty, so no file info available" );
  139. unset( $blockFile );
  140. unset( $archive );
  141. }
  142. public function testIteratorOperations()
  143. {
  144. $entry = $this->archive->current();
  145. $entry = $this->archive->current();
  146. $this->assertEquals( "file1.txt", $entry->getPath() );
  147. $this->assertTrue( $this->archive->valid(), "Expected a valid archive position." );
  148. $this->archive->rewind();
  149. $entry = $this->archive->current();
  150. $this->assertEquals( "file1.txt", $entry->getPath() );
  151. $this->assertEquals( 0, $this->archive->key() );
  152. $this->assertTrue( $this->archive->valid(), "Expected a valid archive position." );
  153. $this->assertTrue( $this->archive->next() !== false );
  154. $entry = $this->archive->current();
  155. $this->assertEquals( "file2.txt", $entry->getPath() );
  156. $this->assertEquals( 1, $this->archive->key() );
  157. $this->assertTrue( $this->archive->valid(), "Expected a valid archive position." );
  158. $this->assertFalse( $this->archive->next() );
  159. $this->assertFalse( $this->archive->current() );
  160. $this->assertFalse( $this->archive->valid() );
  161. $this->assertFalse( $this->archive->key() );
  162. $this->assertFalse( $this->archive->next() );
  163. $this->assertFalse( $this->archive->next() );
  164. }
  165. public function testForEaching()
  166. {
  167. for ( $i = 0; $i < 2; $i++ )
  168. {
  169. $loopNumber = 0;
  170. foreach ( $this->archive as $entryNumber => $entry )
  171. {
  172. if ( $loopNumber == 0 )
  173. {
  174. $this->assertEquals( "file1.txt", $entry->getPath() );
  175. $this->assertEquals( 0, $entryNumber );
  176. }
  177. else if ( $loopNumber == 1 )
  178. {
  179. $this->assertEquals( "file2.txt", $entry->getPath() );
  180. $this->assertEquals( 1, $entryNumber );
  181. }
  182. else
  183. {
  184. $this->fail( "Didn't expect another entry in the archive" );
  185. }
  186. $loopNumber++;
  187. }
  188. }
  189. }
  190. public function testExtractCurrent()
  191. {
  192. $targetDir = $this->getTempDir() . "/";
  193. $this->archive->extractCurrent( $targetDir );
  194. $file1 = $this->getTempDir() . "/file1.txt";
  195. $this->assertEquals( "Hello world.\nThe first file.\n", file_get_contents( $file1 ) );
  196. // Remove the file, and extract again.
  197. unlink( $file1 );
  198. // Check whether the file is really removed (paranoia?).
  199. $fp = @fopen( $file1, "r" );
  200. if ( $fp )
  201. {
  202. $this->assertFail( "No noo nooo. The file shouldn't be here." );
  203. }
  204. $this->archive->extractCurrent( $targetDir );
  205. $this->assertEquals( "Hello world.\nThe first file.\n", file_get_contents( $file1 ) );
  206. // Move on.
  207. $entry = $this->archive->next();
  208. $this->assertTrue( $this->archive->valid(), "Second file is expected here." );
  209. $this->archive->extractCurrent( $targetDir );
  210. $file2 = $this->getTempDir() . "/file2.txt";
  211. $this->assertEquals( "Hello world.\nThe second file.\n", file_get_contents( $file2 ) );
  212. $this->assertFalse( $this->archive->next(), "No more files in the archive" );
  213. }
  214. public function testExtractCurrentOverwriteFile()
  215. {
  216. // Normally it will overwrite the file, if possible.
  217. $targetDir = $this->getTempDir() . "/";
  218. $this->archive->extractCurrent( $targetDir );
  219. $file1 = $this->getTempDir() . "/file1.txt";
  220. $this->assertEquals( "Hello world.\nThe first file.\n", file_get_contents( $file1 ) );
  221. $fp = @fopen( $file1, "w" );
  222. fwrite( $fp, "Garbage" );
  223. fclose( $fp );
  224. $this->assertEquals( "Garbage", file_get_contents( $file1 ) );
  225. $this->archive->extractCurrent( $targetDir );
  226. $this->assertEquals( "Hello world.\nThe first file.\n", file_get_contents( $file1 ) );
  227. }
  228. public function testExtractCurrentKeepExistingFile()
  229. {
  230. // Normally it will overwrite the file, if possible.
  231. $targetDir = $this->getTempDir() . "/";
  232. $this->archive->extractCurrent( $targetDir, true );
  233. $file1 = $this->getTempDir() . "/file1.txt";
  234. $this->assertEquals( "Hello world.\nThe first file.\n", file_get_contents( $file1 ) );
  235. $fp = @fopen( $file1, "w" );
  236. fwrite( $fp, "Garbage" );
  237. fclose( $fp );
  238. $this->assertEquals( "Garbage", file_get_contents( $file1 ) );
  239. $this->archive->extractCurrent( $targetDir, true );
  240. $this->assertEquals( "Garbage", file_get_contents( $file1 ) );
  241. }
  242. public function testExtractComplexArchive()
  243. {
  244. $dir = $this->getTempDir();
  245. mkdir( $dir . "/php" );
  246. mkdir( $dir . "/gnu" );
  247. foreach ( $this->complexArchive as $entry )
  248. {
  249. $this->complexArchive->extractCurrent( $dir ."/php" );
  250. }
  251. exec( "tar -xf " . $this->complexFile . " -C $dir/gnu" );
  252. // make corrections that emulate symlink in Windows
  253. if ( $this->isWindows() )
  254. {
  255. exec( 'attrib -r ' . $dir . '\gnu\files\file3.txt.lnk' );
  256. exec( 'del "' . $dir . '\gnu\files\file3.txt.lnk"' );
  257. exec( 'copy "' . $dir . '\gnu\files\bla\file3.txt" "' . $dir . '\gnu\files\file3.txt"' );
  258. }
  259. $this->compareDirectories( "$dir/gnu", "$dir/php" );
  260. $stat = stat( "$dir/php/files/bla/file3.txt" );
  261. $this->assertEquals( 0644, $stat['mode'] & 07777 );
  262. $this->assertEquals( 1000, $stat['uid'] );
  263. $this->assertEquals( $this->usersGid, $stat['gid'] );
  264. }
  265. public function testExtractComplexArchiveModPerms()
  266. {
  267. $options = new ezcArchiveOptions;
  268. $options->extractCallback = new testExtractCallback;
  269. $this->complexArchive->setOptions( $options );
  270. $dir = $this->getTempDir();
  271. mkdir( $dir . "/php" );
  272. mkdir( $dir . "/gnu" );
  273. foreach ( $this->complexArchive as $entry )
  274. {
  275. $this->complexArchive->extractCurrent( $dir ."/php" );
  276. }
  277. exec( "tar -xf " . $this->complexFile . " -C $dir/gnu" );
  278. // make corrections that emulate symlink in Windows
  279. if ( $this->isWindows() )
  280. {
  281. exec( 'attrib -r ' . $dir . '\gnu\files\file3.txt.lnk' );
  282. exec( 'del "' . $dir . '\gnu\files\file3.txt.lnk"' );
  283. exec( 'copy "' . $dir . '\gnu\files\bla\file3.txt" "' . $dir . '\gnu\files\file3.txt"' );
  284. }
  285. $this->compareDirectories( "$dir/gnu", "$dir/php" );
  286. $options->extractCallback = null;
  287. $stat = stat( "$dir/php/files/bla/file3.txt" );
  288. $this->assertEquals( 0600, $stat['mode'] & 07777 );
  289. $this->assertEquals( 1000, $stat['uid'] );
  290. $this->assertEquals( $this->usersGid, $stat['gid'] );
  291. $stat = stat( "$dir/php/files/bla" );
  292. $this->assertEquals( 0700, $stat['mode'] & 07777 );
  293. $this->assertEquals( 1000, $stat['uid'] );
  294. $this->assertEquals( $this->usersGid, $stat['gid'] );
  295. }
  296. public function testInvalidChecksum()
  297. {
  298. // Correct checksum.
  299. $ustarFile = new ezcArchiveBlockFile( dirname( __FILE__) . "/../data/tar_v7_2_textfiles.tar" );
  300. $tar = new ezcArchiveV7Tar( $ustarFile );
  301. // Incorrect checksum.
  302. try
  303. {
  304. $ustarFile = new ezcArchiveBlockFile( dirname( __FILE__) . "/../data/tar_v7_invalid_checksum.tar" );
  305. $tar = new ezcArchiveV7Tar( $ustarFile );
  306. $tar->current();
  307. $this->fail("Expected the checksum to fail.");
  308. }
  309. catch ( ezcArchiveChecksumException $e )
  310. {
  311. }
  312. unset( $tar );
  313. unset( $ustarFile );
  314. }
  315. public function testSeekPositions()
  316. {
  317. $entry = $this->complexArchive->current();
  318. $this->assertEquals( "files/", $entry->getPath() );
  319. $this->complexArchive->seek( 2 ); // third file in archive.
  320. $entry = $this->complexArchive->current();
  321. $this->assertEquals( "files/bla/bin/", $entry->getPath() );
  322. $this->complexArchive->seek( 0 ); // first file in archive.
  323. $entry = $this->complexArchive->current();
  324. $this->assertEquals( "files/", $entry->getPath() );
  325. $this->complexArchive->seek( 6 );
  326. $entry = $this->complexArchive->current();
  327. $this->assertEquals( "files/file2.txt", $entry->getPath() );
  328. $this->complexArchive->seek( 8 );
  329. $entry = $this->complexArchive->current();
  330. $this->assertEquals( "files/file4.txt", $entry->getPath() );
  331. $this->complexArchive->seek( 9 );
  332. $this->assertFalse( $this->complexArchive->current() );
  333. $this->complexArchive->seek( 0 );
  334. $entry = $this->complexArchive->current();
  335. $this->assertEquals( "files/", $entry->getPath() );
  336. $this->complexArchive->seek( -1 );
  337. $this->assertFalse( $this->complexArchive->current() );
  338. }
  339. public function testSeekEndOfFile()
  340. {
  341. $this->complexArchive->seek( 0, SEEK_END ); // nineth and last file.
  342. $entry = $this->complexArchive->current();
  343. $this->assertEquals( "files/file4.txt", $entry->getPath() );
  344. $this->complexArchive->seek( -2, SEEK_END ); // seventh file
  345. $entry = $this->complexArchive->current();
  346. $this->assertEquals( "files/file2.txt", $entry->getPath() );
  347. $this->complexArchive->seek( -8, SEEK_END ); // first file
  348. $entry = $this->complexArchive->current();
  349. $this->assertEquals( "files/", $entry->getPath() );
  350. $this->complexArchive->seek( 1, SEEK_END ); // invalid
  351. $this->assertFalse( $this->complexArchive->current() );
  352. $this->complexArchive->seek( 0, SEEK_END ); // nineth and last file.
  353. $entry = $this->complexArchive->current();
  354. $this->assertEquals( "files/file4.txt", $entry->getPath() );
  355. $this->complexArchive->seek( -9, SEEK_END ); // invalid
  356. $this->assertFalse( $this->complexArchive->current() );
  357. }
  358. public function testSeekCur()
  359. {
  360. $entry = $this->complexArchive->current();
  361. $this->assertEquals( "files/", $entry->getPath() );
  362. $this->complexArchive->seek( 2, SEEK_CUR ); // third file in archive.
  363. $entry = $this->complexArchive->current();
  364. $this->assertEquals( "files/bla/bin/", $entry->getPath() );
  365. $this->complexArchive->seek( 0, SEEK_CUR ); // Third file in archive.
  366. $entry = $this->complexArchive->current();
  367. $this->assertEquals( "files/bla/bin/", $entry->getPath() );
  368. $this->complexArchive->seek( 4, SEEK_CUR ); // Seventh file in the archive.
  369. $entry = $this->complexArchive->current();
  370. $this->assertEquals( "files/file2.txt", $entry->getPath() );
  371. $this->complexArchive->seek( 2, SEEK_CUR ); // nineth and last.
  372. $entry = $this->complexArchive->current();
  373. $this->assertEquals( "files/file4.txt", $entry->getPath() );
  374. $this->complexArchive->seek( 1, SEEK_CUR );
  375. $this->assertFalse( $this->complexArchive->current() );
  376. $this->complexArchive->seek( 2 );
  377. $entry = $this->complexArchive->current();
  378. $this->assertEquals( "files/bla/bin/", $entry->getPath() );
  379. $this->complexArchive->seek( -2, SEEK_CUR ); // First file.
  380. $entry = $this->complexArchive->current();
  381. $this->assertEquals( "files/", $entry->getPath() );
  382. $this->complexArchive->seek( -1, SEEK_CUR ); // And invalid again.
  383. $this->assertFalse( $this->complexArchive->current() );
  384. }
  385. public function testExtractOneDirectory()
  386. {
  387. // The subdirectory should be created automatically.
  388. $this->complexArchive->seek( 1 );
  389. $targetDir = $this->getTempDir() ;
  390. $this->complexArchive->extractCurrent( $targetDir );
  391. $this->assertTrue( file_exists( $targetDir . "/files/bla/" ), "Cannot find the extracted directory." );
  392. }
  393. public function testExtractOneFile()
  394. {
  395. // The directory should be created automatically.
  396. $this->complexArchive->seek( 4 ); // 5th file.
  397. $targetDir = $this->getTempDir();
  398. $this->complexArchive->extractCurrent( $targetDir );
  399. $this->assertTrue( file_exists( $targetDir . "/files/bla/file3.txt" ), "Cannot find the extracted file." );
  400. $this->assertEquals( "Hello world.\nThe third file.\n", file_get_contents( $targetDir . "/files/bla/file3.txt" ) );
  401. }
  402. public function testExtractOneSymbolicLink()
  403. {
  404. // this test a bit different in Windows as symlinks
  405. // simulated by copying
  406. if ( $this->isWindows() )
  407. {
  408. // The directory should be created automatically.
  409. // There is both link and link target extracted
  410. // and there are both the same file.
  411. $targetDir = $this->getTempDir();
  412. // extract target
  413. $this->complexArchive->seek( 4 );
  414. $this->complexArchive->extractCurrent( $targetDir );
  415. // "extract" link i.e. copy target
  416. $this->complexArchive->seek( 7 );
  417. $this->complexArchive->extractCurrent( $targetDir );
  418. }
  419. else
  420. {
  421. // The directory should be created automatically.
  422. // The link points to an non existing file.
  423. $this->complexArchive->seek( 7 );
  424. $targetDir = $this->getTempDir();
  425. $this->complexArchive->extractCurrent( $targetDir );
  426. }
  427. $this->assertTrue( is_array ( lstat( $targetDir . "/files/file3.txt" ) ) );
  428. }
  429. public function testExtractOneHardLinkException()
  430. {
  431. // Should throw an exception.
  432. $this->complexArchive->seek( 8 );
  433. $targetDir = $this->getTempDir();
  434. try
  435. {
  436. $this->complexArchive->extractCurrent( $targetDir );
  437. $this->fail( "Expected an exception" );
  438. }
  439. catch ( ezcBaseFileNotFoundException $e )
  440. {
  441. }
  442. }
  443. public function testExtractOneHardLink()
  444. {
  445. $this->complexArchive->seek( 4 );
  446. $targetDir = $this->getTempDir();
  447. $this->complexArchive->extractCurrent( $targetDir );
  448. $this->complexArchive->seek( 8 );
  449. $this->complexArchive->extractCurrent( $targetDir );
  450. $this->assertTrue( file_exists( $targetDir . "/files/bla/file3.txt" ) );
  451. $this->assertTrue( file_exists( $targetDir . "/files/file4.txt" ) );
  452. }
  453. public function testExtractComplexArchiveOverwrite()
  454. {
  455. $dir = $this->getTempDir();
  456. mkdir( $dir . "/php" );
  457. mkdir( $dir . "/gnu" );
  458. // Extract once
  459. foreach ( $this->complexArchive as $entry )
  460. {
  461. $this->complexArchive->extractCurrent( $dir ."/php" );
  462. }
  463. // Extract with gnu tar.
  464. exec( "tar -xf " . $this->complexFile . " -C $dir/gnu" );
  465. // Truncate file1.txt
  466. $fp = fopen( $dir ."/php/files/file1.txt", "r+w" );
  467. ftruncate( $fp, 0 );
  468. fclose( $fp );
  469. // Change link.
  470. unlink( $dir . "/php/files/file3.txt" );
  471. if ( $this->isWindows() )
  472. {
  473. copy( $dir . "/php/files/file4.txt", $dir . "/php/files/file3.txt" );
  474. // make corrections of gnu tar output
  475. // replace .lnk file with copy of target file
  476. exec( 'attrib -r ' . $dir . '\gnu\files\file3.txt.lnk' );
  477. exec( 'del "' . $dir . '\gnu\files\file3.txt.lnk"' );
  478. exec( 'copy "' . $dir . '\gnu\files\bla\file3.txt" "' . $dir . '\gnu\files\file3.txt"' );
  479. }
  480. else
  481. {
  482. symlink( "file4.txt", $dir . "/php/files/file3.txt" );
  483. }
  484. // Truncate file4.txt (and also files/bla/file3.txt.
  485. $fp = fopen( $dir . "/php/files/file4.txt", "r+w" );
  486. ftruncate( $fp, 0 );
  487. fclose( $fp );
  488. foreach ( $this->complexArchive as $entry )
  489. {
  490. $this->complexArchive->extractCurrent( $dir . "/php" );
  491. }
  492. $this->compareDirectories( "$dir/gnu", "$dir/php" );
  493. }
  494. public function testExtractComplexArchiveKeepExisting()
  495. {
  496. $dir = $this->getTempDir();
  497. mkdir( $dir . "/php" );
  498. mkdir( $dir . "/gnu" );
  499. // Extract once
  500. foreach ( $this->complexArchive as $entry )
  501. {
  502. $this->complexArchive->extractCurrent( $dir ."/php" );
  503. }
  504. // Extract with gnu tar.
  505. exec( "tar -xf " . $this->complexFile . " -C $dir/gnu" );
  506. // Truncate file1.txt
  507. $fp = fopen( $dir . "/php/files/file1.txt", "r+w" );
  508. ftruncate( $fp, 0 );
  509. fclose( $fp );
  510. // Change link.
  511. unlink( $dir . "/php/files/file3.txt" );
  512. if ( $this->isWindows() )
  513. {
  514. copy( $dir . "/php/files/file4.txt", $dir . "/php/files/file3.txt" );
  515. // make corrections of gnu tar output
  516. // replace .lnk file with copy of target file
  517. exec( 'attrib -r ' . $dir . '\gnu\files\file3.txt.lnk' );
  518. exec( 'del "' . $dir . '\gnu\files\file3.txt.lnk"' );
  519. exec( 'copy "' . $dir . '\gnu\files\bla\file3.txt" "' . $dir . '\gnu\files\file3.txt"' );
  520. }
  521. else
  522. {
  523. symlink( "file4.txt", $dir."/php/files/file3.txt");
  524. }
  525. // Truncate file4.txt (and also files/bla/file3.txt.
  526. $fp = fopen( $dir . "/php/files/file4.txt", "r+w" );
  527. ftruncate( $fp, 0 );
  528. fclose( $fp );
  529. foreach ( $this->complexArchive as $entry )
  530. {
  531. $this->complexArchive->extractCurrent( $dir . "/php", true );
  532. }
  533. $this->assertEquals( "", file_get_contents( $dir . "/php/files/file1.txt" ) );
  534. $this->assertEquals( "", file_get_contents( $dir . "/php/files/file3.txt" ) );
  535. $this->assertEquals( "", file_get_contents( $dir . "/php/files/file4.txt" ) );
  536. $this->assertEquals( "", file_get_contents( $dir . "/php/files/bla/file3.txt" ) );
  537. }
  538. // Write methods.
  539. public function testTruncate()
  540. {
  541. if ( !$this->canWrite )
  542. {
  543. try
  544. {
  545. $this->complexArchive->truncate();
  546. $this->fail( "Cannot write exception expected" );
  547. }
  548. catch ( ezcBaseFilePermissionException $e )
  549. {
  550. // Okay, some exception thrown.
  551. }
  552. return;
  553. }
  554. $this->complexArchive->truncate();
  555. $this->assertFalse( $this->complexArchive->valid(), "Truncated archive shouldn't contain any elements" );
  556. $this->complexArchive->seek( 0 );
  557. $this->assertFalse( $this->complexArchive->valid(), "Truncated archive shouldn't contain any elements" );
  558. $this->complexArchive->seek( 2 );
  559. $this->assertFalse( $this->complexArchive->valid(), "Truncated archive shouldn't contain any elements" );
  560. }
  561. public function testTruncatePart()
  562. {
  563. if ( !$this->canWrite )
  564. {
  565. return;
  566. }
  567. $this->complexArchive->truncate( 4 );
  568. // Without rewind.. should work since we truncated after our position.
  569. $entry = $this->complexArchive->current();
  570. $this->assertEquals( "files/", $entry->getPath() );
  571. $entry = $this->complexArchive->next();
  572. $this->assertEquals( "files/bla/", $entry->getPath() );
  573. $entry = $this->complexArchive->next();
  574. $this->assertEquals( "files/bla/bin/", $entry->getPath() );
  575. $entry = $this->complexArchive->next();
  576. $this->assertEquals( "files/bla/bin/true", $entry->getPath() );
  577. $this->assertFalse( $this->complexArchive->next() );
  578. $this->complexArchive->seek( 6 );
  579. $this->assertFalse( $this->complexArchive->valid(), "Truncated archive shouldn't contain any elements" );
  580. }
  581. public function testTruncateLastFile()
  582. {
  583. if ( !$this->canWrite )
  584. {
  585. return;
  586. }
  587. // Truncate after the last file, but don't write the null blocks.
  588. $this->archive->truncate( 2, false );
  589. // File should have 4 blocks.
  590. $blockFile = new ezcArchiveBlockFile( $this->file );
  591. $i = 1;
  592. while ( $blockFile->next() )
  593. {
  594. $i++;
  595. }
  596. $this->assertEquals( 4, $i );
  597. unset( $blockFile );
  598. }
  599. public function testTruncateAmountOfBlocks()
  600. {
  601. if ( !$this->canWrite )
  602. {
  603. return;
  604. }
  605. $blockFile = new ezcArchiveBlockFile( $this->file );
  606. $i = 1;
  607. while ( $blockFile->next() ) $i++;
  608. $this->assertEquals( 20, $i, "Expected 20 blocks in the file." );
  609. $blockFile->seek( 2 );
  610. $this->assertFalse( $blockFile->isNullBlock(), "Didn't expect a null block." );
  611. $blockFile->seek( 3 );
  612. $this->assertFalse( $blockFile->isNullBlock(), "Didn't expect a null block." );
  613. $blockFile->seek( 4 );
  614. $this->assertTrue( $blockFile->isNullBlock(), "Expected a null block." );
  615. // Give the block File to the archive.
  616. $archive = new ezcArchiveV7Tar( $blockFile );
  617. $entry = $archive->current();
  618. // A non rewinded block file, does that work?
  619. $this->assertEquals( "file1.txt", $entry->getPath() );
  620. $archive->truncate( 1 ); // keep the first file.
  621. $archive->close();
  622. $blockFile = new ezcArchiveBlockFile( $this->file );
  623. // Should be 20 blocks..
  624. $i = 1;
  625. while ( $blockFile->next() )
  626. {
  627. $i++;
  628. }
  629. $this->assertEquals( 20, $i, "Expected 20 blocks in the file." );
  630. $blockFile->seek( 0 );
  631. $this->assertFalse( $blockFile->isNullBlock(), "Didn't expect a null block." );
  632. $blockFile->seek( 1 );
  633. $this->assertFalse( $blockFile->isNullBlock(), "Didn't expect a null block." );
  634. $blockFile->seek( 2 );
  635. $this->assertTrue( $blockFile->isNullBlock(), "Expected a null block." );
  636. unset( $blockFile );
  637. }
  638. public function testAppendToCurrentNonExistingFile()
  639. {
  640. if ( !$this->canWrite )
  641. {
  642. try
  643. {
  644. $this->complexArchive->truncate();
  645. $this->fail( "Cannot write exception expected" );
  646. }
  647. catch ( ezcBaseFilePermissionException $e )
  648. {
  649. // Okay, some exception thrown.
  650. }
  651. return;
  652. }
  653. try
  654. {
  655. $this->archive->appendToCurrent( "file_does_not_exist", "/" );
  656. $this->fail( "Expected a 'file does not exist' exception." );
  657. }
  658. catch ( ezcBaseFileNotFoundException $e )
  659. {
  660. }
  661. }
  662. public function testAppendToCurrentOnEmptyArchive()
  663. {
  664. if ( !$this->canWrite )
  665. {
  666. return;
  667. }
  668. $this->assertNotEquals( "\0\0a\0", "\0a\0\0", "Something wrong with the unit test system." );
  669. $this->archive->extractCurrent( $this->getTempDir() );
  670. $dir = $this->getTempDir();
  671. $emptyTar = "$dir/empty_archive.tar";
  672. $bf = new ezcArchiveBlockFile( $emptyTar, true );
  673. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  674. $this->assertFalse( $archive->valid() );
  675. $archive->appendToCurrent( "$dir/file1.txt", $dir );
  676. $archive->close();
  677. $this->assertEquals( 10240, strlen( file_get_contents( "$dir/empty_archive.tar" ) ), "Expected 20 blocks of 512 bytes" );
  678. // Do the same with gnu tar.
  679. exec( "tar -cf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir file1.txt" );
  680. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( "$dir/empty_archive.tar" ) );
  681. unset( $archive );
  682. unset( $bf );
  683. }
  684. public function testAppendToCurrentAtEndOfArchive()
  685. {
  686. if ( !$this->canWrite )
  687. {
  688. return;
  689. }
  690. $dir = $this->getTempDir();
  691. $bf = new ezcArchiveBlockFile( $this->file );
  692. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  693. $archive->extractCurrent( $dir );
  694. copy( $this->file, $dir."/gnutar.tar" );
  695. $archive->seek( 0, SEEK_END ); // File number two.
  696. $archive->appendToCurrent( "$dir/file1.txt", $dir );
  697. $archive->close();
  698. // Do the same with gnu tar.
  699. exec( "tar -rf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir file1.txt" );
  700. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( $this->file ) );
  701. unset( $archive );
  702. unset( $bf );
  703. }
  704. public function testAppendToCurrentInArchive()
  705. {
  706. if ( !$this->canWrite )
  707. {
  708. return;
  709. }
  710. $dir = $this->getTempDir();
  711. $bf = new ezcArchiveBlockFile( $this->file );
  712. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  713. $archive->extractCurrent( $dir );
  714. copy( $this->file, $dir."/gnutar.tar" );
  715. $archive->seek( 0 ); // After file number one.
  716. $archive->appendToCurrent( "$dir/file1.txt", $dir );
  717. $archive->close();
  718. // Do the same with gnu tar.
  719. exec( "tar --delete -f $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir file2.txt" );
  720. exec( "tar -rf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir file1.txt" );
  721. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( $this->file ) );
  722. unset( $bf );
  723. }
  724. public function testAppendToCurrentMultipleTimes()
  725. {
  726. if ( !$this->canWrite )
  727. {
  728. return;
  729. }
  730. // Extract the archive.
  731. $dir = $this->getTempDir();
  732. $bf = new ezcArchiveBlockFile( $this->file );
  733. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  734. $archive->extractCurrent( $dir );
  735. $archive->next();
  736. $archive->extractCurrent( $dir );
  737. // Clear the archive.
  738. $archive->truncate();
  739. // Append the files again.
  740. $archive->appendToCurrent( $dir . "/file1.txt", $dir );
  741. // $this->assertTrue( $this->archive->next() !== false );
  742. $archive->appendToCurrent( $dir . "/file2.txt", $dir );
  743. $archive->close();
  744. // Do the same with gnu tar.
  745. exec( "tar -cf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir file1.txt file2.txt" );
  746. // Compare
  747. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents($this->file ) );
  748. $bf = new ezcArchiveBlockFile( $this->file );
  749. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  750. // Append another file.
  751. $archive->append( $dir . "/file1.txt", $dir );
  752. $archive->close();
  753. exec( "tar -rf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir file1.txt" );
  754. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( $this->file ) );
  755. }
  756. public function testAppendToCurrentDirectory()
  757. {
  758. if ( !$this->canWrite )
  759. {
  760. return;
  761. }
  762. $dir = $this->getTempDir();
  763. $this->complexArchive->extractCurrent( $dir );
  764. $emptyTar = "$dir/empty_archive.tar";
  765. $bf = new ezcArchiveBlockFile( $emptyTar, true );
  766. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  767. $archive->appendToCurrent( $dir . "/files", $dir );
  768. $archive->close();
  769. // Do the same with gnu tar.
  770. exec( "tar -cf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir files" );
  771. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( $emptyTar ) );
  772. unset( $bf );
  773. }
  774. public function testAppendToCurrentSymbolicLink()
  775. {
  776. if ( !$this->canWrite )
  777. {
  778. return;
  779. }
  780. if ( $this->isWindows() )
  781. {
  782. return; // there is no sense to test it in Windows as its the same as appending file.
  783. }
  784. $dir = $this->getTempDir();
  785. $this->complexArchive->seek( 7 );
  786. $this->complexArchive->extractCurrent( $dir );
  787. $emptyTar = "$dir/empty_archive.tar";
  788. $bf = new ezcArchiveBlockFile( $emptyTar, true );
  789. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  790. $archive->appendToCurrent( $dir . "/files/file3.txt", $dir );
  791. $archive->close();
  792. // Do the same with gnu tar.
  793. exec( "tar -cf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir files/file3.txt" );
  794. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( $emptyTar ) );
  795. unset( $bf );
  796. }
  797. public function testAppendToCurrentHardLink()
  798. {
  799. if ( !$this->canWrite )
  800. {
  801. return;
  802. }
  803. $dir = $this->getTempDir();
  804. $this->complexArchive->seek( 4 ); // File.
  805. $this->complexArchive->extractCurrent( $dir );
  806. $this->complexArchive->seek( 8 ); // Hardlink
  807. $this->complexArchive->extractCurrent( $dir );
  808. $emptyTar = "$dir/empty_archive.tar";
  809. $bf = new ezcArchiveBlockFile( $emptyTar, true );
  810. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  811. $archive->appendToCurrent( $dir . "/files/file4.txt", $dir );
  812. $archive->writeEnd();
  813. // Do the same with gnu tar.
  814. exec( "tar -cf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir files/file4.txt" );
  815. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( $emptyTar ) );
  816. // File was appended as a normal file.
  817. $archive->rewind();
  818. $archive->appendToCurrent( $dir . "/files/bla/file3.txt", $dir );
  819. $archive->close();
  820. // Do the same with gnu tar.
  821. exec( "tar -rf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir files/bla/file3.txt" );
  822. // Appended as two separated files.
  823. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( $emptyTar ) );
  824. unset( $bf );
  825. }
  826. public function testAppendToCurrentHardLinkedFiles()
  827. {
  828. if ( !$this->canWrite )
  829. {
  830. return;
  831. }
  832. $dir = $this->getTempDir();
  833. $this->complexArchive->seek( 4 ); // File.
  834. $this->complexArchive->extractCurrent( $dir );
  835. $this->complexArchive->seek( 8 ); // Hardlink
  836. $this->complexArchive->extractCurrent( $dir );
  837. exec( "tar -cf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $dir files/bla/file3.txt files/file4.txt" );
  838. $emptyTar = "$dir/empty_archive.tar";
  839. $bf = new ezcArchiveBlockFile( $emptyTar, true );
  840. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  841. $archive->appendToCurrent( array ( "$dir/files/bla/file3.txt", "$dir/files/file4.txt" ), $dir );
  842. $archive->close();
  843. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( $emptyTar ) );
  844. unset( $bf );
  845. }
  846. public function testAppendArchiveAtOnce()
  847. {
  848. if ( !$this->canWrite )
  849. {
  850. try
  851. {
  852. $this->complexArchive->truncate();
  853. $this->fail( "Cannot write exception expected" );
  854. }
  855. catch ( ezcBaseFilePermissionException $e )
  856. {
  857. // Okay, some exception thrown.
  858. }
  859. return;
  860. }
  861. $dir = $this->getTempDir();
  862. $src = $dir . "/src";
  863. mkdir ( $src );
  864. $files = array();
  865. do
  866. {
  867. $this->complexArchive->extractCurrent( $src );
  868. $files[] = $src . '/'. $this->complexArchive->current()->getPath();
  869. } while ( $this->complexArchive->next() );
  870. $mytar = "$dir/my_archive.tar";
  871. $bf = new ezcArchiveBlockFile( $mytar, true );
  872. $archive = ezcArchive::getTarInstance( $bf, $this->tarMimeFormat );
  873. $archive->appendToCurrent( $files, $src );
  874. $archive->close();
  875. exec( "tar -cf $dir/gnutar.tar --format=" . $this->tarFormat . " -C $src files" );
  876. $this->assertEquals( file_get_contents( "$dir/gnutar.tar" ), file_get_contents( $mytar ) );
  877. unset( $archive );
  878. unset( $bf );
  879. }
  880. /**
  881. * Test for issue ZETACOMP-8: Double extraction causes empty file
  882. *
  883. * The failure happens only with some tarballs. The easiest way to create
  884. * such failing one is to remove some of the nul characters which are
  885. * appended to the file's content to continue the block.
  886. */
  887. public function testDoubleExtraction()
  888. {
  889. $archive = ezcArchive::open( dirname( dirname( __FILE__ ) ) . "/data/tar_v7_truncated_block.tar" );
  890. $dir = $this->getTempDir();
  891. foreach ( $archive as $entry )
  892. {
  893. if ( $entry->getPath() === "file1" )
  894. {
  895. $archive->extractCurrent( $dir );
  896. // break intentionally omitted.
  897. }
  898. }
  899. $archive->extract( $dir );
  900. $this->assertEquals( 13, filesize( "$dir/file1" ) );
  901. }
  902. public static function suite()
  903. {
  904. return new PHPUnit_Framework_TestSuite( __CLASS__ );
  905. }
  906. }
  907. ?>