1 7 22 23 package de.schlichtherle.io; 24 25 import de.schlichtherle.io.archive.spi.ArchiveDriver; 26 import java.io.ByteArrayInputStream ; 27 import java.io.ByteArrayOutputStream ; 28 import java.io.IOException ; 29 import java.io.InputStream ; 30 import java.io.ObjectInputStream ; 31 import java.io.ObjectOutputStream ; 32 import java.io.OutputStream ; 33 import java.io.FileNotFoundException ; 34 import java.io.FilenameFilter ; 35 import java.io.FileFilter ; 36 import java.io.PrintStream ; 37 import java.io.RandomAccessFile ; 38 import java.lang.ref.Reference ; 39 import java.lang.ref.WeakReference ; 40 import java.net.URI ; 41 import java.util.Arrays ; 42 import java.util.HashSet ; 43 import java.util.Random ; 44 import java.util.Set ; 45 import java.util.logging.Logger ; 46 import java.util.regex.Matcher ; 47 import java.util.regex.Pattern ; 48 49 import junit.framework.*; 50 51 54 public abstract class FileTestBase extends TestCase { 55 56 private static final Logger logger = Logger.getLogger( 57 FileTestBase.class.getName()); 58 59 private static final java.io.File _tempDir = new java.io.File ( 60 System.getProperty("java.io.tmpdir")); 61 62 private static final Matcher _tempMatcher 63 = Pattern.compile(UpdatingArchiveController.TEMP_FILE_PREFIX 64 + ".*\\" + UpdatingArchiveController.TEMP_FILE_SUFFIX).matcher(""); 65 66 private static final Set totalTemps = new HashSet (); 67 68 private static final java.io.File _baseDir = _tempDir; 69 70 71 private static final byte[] _data = new byte[100 * 1024]; static { 73 boolean ea = false; 74 assert ea = true; logger.config("Java assertions " + (ea ? "enabled." : "disabled!")); 76 if (!ea) 77 logger.info("Please enable assertions for additional white box testing."); 78 79 new Random ().nextBytes(_data); 80 logger.config("Created " + _data.length + " bytes of random data."); 81 logger.config("Temp dir for TrueZIP API: " + _tempDir.getPath()); 82 logger.config("Default temp dir for unit tests: " + _baseDir.getPath()); 83 logger.config("Free memory: " + mb(Runtime.getRuntime().freeMemory())); 84 logger.config("Total memory: " + mb(Runtime.getRuntime().totalMemory())); 85 logger.config("Max memory: " + mb(Runtime.getRuntime().maxMemory())); 86 } 87 88 private static final String mb(long value) { 89 return ((value - 1 + 1024 * 1024) / (1024 * 1024)) + " MB"; } 91 92 protected byte[] data; 93 94 protected java.io.File baseDir; 95 96 protected String prefix; 97 98 102 protected String suffix; 103 104 105 protected File archive; 106 107 public FileTestBase(String testName) { 108 super(testName); 109 110 File.setDefaultArchiveDetector(ArchiveDetector.DEFAULT); 111 } 112 113 119 protected void setUp() throws Exception { 120 if (data == null) 121 data = _data; if (baseDir == null) 123 baseDir = _baseDir; 124 if (prefix == null) 125 prefix = "tzp-test"; 126 if (suffix == null) 127 suffix = ".zip"; 128 if (archive == null) { 129 archive = new File(createTempFile(prefix, suffix)); 130 assertTrue(archive.delete()); 131 } 132 133 File.setLenient(true); } 135 136 protected void tearDown() throws Exception { 137 data = null; 138 baseDir = null; 139 prefix = null; 140 suffix = null; 141 142 final boolean deleted = archive.delete(); 143 if (!deleted && archive.exists()) { 144 logger.warning(archive + " (could not delete)"); 145 } 147 archive = null; 148 149 try { 154 File.umount(); 155 } catch (ArchiveException ignored) { 156 } 161 162 final String [] temps = _tempDir.list(new FilenameFilter () { 163 public boolean accept(java.io.File dir, String name) { 164 _tempMatcher.reset(name); 165 return _tempMatcher.matches(); 166 } 167 }); 168 assert temps != null; 169 for (int i = 0; i < temps.length; i++) { 170 if (totalTemps.add(temps[i])) { 171 logger.warning("Bug in TrueZIP API: Temp file found: " + temps[i]); 174 } 175 } 176 177 } 178 179 public void testNormalize() { 180 logger.fine("testNormalize"); 181 182 final java.io.File empty = new java.io.File (""); 183 assertEquals(".", File.normalize(empty).getPath()); 184 185 testNormalize("a", "./a"); 186 187 testNormalize(".", "."); 188 testNormalize("..", "./.."); 189 testNormalize("../..", "./../.."); 190 testNormalize("../../..", "./../../.."); 191 testNormalize("../../..", "./.././.././.."); 192 testNormalize("../../..", "././../././../././.."); 193 testNormalize("../../..", "./././.././././.././././.."); 194 195 testNormalize("..", ".."); 196 testNormalize("../..", "../.."); 197 testNormalize("../../..", "../../.."); 198 testNormalize("../../../..", "../../../.."); 199 testNormalize("../../../..", "../.././.././.."); 200 testNormalize("../../../..", ".././../././../././.."); 201 testNormalize("../../../..", "../././.././././.././././.."); 202 203 testNormalize("a", "a"); 204 testNormalize(".", "a/.."); 205 testNormalize("..", "a/../.."); 206 testNormalize("../..", "a/../../.."); 207 testNormalize("../..", "a/./.././.././.."); 208 testNormalize("../..", "a/././../././../././.."); 209 testNormalize("../..", "a/./././.././././.././././.."); 210 211 testNormalize("a/b", "a/b"); 212 testNormalize("a", "a/b/.."); 213 testNormalize(".", "a/b/../.."); 214 testNormalize("..", "a/b/../../.."); 215 testNormalize("..", "a/b/./.././.././.."); 216 testNormalize("..", "a/b/././../././../././.."); 217 testNormalize("..", "a/b/./././.././././.././././.."); 218 219 testNormalize("a/b/c", "a/b/c"); 220 testNormalize("a/b", "a/b/c/.."); 221 testNormalize("a", "a/b/c/../.."); 222 testNormalize(".", "a/b/c/../../.."); 223 testNormalize(".", "a/b/c/./.././.././.."); 224 testNormalize(".", "a/b/c/././../././../././.."); 225 testNormalize(".", "a/b/c/./././.././././.././././.."); 226 227 testNormalize("a/b/c/d", "a/b/c/d"); 228 testNormalize("a/b/c", "a/b/c/d/.."); 229 testNormalize("a/b", "a/b/c/d/../.."); 230 testNormalize("a", "a/b/c/d/../../.."); 231 testNormalize("a", "a/b/c/d/./.././.././.."); 232 testNormalize("a", "a/b/c/d/././../././../././.."); 233 testNormalize("a", "a/b/c/d/./././.././././.././././.."); 234 } 235 236 void testNormalize(String result, final String path) { 237 result = result.replace('/', File.separatorChar); 238 java.io.File file = new java.io.File (path); 239 assertEquals(result, File.normalize(file).getPath()); 240 file = new java.io.File (path + '/'); 241 assertEquals(result, File.normalize(file).getPath()); 242 file = new java.io.File (path + File.separator); 243 assertEquals(result, File.normalize(file).getPath()); 244 file = new java.io.File (path + File.separator + "."); 245 assertEquals(result, File.normalize(file).getPath()); 246 file = new java.io.File (path + File.separator + "." + File.separator + "."); 247 assertEquals(result, File.normalize(file).getPath()); 248 file = new java.io.File (path + File.separator + "." + File.separator + "." + File.separator + "."); 249 assertEquals(result, File.normalize(file).getPath()); 250 } 251 252 public void testNormalizedAbsoluteFile() throws IOException { 253 logger.fine("testNormalizedAbsoluteFile"); 254 255 testNormalizedAbsoluteFile("", ""); 256 testNormalizedAbsoluteFile(".", "."); 257 testNormalizedAbsoluteFile("..", ".."); 258 259 testNormalizedAbsoluteFile("a", "a"); 260 testNormalizedAbsoluteFile("a", "a/."); 261 testNormalizedAbsoluteFile(".", "a/.."); 262 testNormalizedAbsoluteFile("b", "a/../b"); 263 testNormalizedAbsoluteFile("b", "a/../b/."); 264 testNormalizedAbsoluteFile(".", "a/../b/.."); 265 testNormalizedAbsoluteFile("c", "a/../b/../c"); 266 testNormalizedAbsoluteFile("c", "a/../b/../c/."); 267 testNormalizedAbsoluteFile(".", "a/../b/../c/.."); 268 269 testNormalizedAbsoluteFile("../a", "../a"); 270 testNormalizedAbsoluteFile("../a", "../a/."); 271 testNormalizedAbsoluteFile("..", "../a/.."); 272 testNormalizedAbsoluteFile("../b", "../a/../b"); 273 testNormalizedAbsoluteFile("../b", "../a/../b/."); 274 testNormalizedAbsoluteFile("..", "../a/../b/.."); 275 testNormalizedAbsoluteFile("../c", "../a/../b/../c"); 276 testNormalizedAbsoluteFile("../c", "../a/../b/../c/."); 277 testNormalizedAbsoluteFile("..", "../a/../b/../c/.."); 278 279 testNormalizedAbsoluteFile("../a", "../a"); 280 testNormalizedAbsoluteFile("../a", "../a/."); 281 testNormalizedAbsoluteFile("../a/b", "../a/b"); 282 testNormalizedAbsoluteFile("../a/b", "../a/b/."); 283 testNormalizedAbsoluteFile("../a", "../a/b/.."); 284 testNormalizedAbsoluteFile("../a/c", "../a/b/../c"); 285 testNormalizedAbsoluteFile("../a/c", "../a/b/../c/."); 286 testNormalizedAbsoluteFile("../a", "../a/b/../c/.."); 287 } 288 289 void testNormalizedAbsoluteFile(final String result, final String path) 290 throws IOException { 291 java.io.File resultFile = new java.io.File (result).getCanonicalFile(); 292 java.io.File pathFile = new java.io.File (new File(path).getNormalizedAbsoluteFile().getPath()); 293 assertEquals(resultFile, pathFile); 294 } 295 296 public void testParentConstructor() throws Exception { 297 logger.fine("testParentConstructor"); 298 299 302 { 303 try { 304 new File("x", (String ) null); 305 fail("Expected NullPointerException!"); 306 } catch (NullPointerException expected) { 307 } 308 309 try { 310 new File(new File("x"), (String ) null); 311 fail("Expected NullPointerException!"); 312 } catch (NullPointerException expected) { 313 } 314 } 315 316 final String fs = File.separator; 317 318 { 319 final File[] files = { 320 new File(archive, ""), 321 new File(archive, "."), 322 new File(archive, "." + fs), 323 new File(archive, "." + fs + "."), 324 new File(archive, "." + fs + "." + fs), 325 new File(archive, "." + fs + "." + fs + "."), 326 }; 327 for (int i = 0; i < files.length; i++) { 328 final File file = files[i]; 329 assertSame(file, file.getInnerArchive()); 330 assertEquals("", file.getInnerEntryName()); 331 assertNull(file.getEnclArchive()); 332 assertNull(file.getEnclEntryName()); 333 } 334 } 335 336 { 337 final String innerName = "inner" + suffix; 338 final File inner = new File(archive, innerName); 339 final File[] files = { 340 new File(inner, ""), 341 new File(inner, "."), 342 new File(inner, "." + fs), 343 new File(inner, "." + fs + "."), 344 new File(inner, "." + fs + "." + fs), 345 new File(inner, "." + fs + "." + fs + "."), 346 }; 347 for (int i = 0; i < files.length; i++) { 348 final File file = files[i]; 349 assertSame(file, file.getInnerArchive()); 350 assertEquals("", file.getInnerEntryName()); 351 assertSame(archive, file.getEnclArchive()); 352 assertEquals(innerName, file.getEnclEntryName()); 353 } 354 } 355 356 { 357 final String entryName = "entry"; 358 final File entry = new File(archive, entryName); 359 final File[] files = { 360 new File(entry, ""), 361 new File(entry, "."), 362 new File(entry, "." + fs), 363 new File(entry, "." + fs + "."), 364 new File(entry, "." + fs + "." + fs), 365 new File(entry, "." + fs + "." + fs + "."), 366 }; 367 for (int i = 0; i < files.length; i++) { 368 final File file = files[i]; 369 assertSame(archive, file.getInnerArchive()); 370 assertEquals(entryName, file.getInnerEntryName()); 371 assertSame(archive, file.getEnclArchive()); 372 assertEquals(entryName, file.getEnclEntryName()); 373 } 374 } 375 376 final File a = new File("outer" + suffix + "/removed" + suffix); 377 File b, c; 378 379 b = new File("../removed.dir/removed.dir/../../dir/./inner" + suffix); 380 c = new File(a, b.getPath()); 381 assertTrue(c.isArchive()); 382 assertTrue(c.isEntry()); 383 assertEquals("outer" + suffix, 384 c.getEnclArchive().getPath()); 385 assertEquals("dir/inner" + suffix, 386 c.getEnclEntryName()); 387 388 b = new File("../removed.dir/removed.dir/../../dir/./inner" + suffix); 389 c = new File(a, b.getPath(), ArchiveDetector.NULL); 390 assertFalse(c.isArchive()); 391 assertTrue(c.isEntry()); 392 assertEquals("outer" + suffix, 393 c.getInnerArchive().getPath()); 394 assertEquals("dir/inner" + suffix, 395 c.getInnerEntryName()); 396 397 b = new File("../removed.dir/removed.dir/../../dir/./inner" 398 + suffix + "/removed.dir/removed.dir/../../dir/./test.txt"); 399 c = new File(a, b.getPath()); 400 assertFalse(c.isArchive()); 401 assertTrue(c.isEntry()); 402 assertEquals("outer" + suffix + fs + "removed" + suffix + fs + ".." 403 + fs + "removed.dir" + fs + "removed.dir" + fs + ".." + fs 404 + ".." + fs + "dir" + fs + "." + fs + "inner" + suffix, 405 c.getInnerArchive().getPath()); 406 assertEquals("dir/inner" + suffix, 407 c.getInnerArchive().getEnclEntryName()); 408 } 409 410 public void testURIConstructor() throws Exception { 411 logger.fine("testURIConstructor"); 412 413 File file; 414 final String fs = File.separator; 415 416 file = new File(new URI ("file", "/with a space", null)); 418 assertEquals("with a space", file.getName()); 419 assertNull(file.getInnerArchive()); 420 assertNull(file.getInnerEntryName()); 421 assertNull(file.getEnclArchive()); 422 assertNull(file.getEnclEntryName()); 423 424 426 file = new File(new URI ("file", "/a " + suffix + "/b " + suffix + "/", null)); 427 assertNull(file.getInnerArchive()); 428 assertNull(file.getInnerEntryName()); 429 assertNull(file.getEnclArchive()); 430 assertNull(file.getEnclEntryName()); 431 432 file = new File(new URI ("file", "/a " + suffix + "/b " + suffix + "", null)); 433 assertNull(file.getInnerArchive()); 434 assertNull(file.getInnerEntryName()); 435 assertNull(file.getEnclArchive()); 436 assertNull(file.getEnclEntryName()); 437 438 file = new File(new URI ("jar", "file:/a " + suffix + "/b " + suffix + "!/", null)); 440 assertSame(file, file.getInnerArchive()); 441 assertSame(File.EMPTY, file.getInnerEntryName()); 442 assertNull(file.getEnclArchive()); 443 assertNull(file.getEnclEntryName()); 444 445 file = new File(new URI ("jar", "file:/a " + suffix + "/b " + suffix + "!", null)); 446 assertSame(file, file.getInnerArchive()); 447 assertSame(File.EMPTY, file.getInnerEntryName()); 448 assertNull(file.getEnclArchive()); 449 assertNull(file.getEnclEntryName()); 450 451 file = new File(new URI ("jar", "file:/a " + suffix + "!/b " + suffix + "/", null)); 452 assertSame(file.getInnerArchive(), file.getEnclArchive()); 453 assertSame(file.getInnerEntryName(), file.getEnclEntryName()); 454 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 455 assertEquals("b " + suffix + "", file.getEnclEntryName()); 456 457 file = new File(new URI ("jar", "file:/a " + suffix + "!/b " + suffix + "", null)); 458 assertSame(file.getInnerArchive(), file.getEnclArchive()); 459 assertSame(file.getInnerEntryName(), file.getEnclEntryName()); 460 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 461 assertEquals("b " + suffix + "", file.getEnclEntryName()); 462 463 465 file = new File(new URI ("jar", "jar:file:/a " + suffix + "/b " + suffix + "!/", null)); 466 assertSame(file, file.getInnerArchive()); 467 assertSame(File.EMPTY, file.getInnerEntryName()); 468 assertNull(file.getEnclArchive()); 469 assertNull(file.getEnclEntryName()); 470 471 file = new File(new URI ("jar", "jar:file:/a " + suffix + "/b " + suffix + "!", null)); 472 assertSame(file, file.getInnerArchive()); 473 assertSame(File.EMPTY, file.getInnerEntryName()); 474 assertNull(file.getEnclArchive()); 475 assertNull(file.getEnclEntryName()); 476 477 file = new File(new URI ("jar", "jar:file:/a " + suffix + "!/b " + suffix + "/", null)); 478 assertSame(file.getInnerArchive(), file.getEnclArchive()); 479 assertSame(file.getInnerEntryName(), file.getEnclEntryName()); 480 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 481 assertEquals("b " + suffix + "", file.getEnclEntryName()); 482 483 file = new File(new URI ("jar", "jar:file:/a " + suffix + "!/b " + suffix + "", null)); 484 assertSame(file.getInnerArchive(), file.getEnclArchive()); 485 assertSame(file.getInnerEntryName(), file.getEnclEntryName()); 486 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 487 assertEquals("b " + suffix + "", file.getEnclEntryName()); 488 489 491 file = new File(new URI ("jar", "jar:jar:file:/a " + suffix + "/b " + suffix + "!/", null)); 492 assertSame(file, file.getInnerArchive()); 493 assertSame(File.EMPTY, file.getInnerEntryName()); 494 assertNull(file.getEnclArchive()); 495 assertNull(file.getEnclEntryName()); 496 497 file = new File(new URI ("jar", "jar:jar:file:/a " + suffix + "/b " + suffix + "!", null)); 498 assertSame(file, file.getInnerArchive()); 499 assertSame(File.EMPTY, file.getInnerEntryName()); 500 assertNull(file.getEnclArchive()); 501 assertNull(file.getEnclEntryName()); 502 503 file = new File(new URI ("jar", "jar:jar:file:/a " + suffix + "!/b " + suffix + "/", null)); 504 assertSame(file.getInnerArchive(), file.getEnclArchive()); 505 assertSame(file.getInnerEntryName(), file.getEnclEntryName()); 506 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 507 assertEquals("b " + suffix + "", file.getEnclEntryName()); 508 509 file = new File(new URI ("jar", "jar:jar:file:/a " + suffix + "!/b " + suffix + "", null)); 510 assertSame(file.getInnerArchive(), file.getEnclArchive()); 511 assertSame(file.getInnerEntryName(), file.getEnclEntryName()); 512 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 513 assertEquals("b " + suffix + "", file.getEnclEntryName()); 514 515 517 file = new File(new URI ("jar", "jar:file:/a " + suffix + "!/b " + suffix + "!/", null)); 518 assertSame(file, file.getInnerArchive()); 519 assertSame(File.EMPTY, file.getInnerEntryName()); 520 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 521 assertEquals("b " + suffix + "", file.getEnclEntryName()); 522 523 file = new File(new URI ("jar", "jar:file:/a " + suffix + "!/b " + suffix + "!", null)); 524 assertSame(file, file.getInnerArchive()); 525 assertSame(File.EMPTY, file.getInnerEntryName()); 526 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 527 assertEquals("b " + suffix + "", file.getEnclEntryName()); 528 529 531 file = new File(new URI ("jar", "file:/a " + suffix + "!/b " + suffix + "!/", null)); 532 assertSame(file, file.getInnerArchive()); 533 assertSame(File.EMPTY, file.getInnerEntryName()); 534 assertNull(file.getEnclArchive()); 535 assertNull(file.getEnclEntryName()); 536 537 file = new File(new URI ("jar", "file:/a " + suffix + "!/b " + suffix + "!", null)); 538 assertSame(file, file.getInnerArchive()); 539 assertSame(File.EMPTY, file.getInnerEntryName()); 540 assertNull(file.getEnclArchive()); 541 assertNull(file.getEnclEntryName()); 542 543 545 file = new File(new URI ("jar", "jar:file:/a " + suffix + "!/b " + suffix + "!/../c " + suffix + "!/", null)); 546 assertSame(file, file.getInnerArchive()); 547 assertSame(File.EMPTY, file.getInnerEntryName()); 548 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 549 assertEquals("c " + suffix + "", file.getEnclEntryName()); 550 551 file = new File(new URI ("jar", "jar:file:/a " + suffix + "!/b " + suffix + "!/../c " + suffix + "!", null)); 552 assertSame(file, file.getInnerArchive()); 553 assertSame(File.EMPTY, file.getInnerEntryName()); 554 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 555 assertEquals("c " + suffix + "", file.getEnclEntryName()); 556 557 560 file = new File(new URI ("jar", "jar:jar:file:/a " + suffix + "!/b " + suffix + "!/../c " + suffix + "!/", null)); 561 assertSame(file, file.getInnerArchive()); 562 assertSame(File.EMPTY, file.getInnerEntryName()); 563 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 564 assertEquals("c " + suffix + "", file.getEnclEntryName()); 565 566 file = new File(new URI ("jar", "jar:jar:file:/a " + suffix + "!/b " + suffix + "!/../c " + suffix + "!", null)); 567 assertSame(file, file.getInnerArchive()); 568 assertSame(File.EMPTY, file.getInnerEntryName()); 569 assertEquals(fs + "a " + suffix + "", file.getEnclArchive().getPath()); 570 assertEquals("c " + suffix + "", file.getEnclEntryName()); 571 572 574 file = new File(new URI ("jar", "file:/a " + suffix + "!/../b " + suffix + "/", null)); 575 assertNull(file.getInnerArchive()); 576 assertNull(file.getInnerEntryName()); 577 assertNull(file.getEnclArchive()); 578 assertNull(file.getEnclEntryName()); 579 580 file = new File(new URI ("jar", "file:/a " + suffix + "!/../b " + suffix + "", null)); 581 assertNull(file.getInnerArchive()); 582 assertNull(file.getInnerEntryName()); 583 assertNull(file.getEnclArchive()); 584 assertNull(file.getEnclEntryName()); 585 } 586 587 public void testSerialization() throws IOException , ClassNotFoundException { 588 logger.fine("testSerialization"); 589 590 final File inner = new File(archive, "inner" + suffix); 592 assertTrue(archive.isArchive()); 593 assertTrue(inner.isArchive()); 594 595 final ByteArrayOutputStream bos = new ByteArrayOutputStream (); 597 final ObjectOutputStream out = new ObjectOutputStream (bos); 598 out.writeObject(inner); 599 out.close(); 600 601 final ByteArrayInputStream bis = new ByteArrayInputStream (bos.toByteArray()); 603 final ObjectInputStream in = new ObjectInputStream (bis); 604 final File inner2 = (File) in.readObject(); 605 final File archive2 = (File) inner2.getParentFile(); 606 in.close(); 607 608 assertNotSame(inner, inner2); 609 assertNotSame(archive, archive2); 610 611 616 final ArchiveController innerController = inner.getArchiveController(); 618 final ArchiveController archiveController = archive.getArchiveController(); 619 final ArchiveController inner2Controller = inner2.getArchiveController(); 620 final ArchiveController archive2Controller = archive2.getArchiveController(); 621 assertSame(innerController, inner2Controller); 622 assertSame(archiveController, archive2Controller); 623 624 final ArchiveDetector innerDetector = inner.getArchiveDetector(); 626 final ArchiveDetector archiveDetector = archive.getArchiveDetector(); 627 final ArchiveDetector inner2Detector = inner2.getArchiveDetector(); 628 final ArchiveDetector archive2Detector = archive2.getArchiveDetector(); 629 assertNotSame(innerDetector, inner2Detector); 630 assertNotSame(archiveDetector, archive2Detector); 631 632 final ArchiveDriver innerDriver = innerDetector.getArchiveDriver(inner.getPath()); 634 final ArchiveDriver archiveDriver = archiveDetector.getArchiveDriver(archive.getPath()); 635 final ArchiveDriver inner2Driver = inner2Detector.getArchiveDriver(inner2.getPath()); 636 final ArchiveDriver archive2Driver = archive2Detector.getArchiveDriver(archive2.getPath()); 637 assertNotSame(innerDriver, inner2Driver); 638 assertNotSame(archiveDriver, archive2Driver); 639 640 final ArchiveDriver innerControllerDriver = innerController.getDriver(); 644 final ArchiveDriver archiveControllerDriver = archiveController.getDriver(); 645 assertSame(innerControllerDriver, inner2Driver); 646 assertSame(archiveControllerDriver, archive2Driver); 647 } 648 649 public void testGetOutermostArchive() { 650 logger.fine("testGetOutermostArchive"); 651 652 File file = new File("abc/def" + suffix + "/efg" + suffix + "/hij" + suffix + "/test.txt"); 653 assertEquals(new java.io.File ("abc/def" + suffix), file.getTopLevelArchive()); 654 } 655 656 659 public void testEqualsAndHashCode() { 660 logger.fine("testEqualsAndHashCode"); 661 662 final boolean win = File.separatorChar == '\\'; 664 assertFalse(new File("dir/test.txt").equals(new File("dir" + suffix + "/test.txt"))); 665 assertFalse(new File("dir" + suffix + "/test.txt").equals(new File("dir/test.txt"))); 666 assertEquals(new File("dir" + suffix + "/test.txt", ArchiveDetector.NULL), new File("dir" + suffix + "/test.txt")); 667 assertEquals(new File("dir" + suffix + "/test.txt"), new File("dir" + suffix + "/test.txt", ArchiveDetector.NULL)); 668 testEqualsAndHashCode( 669 new File(win ? "c:\\any.txt" : "/any.txt"), 670 new File(win ? "C:\\ANY.TXT" : "/ANY.TXT")); 671 testEqualsAndHashCode( 672 new File(win ? "c:\\any" + suffix + "\\test.txt" : "/any" + suffix + "/test.txt"), 673 new File(win ? "C:\\ANY" + suffix.toUpperCase() + "\\test.txt" : "/ANY" + suffix.toUpperCase() + "/test.txt")); 674 testEqualsAndHashCode( 675 new File(win ? "c:/any" + suffix + "/test.txt" : "/any" + suffix + "/test.txt"), 676 new File(win ? "C:\\ANY" + suffix.toUpperCase() + "\\test.txt" : "/ANY" + suffix.toUpperCase() + "/test.txt")); 677 testEqualsAndHashCode( 678 new File(win ? "c:\\any" + suffix + "\\test.txt" : "/any" + suffix + "/test.txt"), 679 new File(win ? "C:/ANY" + suffix.toUpperCase() + "/test.txt" : "/ANY" + suffix.toUpperCase() + "/test.txt")); 680 testEqualsAndHashCode( 681 new File(win ? "c:/any" + suffix + "/test.txt" : "/any" + suffix + "/test.txt"), 682 new File(win ? "C:/ANY" + suffix.toUpperCase() + "/test.txt" : "/ANY" + suffix.toUpperCase() + "/test.txt")); 683 if (win) { 684 testEqualsAndHashCode( 685 new File("\\\\localhost\\any" + suffix + "\\test.txt"), 686 new File("\\\\LOCALHOST\\ANY" + suffix.toUpperCase() + "\\test.txt")); 687 testEqualsAndHashCode( 688 new File("//localhost/any" + suffix + "/test.txt"), 689 new File("\\\\LOCALHOST\\ANY" + suffix.toUpperCase() + "\\test.txt")); 690 testEqualsAndHashCode( 691 new File("\\\\localhost\\any" + suffix + "\\test.txt"), 692 new File("//LOCALHOST/ANY" + suffix.toUpperCase() + "/test.txt")); 693 testEqualsAndHashCode( 694 new File("//localhost/any" + suffix + "/test.txt"), 695 new File("//LOCALHOST/ANY" + suffix.toUpperCase() + "/test.txt")); 696 } 697 final File l = new File(win ? "c:\\any" + suffix + "\\test.txt" : "/any" + suffix + "/test.txt"); 698 final File u = new File(win ? "c:\\any" + suffix + "\\TEST.TXT" : "/any" + suffix + "/TEST.TXT"); 699 assertFalse(l.equals(u)); 700 assertFalse(u.equals(l)); 701 } 702 703 void testEqualsAndHashCode(File a, File b) { 704 if (File.separatorChar == '\\') { 705 assertTrue(a.equals(b)); 706 assertTrue(b.equals(a)); 707 assertEquals(a.hashCode(), b.hashCode()); 708 } else { 709 assertFalse(a.equals(b)); 710 assertFalse(b.equals(a)); 711 } 712 assertEquals(a.hashCode(), a.hashCode()); assertEquals(b.hashCode(), b.hashCode()); 714 } 715 716 public void testGetParentFile() { 717 logger.fine("testGetParentFile"); 718 719 File abcdefgh = new File("a/b" + suffix + "/c/d/e" + suffix + "/f" + suffix + "/g/h" + suffix + ""); 720 File abcdefg = (File) abcdefgh.getParentFile(); 721 File abcdef = (File) abcdefg .getParentFile(); 722 File abcde = (File) abcdef .getParentFile(); 723 File abcd = (File) abcde .getParentFile(); 724 File abc = (File) abcd .getParentFile(); 725 File ab = (File) abc .getParentFile(); 726 File a = (File) ab .getParentFile(); 727 File n = (File) a .getParentFile(); 728 assertEquals(abcdefgh.getInnerArchive(), abcdefgh); 729 assertEquals(abcdefgh.getEnclArchive() , abcdef); 730 assertEquals(abcdefg .getInnerArchive(), abcdef); 731 assertEquals(abcdefg .getEnclArchive() , abcdef); 732 assertEquals(abcdef .getInnerArchive(), abcdef); 733 assertEquals(abcdef .getEnclArchive() , abcde); 734 assertEquals(abcde .getInnerArchive(), abcde); 735 assertEquals(abcde .getEnclArchive() , ab); 736 assertEquals(abcd .getInnerArchive(), ab); 737 assertEquals(abcd .getEnclArchive() , ab); 738 assertEquals(abc .getInnerArchive(), ab); 739 assertEquals(abc .getEnclArchive() , ab); 740 assertEquals(ab .getInnerArchive(), ab); 741 assertEquals(ab .getEnclArchive() , null); 742 assertEquals(a .getInnerArchive(), null); 743 assertEquals(a .getEnclArchive() , null); 744 assertNull(n); 745 } 746 747 753 public void testIsWritableOrCreatable() throws IOException { 754 logger.fine("testIsWritableOrCreatable"); 755 756 final java.io.File file = createTempFile(prefix, null); 757 758 boolean result = File.isWritableOrCreatable(file); 759 assertTrue(result); 760 761 boolean total = true; 762 final FileInputStream fin = new FileInputStream(file); 763 try { 764 result = File.isWritableOrCreatable(file); 765 total &= result; 766 } finally { 767 fin.close(); 768 } 769 if (!result) 770 logger.finer("Overwriting a file which has an open FileInputStream is not tolerated!"); 771 772 final String [] modes = { "r", "rw", "rws", "rwd" }; 773 for (int i = 0, l = modes.length; i < l; i++) { 774 final String mode = modes[i]; 775 final RandomAccessFile raf = new RandomAccessFile (file, mode); 776 try { 777 result = File.isWritableOrCreatable(file); 778 total &= result; 779 } finally { 780 raf.close(); 781 } 782 if (!result) 783 logger.finer("Overwriting a file which has an open RandomAccessFile in \"" + mode + "\" mode is not tolerated!"); 784 } 785 786 if (!total) 787 logger.finer( 788 "Applications should ALWAYS close their streams or you may face strange 'errors'.\n" 789 + "Note that this issue is NOT AT ALL specific to TrueZIP, but rather imposed by this platform!"); 790 791 assertTrue(file.delete()); 792 } 793 794 public void testFalsePositives() throws IOException { 795 logger.fine("testFalsePositives"); 796 797 testFalsePositive(archive); 798 799 final File entry = new File(archive, "entry" + suffix); 801 802 assertTrue(archive.mkdir()); 803 testFalsePositive(entry); 804 assertTrue(archive.delete()); 805 806 assertTrue(getNonArchiveFile(archive).mkdir()); 807 testFalsePositive(entry); 808 assertTrue(archive.delete()); 809 } 810 811 void testFalsePositive(File file) throws IOException { 812 assert file.isArchive(); 813 814 816 818 OutputStream os = new FileOutputStream(file); 819 try { 820 os.write(data); 821 } finally { 822 os.close(); 823 } 824 825 assertTrue(file.exists()); 826 assertFalse(file.isDirectory()); 827 assertTrue(file.isFile()); 828 assertEquals(data.length, file.length()); 829 assertTrue(0 != file.lastModified()); 830 831 testDelete(file); 832 833 835 assertTrue(getNonArchiveFile(file).mkdir()); 836 assertTrue(file.exists()); 837 assertTrue(file.isDirectory()); 838 assertFalse(file.isFile()); 839 assertTrue(0 != file.lastModified()); 841 842 testDelete(file); 843 844 846 assertTrue(file.mkdir()); 847 assertTrue(getNonArchiveFile(file).isFile()); 848 assertTrue(file.exists()); 849 assertTrue(file.isDirectory()); 850 assertFalse(file.isFile()); 851 assertTrue(0 != file.lastModified()); 853 854 testDelete(file); 855 } 856 857 void testDelete(File file) throws IOException { 858 assertTrue(file.delete()); 859 assertFalse(file.exists()); 860 assertFalse(file.isDirectory()); 861 assertFalse(file.isFile()); 862 assertEquals(0, file.length()); 863 assertFalse(0 != file.lastModified()); 864 } 865 866 public void testCreateNewFile() 867 throws IOException { 868 logger.fine("testCreateNewFile"); 869 870 createNewPlainFile(); 871 createNewSmartFile(); 872 } 873 874 void createNewPlainFile() 875 throws IOException { 876 final java.io.File zip = createTempFile(prefix, suffix); 877 assertTrue(zip.delete()); 878 final java.io.File file1 = new java.io.File (zip, "test.txt"); 879 final java.io.File file2 = new java.io.File (file1, "test.txt"); 880 try { 881 file1.createNewFile(); 882 fail("Creating a file in a non-existent directory should throw an IOException!"); 883 } catch (IOException ok) { 884 } 886 testCreateNewFile(zip, file1, file2); 887 } 888 889 void createNewSmartFile() 890 throws IOException { 891 final java.io.File file1 = new File(archive, "test.txt"); 892 final java.io.File file2 = new File(file1, "test.txt"); 893 894 File.setLenient(false); 895 try { 896 file1.createNewFile(); 897 fail("Creating a file in a non-existent directory should throw an IOException!"); 898 } catch (IOException ok) { 899 } 901 testCreateNewFile(archive, file1, file2); 902 903 File.setLenient(true); 904 testCreateNewFile(archive, file1, file2); 905 } 906 907 void testCreateNewFile( 908 final java.io.File dir, 909 final java.io.File file1, 910 final java.io.File file2) 911 throws IOException { 912 assertFalse(dir.exists()); 913 914 assertTrue(dir.mkdir()); 915 assertTrue(dir.exists()); 916 assertTrue(dir.isDirectory()); 917 assertFalse(dir.isFile()); 918 assertEquals(0, file1.length()); 919 920 assertTrue(file1.createNewFile()); 921 assertTrue(file1.exists()); 922 assertFalse(file1.isDirectory()); 923 assertTrue(file1.isFile()); 924 assertEquals(0, file1.length()); 925 926 try { 927 file2.createNewFile(); 928 fail("Creating a file in another file should throw an IOException!"); 929 } catch (IOException ok) { 930 } 932 933 assertTrue(file1.delete()); assertFalse(file1.exists()); 935 assertFalse(file1.isDirectory()); 936 assertFalse(file1.isFile()); 937 assertEquals(0, file1.length()); 938 939 assertTrue(dir.delete()); 940 assertFalse(dir.exists()); 941 assertFalse(dir.isDirectory()); 942 assertFalse(dir.isFile()); 943 assertEquals(0, dir.length()); 944 } 945 946 public void testFileOutputStream2Directory() 947 throws IOException { 948 logger.fine("testFileOutputStream2Directory"); 949 950 final File dir = new File(createTempFile(prefix, ".dir")); 951 assertTrue(dir.delete()); 952 assertTrue(dir.mkdir()); 953 try { 954 new FileOutputStream(dir).close(); 955 fail("Writing to a directory should not be possible!"); 956 } catch (FileNotFoundException ok) { 957 } 959 assertTrue(dir.delete()); 960 961 final OutputStream out = new FileOutputStream(archive); 964 out.write(data); 965 out.close(); 966 new FileOutputStream(archive).close(); 967 assertTrue(archive.delete()); 968 969 assertTrue(archive.mkdir()); 972 try { 973 new FileOutputStream(archive).close(); 974 fail("Writing to files with a ZIP file suffix should not be possible!"); 975 } catch (FileNotFoundException ok) { 976 } 978 980 final File zipDir = new File(archive, "test"); 981 assertTrue(zipDir.mkdirs()); 982 try { 983 new FileOutputStream(zipDir).close(); 984 fail("Writing to a directory within a ZIP file should not be possible!"); 985 } catch (FileNotFoundException ok) { 986 988 } 989 assertTrue(zipDir.delete()); 990 991 final File zipZip = new File(archive, "inner" + suffix); 992 final File zipZipDir = new File(zipZip, "test"); 993 assertTrue(zipZipDir.mkdirs()); 994 try { 995 new FileOutputStream(zipZipDir).close(); 996 fail("Writing to a directory within a ZIP file should not be possible!"); 997 } catch (FileNotFoundException ok) { 998 } 1000 assertTrue(zipZipDir.delete()); 1001 assertTrue(zipZip.delete()); 1002 } 1003 1004 public void testStrictFileOutputStream() 1005 throws IOException { 1006 logger.fine("testStrictFileOutputStream"); 1007 1008 File file = new File(archive, "test.txt"); 1009 1010 File.setLenient(false); 1011 try { 1012 testFileOutputStream(file); 1013 fail("Creating missing parent ZIP directories should be impossible when File.isLenient() is not set!"); 1014 } catch (IOException ok) { 1015 } 1017 1018 assertTrue(archive.mkdir()); 1019 testFileOutputStream(file); 1020 assertTrue(archive.delete()); 1021 } 1022 1023 public void testLenientFileOutputStream() 1024 throws IOException { 1025 logger.fine("testLenientFileOutputStream"); 1026 1027 File file = new File(archive, "dir/inner" + suffix + "/dir/test.txt"); 1028 1029 testFileOutputStream(file); 1030 1031 assertFalse(archive.delete()); File.umount(); assertTrue(new java.io.File (archive.getPath()).delete()); assertFalse(archive.exists()); 1035 assertFalse(archive.isDirectory()); 1036 assertFalse(archive.isFile()); 1037 assertEquals(0, archive.length()); 1038 } 1039 1040 void testFileOutputStream(File file) 1041 throws IOException { 1042 final byte[] message = "Hello World!\r\n".getBytes(); 1043 1044 final FileOutputStream fos = new FileOutputStream(file); 1045 assertTrue(file.exists()); 1046 assertFalse(file.isDirectory()); 1047 assertTrue(file.isFile()); 1048 assertEquals(0, file.length()); 1049 fos.write(message); 1050 assertEquals(0, file.length()); 1051 fos.flush(); 1052 assertEquals(0, file.length()); 1053 fos.close(); 1054 assertTrue(file.exists()); 1055 assertFalse(file.isDirectory()); 1056 assertTrue(file.isFile()); 1057 assertEquals(message.length, file.length()); 1058 1059 assertFalse(file.createNewFile()); 1060 1061 assertTrue(file.delete()); 1062 assertFalse(file.exists()); 1063 assertFalse(file.isDirectory()); 1064 assertFalse(file.isFile()); 1065 assertEquals(0, file.length()); 1066 } 1067 1068 public void testBusyFileInputStream() 1069 throws IOException { 1070 logger.fine("testBusyFileInputStream"); 1071 1072 File file1 = new File(archive, "file1"); 1073 File file2 = new File(archive, "file2"); 1074 1075 assertTrue(file1.createNewFile()); 1077 File.update(); assertTrue(file2.createNewFile()); 1079 FileInputStream fisA = new FileInputStream(file1); 1080 try { 1081 FileInputStream fisB = new FileInputStream(file2); 1082 fail("Accessing file2 was expected to fail because an auto update needs to be done but the ZIP file is busy on input for fis1!"); 1083 } catch (FileBusyException expected) { 1084 } 1085 assertFalse(file2.catFrom(fisA)); 1087 try { 1089 File.update(); fail("ArchiveWarningException expected!"); 1091 } catch (ArchiveBusyWarningException expected) { 1092 } 1094 assertTrue(file2.isFile()); 1095 if (!file2.catFrom(fisA)) assertFalse(file2.exists()); 1098 FileInputStream fisB = new FileInputStream(file1); 1100 fisB = null; 1102 System.gc(); 1103 try { 1104 Thread.sleep(100); 1105 } catch (InterruptedException ignored) { 1106 } 1107 1108 try { 1111 File.umount(); } catch (ArchiveBusyWarningException failure) { 1113 fail("The garbage collector hasn't been collecting an open stream. If this is only happening occasionally, you can safely ignore it."); 1114 } 1115 1116 assertTrue(getNonArchiveFile(archive).delete()); 1117 fisA.close(); 1119 1120 assertFalse(file2.delete()); assertFalse(file2.exists()); 1123 assertFalse(file1.delete()); 1124 assertFalse(file1.exists()); 1125 } 1126 1127 public void testBusyFileOutputStream() 1128 throws IOException { 1129 logger.fine("testBusyFileOutputStream"); 1130 1131 File file1 = new File(archive, "file1"); 1132 File file2 = new File(archive, "file2"); 1133 1134 FileOutputStream fosA = new FileOutputStream(file1); 1139 File.cat(new ByteArrayInputStream (data), fosA); 1140 fosA.close(); 1141 1142 fosA = new FileOutputStream(file2); 1143 File.cat(new ByteArrayInputStream (data), fosA); 1144 fosA.close(); 1145 1146 File.update(); 1148 fosA = new FileOutputStream(file1); 1149 File.cat(new ByteArrayInputStream (data), fosA); 1150 1151 try { 1153 FileOutputStream fosB = new FileOutputStream(file1); 1154 } catch (FileBusyException busy) { 1155 assertTrue(busy.getCause() instanceof ArchiveBusyException); 1158 } 1159 1160 try { 1162 FileOutputStream fosB = new FileOutputStream(file2); 1163 logger.fine("This archive driver DOES support concurrent writing of different entries in the same archive file."); 1164 } catch (FileBusyException busy) { 1165 logger.fine("This archive driver does NOT support concurrent writing of different entries in the same archive file."); 1167 } 1168 1169 File.cat(new ByteArrayInputStream (data), fosA); 1172 try { 1173 File.update(); fail("Output stream should have been forced to close!"); 1175 } catch (ArchiveBusyWarningException expected) { 1176 } 1177 1178 try { 1179 File.cat(new ByteArrayInputStream (data), fosA); fail("Output stream should have been forcibly closed!"); 1181 } catch (IOException expected) { 1182 } 1183 1184 fosA.close(); 1187 1188 fosA = new FileOutputStream(file1); 1190 fosA = null; 1191 System.gc(); 1192 try { 1193 Thread.sleep(100); 1194 } catch (InterruptedException ignored) { 1195 } 1196 1197 try { 1200 File.update(); 1201 } catch (ArchiveBusyWarningException failure) { 1202 fail("The garbage collector hasn't been collecting an open stream. If this is only happening occasionally, you can safely ignore it."); 1203 } 1204 1205 assertTrue(file2.delete()); 1207 assertFalse(file2.exists()); 1208 assertTrue(file1.delete()); 1209 assertFalse(file1.exists()); 1210 } 1211 1212 public void testMkdir() 1213 throws IOException { 1214 logger.fine("testMkdir"); 1215 1216 final File dir1 = archive; 1217 final File dir2 = new File(dir1, "dir"); 1218 final File dir3 = new File(dir2, "inner" + suffix); 1219 final File dir4 = new File(dir3, "dir"); 1220 final File dir5 = new File(dir4, "nuts" + suffix); 1221 final File dir6 = new File(dir5, "dir"); 1222 1223 File.setLenient(true); 1224 1225 assertTrue(dir6.mkdir()); 1227 assertFalse(dir6.mkdir()); assertFalse(dir5.mkdir()); assertFalse(dir4.mkdir()); assertFalse(dir3.mkdir()); assertFalse(dir2.mkdir()); assertFalse(dir1.mkdir()); 1234 assertTrue(dir6.delete()); 1235 assertTrue(dir5.delete()); 1236 assertTrue(dir4.delete()); 1237 assertTrue(dir3.delete()); 1238 assertTrue(dir2.delete()); 1239 assertTrue(dir1.delete()); 1240 1241 File.setLenient(false); 1242 1243 assertFalse(dir6.mkdir()); 1244 assertFalse(dir5.mkdir()); 1245 assertFalse(dir4.mkdir()); 1246 assertFalse(dir3.mkdir()); 1247 assertFalse(dir2.mkdir()); 1248 1249 assertTrue(dir1.mkdir()); 1250 assertTrue(dir2.mkdir()); 1251 assertTrue(dir3.mkdir()); 1252 assertTrue(dir4.mkdir()); 1253 assertTrue(dir5.mkdir()); 1254 assertTrue(dir6.mkdir()); 1255 1256 assertTrue(dir6.delete()); 1257 assertTrue(dir5.delete()); 1258 assertTrue(dir4.delete()); 1259 assertTrue(dir3.delete()); 1260 assertTrue(dir2.delete()); 1261 assertTrue(dir1.delete()); 1262 } 1263 1264 public void testDirectoryTree() 1265 throws IOException { 1266 logger.fine("testDirectoryTree"); 1267 1268 testDirectoryTree( 1269 new File("."), new File("dir/inner" + suffix + "/dir/outer" + suffix + "/" + archive.getName())); } 1272 1273 void testDirectoryTree(File basePath, File reversePath) 1274 throws IOException { 1275 if (reversePath == null) { 1276 final File test = new File(basePath, "test.txt"); 1278 testFileOutputStream(test); 1280 return; 1281 } 1282 assertFalse(".".equals(reversePath.getPath())); 1283 assertFalse("..".equals(reversePath.getPath())); 1284 1285 final File member = new File(basePath, reversePath.getName()); 1286 final boolean created = member.mkdir(); 1287 final File children = (File) reversePath.getParentFile(); 1288 testDirectoryTree(member, children); 1289 testListFiles(basePath, member.getName()); 1290 assertTrue(member.exists()); 1291 assertTrue(member.isDirectory()); 1292 assertFalse(member.isFile()); 1293 if (member.isArchive()) 1294 assertEquals(0, member.length()); 1295 if (created) { 1296 assertTrue(member.delete()); 1297 assertFalse(member.exists()); 1298 assertFalse(member.isDirectory()); 1299 assertFalse(member.isFile()); 1300 assertEquals(0, member.length()); 1301 } 1302 } 1303 1304 void testListFiles(File dir, String entry) { 1305 java.io.File [] files = dir.listFiles(); 1306 boolean found = false; 1308 for (int i = 0, l = files.length; i < l; i++) { 1309 File file = (File) files[i]; 1310 assertTrue(file instanceof File); 1311 if (file.getName().equals(entry)) 1312 found = true; 1313 } 1314 if (!found) 1315 fail("No such entry: " + entry); 1316 } 1317 1318 public void testCat() 1319 throws IOException { 1320 logger.fine("testCat"); 1321 1322 try { 1323 testCat(archive); 1324 fail("Writing to files with a ZIP file suffix should not be possible!"); 1325 } catch (AssertionFailedError ok) { 1326 } 1328 1329 final File zipTest = new File(archive, "test"); 1330 testCat(zipTest); 1331 1332 final File zipZip = new File(archive, "inner" + suffix); 1333 final File zipZipTest = new File(zipZip, "test"); 1334 testCat(zipZipTest); 1335 assertTrue(zipZip.delete()); 1336 assertTrue(archive.delete()); 1337 } 1338 1339 void testCat(final File file) 1340 throws IOException { 1341 testCatFrom(file); 1342 testCatTo(file); 1343 assertTrue(file.delete()); 1344 } 1345 1346 void testCatFrom(final File file) 1347 throws IOException { 1348 final InputStream in = new ByteArrayInputStream (data); 1349 try { 1350 assertTrue(file.catFrom(in)); 1351 } finally { 1352 in.close(); 1353 } 1354 } 1355 1356 void testCatTo(final File file) 1357 throws IOException { 1358 final ByteArrayOutputStream out = new ByteArrayOutputStream (data.length); 1359 try { 1360 assertTrue(file.catTo(out)); 1361 } finally { 1362 out.close(); 1363 } 1364 assertTrue(Arrays.equals(data, out.toByteArray())); 1365 } 1366 1367 public void testCopyContainingOrSameFiles() throws IOException { 1368 logger.fine("testCopyContainingOrSameFiles"); 1369 1370 assert !archive.exists(); 1371 1372 final File dir = (File) archive.getParentFile(); 1373 assertNotNull(dir); 1374 final File entry = new File(archive, "entry"); 1375 1376 testCopyContainingOrSameFiles1(dir, archive); 1377 testCopyContainingOrSameFiles1(archive, entry); 1378 1379 assertTrue(entry.catFrom(new ByteArrayInputStream (data))); 1380 1381 testCopyContainingOrSameFiles1(dir, archive); 1382 testCopyContainingOrSameFiles1(archive, entry); 1383 1384 assertTrue(archive.deleteAll()); 1385 } 1386 1387 public void testCopyContainingOrSameFiles1( 1388 final File a, 1389 final File b) 1390 throws IOException { 1391 testCopyContainingOrSameFiles2(a, b); 1392 testCopyContainingOrSameFiles2(a.getCanOrAbsFile(), b); 1393 testCopyContainingOrSameFiles2(a, b.getCanOrAbsFile()); 1394 testCopyContainingOrSameFiles2(a.getCanOrAbsFile(), b.getCanOrAbsFile()); 1395 } 1396 1397 public void testCopyContainingOrSameFiles2( 1398 final File a, 1399 final File b) 1400 throws IOException { 1401 try { 1402 File.cp(a, a); 1403 fail("Expected SameFileException"); 1404 } catch (ContainsFileException sfe) { 1405 } 1406 try { 1407 File.cp(a, b); 1408 fail("Expected FileNotFoundException"); 1409 } catch (FileNotFoundException fnfe) { 1410 } 1411 try { 1412 File.cp(b, a); 1413 fail("Expected FileNotFoundException"); 1414 } catch (FileNotFoundException fnfe) { 1415 } 1416 try { 1417 File.cp(b, b); 1418 fail("Expected SameFileException"); 1419 } catch (ContainsFileException sfe) { 1420 } 1421 } 1422 1423 public void testCopy() 1424 throws IOException { 1425 logger.fine("testCopy"); 1426 1427 final File archive1 = archive; 1428 final File archive2 = new File(archive1, "inner" + suffix); 1429 final File archive3 = new File(archive2, "nuts" + suffix); 1430 1431 testCopy(archive1, archive2, archive3, "a", "b"); 1432 } 1433 1434 public void testCopyFalsePositives() 1435 throws IOException { 1436 logger.fine("testCopyFalsePositives"); 1437 1438 final File archive0 = archive; 1439 final File archive1 = new File(archive0, "inner" + suffix); 1440 final File archive2 = new File(archive1, "nuts" + suffix); 1441 1442 final File archives[][] = { 1443 { 1444 getNonArchiveFile(archive0), 1445 getNonArchiveFile(archive1), 1446 getNonArchiveFile(archive2), 1447 }, { 1448 getNonArchiveFile(archive0), 1449 getNonArchiveFile(archive1), 1450 archive2, 1451 }, { 1452 getNonArchiveFile(archive0), 1453 archive1, 1454 getNonArchiveFile(archive2), 1455 }, { 1456 getNonArchiveFile(archive0), 1457 archive1, 1458 archive2, 1459 }, { 1460 archive0, 1461 getNonArchiveFile(archive1), 1462 getNonArchiveFile(archive2), 1463 }, { 1464 archive0, 1465 getNonArchiveFile(archive1), 1466 archive2, 1467 }, { 1468 archive0, 1469 archive1, 1470 getNonArchiveFile(archive2), 1471 } 1472 }; 1473 1474 for (int i = 0; i < archives.length; i++) { 1475 assertTrue(archives[i][0].mkdir()); 1476 assertTrue(archives[i][1].mkdir()); 1477 assertTrue(archives[i][2].mkdir()); 1478 1479 testCopy(archive0, archive1, archive2, "a" + suffix, "b" + suffix); 1480 1481 File.umount(); } 1483 } 1484 1485 private static final File getNonArchiveFile(File file) { 1486 return ArchiveDetector.NULL.createFile( 1487 file.getParentFile(), file.getName()); 1488 } 1489 1490 public void testCopy( 1491 final File archive0, 1492 final File archive1, 1493 final File archive2, 1494 final String entryA, 1495 final String entryB) 1496 throws IOException { 1497 final File zip0a = new File(archive0, entryA); 1498 final File zip0b = new File(archive0, entryB); 1499 final File zip1a = new File(archive1, entryA); 1500 final File zip1b = new File(archive1, entryB); 1501 final File zip2a = new File(archive2, entryA); 1502 final File zip2b = new File(archive2, entryB); 1503 1504 for (int i = 2; i >= 1; i--) { 1505 testCopy(zip0a, zip0b); 1506 testCopy(zip0a, zip1a); 1507 testCopy(zip0a, zip1b); 1508 testCopy(zip0a, zip2a); 1509 testCopy(zip0a, zip2b); 1510 1511 testCopy(zip0b, zip0a); 1512 testCopy(zip0b, zip1a); 1513 testCopy(zip0b, zip1b); 1514 testCopy(zip0b, zip2a); 1515 testCopy(zip0b, zip2b); 1516 1517 testCopy(zip1a, zip0a); 1518 testCopy(zip1a, zip0b); 1519 testCopy(zip1a, zip1b); 1520 testCopy(zip1a, zip2a); 1521 testCopy(zip1a, zip2b); 1522 1523 testCopy(zip1b, zip0a); 1524 testCopy(zip1b, zip0b); 1525 testCopy(zip1b, zip1a); 1526 testCopy(zip1b, zip2a); 1527 testCopy(zip1b, zip2b); 1528 1529 testCopy(zip2a, zip0a); 1530 testCopy(zip2a, zip0b); 1531 testCopy(zip2a, zip1a); 1532 testCopy(zip2a, zip1b); 1533 testCopy(zip2a, zip2b); 1534 1535 testCopy(zip2b, zip0a); 1536 testCopy(zip2b, zip0b); 1537 testCopy(zip2b, zip1a); 1538 testCopy(zip2b, zip1b); 1539 testCopy(zip2b, zip2a); 1540 } 1541 1542 assertTrue(archive2.delete()); 1543 assertTrue(archive1.delete()); 1544 assertTrue(archive0.delete()); 1545 } 1546 1547 final void testCopy(File a, File b) 1548 throws IOException { 1549 testCopy(a, b, 2000); } 1551 1552 void testCopy(final File a, final File b, final long granularity) 1553 throws IOException { 1554 { 1556 final OutputStream out = new FileOutputStream(a); 1557 try { 1558 out.write(data); 1559 } finally { 1560 out.close(); 1561 } 1562 a.setLastModified(System.currentTimeMillis() - granularity); 1563 } 1564 1565 assertTrue(b.copyFrom(a)); 1567 assertEquals(a.length(), b.length()); 1568 assertTrue(a.lastModified() != b.lastModified()); 1569 assertTrue(b.archiveCopyFrom(a)); 1570 assertEquals(a.length(), b.length()); 1571 assertEquals( 1572 (a.lastModified() / granularity) * granularity, 1573 (b.lastModified() / granularity) * granularity); 1574 1575 assertTrue(b.copyTo(a)); assertEquals(a.length(), b.length()); 1578 assertTrue(a.lastModified() != b.lastModified()); 1579 assertTrue(b.archiveCopyTo(a)); 1580 assertEquals(a.length(), b.length()); 1581 assertEquals( 1582 (a.lastModified() / granularity) * granularity, 1583 (b.lastModified() / granularity) * granularity); 1584 1585 { 1587 final ByteArrayOutputStream out = new ByteArrayOutputStream (data.length); 1588 assertTrue(a.copyTo(out)); 1589 assertTrue(Arrays.equals(data, out.toByteArray())); 1590 } 1591 1592 assertTrue(a.delete()); 1594 assertTrue(b.delete()); 1595 } 1596 1597 public void testListPerformance() 1598 throws IOException { 1599 logger.fine("testListPerformance"); 1600 1601 assertTrue(archive.mkdir()); 1602 1603 int i, j; 1604 long time; 1605 1606 time = System.currentTimeMillis(); 1607 for (i = 0; i < 100; i++) { 1608 File file = new File(archive, "" + i); 1609 assertTrue(file.createNewFile()); 1610 } 1611 time = System.currentTimeMillis() - time; 1612 logger.finer("Time required to create " + i + " zip file entries: " + time + "ms"); 1613 1614 time = System.currentTimeMillis(); 1615 for (j = 0; j < 100; j++) { 1616 archive.listFiles((FilenameFilter ) null); 1617 } 1618 time = System.currentTimeMillis() - time; 1619 logger.finer("Time required to list these entries " + j + " times using a nullary FilenameFilter: " + time + "ms"); 1620 1621 time = System.currentTimeMillis(); 1622 for (j = 0; j < 100; j++) { 1623 archive.listFiles((FileFilter ) null); 1624 } 1625 time = System.currentTimeMillis() - time; 1626 logger.finer("Time required to list these entries " + j + " times using a nullary FileFilter: " + time + "ms"); 1627 1628 assertFalse(archive.delete()); File.umount(); assertTrue(new java.io.File (archive.getPath()).delete()); assertFalse(archive.exists()); 1632 assertFalse(archive.isDirectory()); 1633 assertFalse(archive.isFile()); 1634 assertEquals(0, archive.length()); 1635 } 1636 1637 1683 1684 public void testIllegalDeleteEntryWithOpenStream() throws IOException { 1685 logger.fine("testIllegalDeleteEntryWithOpenStream"); 1686 1687 final File entry1 = new File(archive, "entry1"); 1688 final File entry2 = new File(archive, "entry2"); 1689 1690 final OutputStream out1 = new FileOutputStream(entry1); 1691 try { 1692 assertFalse(entry1.delete()); 1693 out1.write(data); 1694 assertFalse(archive.deleteAll()); 1695 } finally { 1696 out1.close(); 1697 } 1698 1699 final OutputStream out2 = new FileOutputStream(entry2); 1700 try { 1701 assertFalse(entry2.delete()); 1702 out2.write(data); 1703 assertFalse(archive.deleteAll()); 1704 } finally { 1705 out2.close(); 1706 } 1707 1708 final InputStream in1 = new FileInputStream(entry1); try { 1710 final InputStream in2 = new FileInputStream(entry2); 1711 try { 1712 assertTrue(entry2.delete()); 1713 final ByteArrayOutputStream out = new ByteArrayOutputStream (data.length); 1714 try { 1715 File.cat(in2, out); 1716 } finally { 1717 out.close(); 1718 } 1719 assertTrue(Arrays.equals(data, out.toByteArray())); 1720 assertFalse(archive.deleteAll()); 1721 } finally { 1722 in2.close(); 1723 } 1724 1725 assertFalse(entry1.delete()); final ByteArrayOutputStream out = new ByteArrayOutputStream (data.length); 1727 try { 1728 File.cat(in1, out); 1729 } finally { 1730 out.close(); 1731 } 1732 assertTrue(Arrays.equals(data, out.toByteArray())); 1733 assertFalse(archive.deleteAll()); 1734 } finally { 1735 in1.close(); 1736 } 1737 1738 assertTrue(archive.deleteAll()); 1739 assertFalse(getPlainFile(archive).exists()); 1740 } 1741 1742 public void testRenameValidArchive() 1743 throws IOException { 1744 logger.fine("testRenameValidArchive"); 1745 1746 final OutputStream out = new FileOutputStream(new File(archive, "entry")); 1749 try { 1750 new PrintStream (out, true).println("Hello World!"); 1751 } finally { 1752 out.close(); } 1754 1755 testRenameArchiveToTemp(archive); 1756 } 1757 1758 public void testRenameFalsePositive() 1759 throws IOException { 1760 logger.fine("testRenameFalsePositive"); 1761 1762 final File tmp = new File(archive.getPath(), ArchiveDetector.NULL); 1771 final InputStream in = new ByteArrayInputStream (data); 1772 try { 1773 assertTrue(tmp.copyFrom(in)); 1774 } finally { 1775 in.close(); } 1777 1778 testRenameArchiveToTemp(archive); 1779 } 1780 1781 public void testRenameArchiveToTemp(final File archive) 1782 throws IOException { 1783 assert archive.isArchive(); assert !archive.isEntry(); 1786 File tmp = new File(createTempFile(prefix, null)); 1788 assertTrue(tmp.delete()); 1789 assertFalse(tmp.exists()); 1790 assertFalse(getPlainFile(tmp).exists()); 1791 1792 assertTrue(archive.renameTo(tmp)); 1797 assertFalse(archive.exists()); 1798 assertFalse(getPlainFile(archive).exists()); 1799 1800 assertTrue(tmp.deleteAll()); 1802 assertFalse(tmp.exists()); 1803 assertFalse(getPlainFile(tmp).exists()); 1804 } 1805 1806 public void testRenameRecursively() 1807 throws IOException { 1808 logger.fine("testRenameRecursively"); 1809 1810 final File zap = new File(createTempFile(prefix, suffix)); 1811 final File zip2 = new File(archive, "inner" + suffix); 1812 final File zip3 = new File(zip2, "nuts" + suffix); 1813 final File zip1a = new File(archive, "a"); 1814 final File zip1b = new File(archive, "b"); 1815 final File zip2a = new File(zip2, "a"); 1816 final File zip2b = new File(zip2, "b"); 1817 final File zip3a = new File(zip3, "a"); 1818 final File zip3b = new File(zip3, "b"); 1819 1820 assertTrue(zap.delete()); 1821 1822 testCatFrom(zip1a); 1823 1824 for (int i = 2; i >= 1; i--) { 1825 testRenameTo(zip1a, zip1b); 1826 testRenameTo(zip1b, zip2a); 1827 testRenameTo(zip2a, zip2b); 1828 testRenameTo(zip2b, zip3a); 1829 testRenameTo(zip3a, zip3b); 1830 testRenameTo(zip3b, zip3a); 1831 testRenameTo(zip3a, zip2b); 1832 testRenameTo(zip2b, zip2a); 1833 testRenameTo(zip2a, zip1b); 1834 testRenameTo(zip1b, zip1a); 1835 } 1836 1837 testRenameTo(archive, zap); 1838 testRenameTo(zap, archive); 1839 assertTrue(zip3.delete()); 1840 assertTrue(zip2.delete()); 1841 testCatTo(zip1a); 1842 assertTrue(zip1a.delete()); 1843 assertTrue(archive.delete()); 1844 } 1845 1846 void testRenameTo(File src, File dst) { 1847 assertTrue(src.exists()); 1848 if (!src.isEntry()) 1849 assertTrue(getPlainFile(src).exists()); 1850 assertFalse(dst.exists()); 1851 if (!dst.isEntry()) 1852 assertFalse(getPlainFile(dst).exists()); 1853 assertTrue(src.renameTo(dst)); assertFalse(src.exists()); 1855 if (!src.isEntry()) 1856 assertFalse(getPlainFile(src).exists()); 1857 assertTrue(dst.exists()); 1858 if (!dst.isEntry()) 1859 assertTrue(getPlainFile(dst).exists()); 1860 } 1861 1862 private static java.io.File getPlainFile(final File file) { 1863 return new java.io.File (file.getPath()); 1864 } 1865 1866 private static final String [] members = { 1867 "A directory member", 1868 "Another directory member", 1869 "Yet another directory member", 1870 }; 1871 1872 public void testListFiles() throws IOException { 1873 logger.fine("testListFiles"); 1874 1875 java.io.File dir = createTempFile(prefix, suffix); 1876 File dir2 = new File(dir); 1877 1878 assertTrue(dir.delete()); 1879 assertTrue(dir.mkdir()); 1880 1881 for (int i = members.length; --i >= 0; ) { 1882 assertTrue(new java.io.File (dir, members[i]).createNewFile()); 1883 } 1884 1885 java.io.File [] files = dir.listFiles(); 1886 java.io.File [] files2 = dir2.listFiles(); 1887 1888 assertEquals(files.length, files2.length); 1889 1890 for (int i = 0, l = files.length; i < l; i++) { 1891 assertTrue(!(files[i] instanceof File)); 1892 assertTrue(files2[i] instanceof File); 1893 assertEquals(files[i].getPath(), files2[i].getPath()); 1894 } 1895 1896 assertTrue(dir2.deleteAll()); 1897 } 1898 1899 public void testMultithreadedSingleArchiveMultipleEntriesReading() 1900 throws Exception { 1901 logger.fine("testMultithreadedSingleArchiveMultipleEntriesReading"); 1902 1903 testMultithreadedSingleArchiveMultipleEntriesReading(20, 20); 1904 } 1905 1906 1914 private void testMultithreadedSingleArchiveMultipleEntriesReading(final int nEntries, final int nThreads) 1915 throws Exception { 1916 createTestArchive(nEntries); 1918 1919 class CheckAllEntriesThread extends Thread { 1921 Throwable failure; 1922 1923 public void run() { 1924 try { 1925 checkArchiveEntries(archive, nEntries); 1926 } catch (Throwable t) { 1927 failure = t; 1928 } 1929 } 1930 } 1932 final CheckAllEntriesThread[] threads = new CheckAllEntriesThread[nThreads]; 1934 for (int i = 0; i < nThreads; i++) { 1935 final CheckAllEntriesThread thread = new CheckAllEntriesThread(); 1936 thread.start(); 1937 threads[i] = thread; 1938 } 1939 1940 for (int i = 0; i < nThreads; i++) { 1942 final CheckAllEntriesThread thread = threads[i]; 1943 thread.join(); 1944 if (thread.failure != null) 1945 throw new Exception (thread.failure); 1946 } 1947 1948 assertTrue(archive.deleteAll()); 1949 } 1950 1951 private void createTestArchive(final int nEntries) throws IOException { 1952 for (int i = 0; i < nEntries; i++) { 1953 final File entry = new File(archive + File.separator + i); 1954 final OutputStream out = new FileOutputStream(entry); 1955 try { 1956 out.write(data); 1957 } finally { 1958 out.close(); 1959 } 1960 } 1961 } 1962 1963 private void checkArchiveEntries(final File archive, int nEntries) 1964 throws IOException { 1965 final java.io.File [] entries = archive.listFiles(); 1966 assertEquals(nEntries, entries.length); 1967 final byte[] buf = new byte[4096]; 1968 for (int i = 0, l = entries.length; i < l; i++) { 1969 final File entry = (File) entries[i]; 1970 final InputStream in = new FileInputStream(entry); 1972 try { 1973 int off = 0; 1974 int read; 1975 do { 1976 read = in.read(buf); 1977 if (read < 0) 1978 break; 1979 assertTrue(read > 0); 1980 assertTrue(de.schlichtherle.util.Arrays.equals( 1981 data, off, buf, 0, read)); 1982 off += read; 1983 } while (true); 1984 assertEquals(-1, read); 1985 assertEquals(off, data.length); 1986 assertEquals(0, in.read(new byte[0])); 1987 } finally { 1988 in.close(); 1989 } 1990 } 1991 } 1992 1993 public void testMultithreadedSingleArchiveMultipleEntriesWriting() 1994 throws Exception { 1995 logger.fine("testMultithreadedSingleArchiveMultipleEntriesWriting"); 1996 1997 testMultithreadedSingleArchiveMultipleEntriesWriting(archive, 20, false); 1998 testMultithreadedSingleArchiveMultipleEntriesWriting(archive, 20, true); 1999 } 2000 2001 private void testMultithreadedSingleArchiveMultipleEntriesWriting( 2002 final File archive, 2003 final int nThreads, 2004 final boolean wait) 2005 throws Exception { 2006 assertTrue(File.isLenient()); 2007 2008 class WritingThread extends Thread { 2009 final int i; 2010 Throwable failure; 2011 2012 WritingThread(int i) { 2013 this.i = i; 2014 } 2015 2016 public void run() { 2017 try { 2018 final File file = new File(archive, i + ""); 2019 OutputStream out; 2020 while (true) { 2021 try { 2022 out = new FileOutputStream(file); 2023 break; 2024 } catch (FileBusyException busy) { 2025 continue; 2026 } 2027 } 2028 try { 2029 out.write(data); 2030 } finally { 2031 out.close(); 2032 } 2033 try { 2034 File.update(wait, false, wait, false); 2035 } catch (ArchiveBusyException mayHappen) { 2036 if (wait) 2045 throw new AssertionError (mayHappen); 2046 } 2047 } catch (Throwable exception) { 2048 failure = exception; 2049 } 2050 } 2051 } 2053 final WritingThread[] threads = new WritingThread[nThreads]; 2055 for (int i = 0; i < nThreads; i++) { 2056 final WritingThread thread = new WritingThread(i); 2057 thread.start(); 2058 threads[i] = thread; 2059 } 2060 2061 for (int i = 0; i < nThreads; i++) { 2063 final WritingThread thread = threads[i]; 2064 thread.join(); 2065 if (thread.failure != null) 2066 throw new Exception (thread.failure); 2067 } 2068 2069 checkArchiveEntries(archive, nThreads); 2070 assertTrue(archive.deleteAll()); 2071 } 2072 2073 public void testMultithreadedMultipleArchivesSingleEntryWriting() 2074 throws Exception { 2075 logger.fine("testMultithreadedMultipleArchivesSingleEntryWriting"); 2076 2077 testMultithreadedMultipleArchivesSingleEntryWriting(20, false); 2078 testMultithreadedMultipleArchivesSingleEntryWriting(20, true); 2079 } 2080 2081 private void testMultithreadedMultipleArchivesSingleEntryWriting( 2082 final int nThreads, final boolean updateIndividually) 2083 throws Exception { 2084 assertTrue(File.isLenient()); 2085 2086 class WritingThread extends Thread { 2087 Throwable failure; 2088 2089 public void run() { 2090 try { 2091 final File archive = new File(createTempFile(prefix, suffix)); 2092 assertTrue(archive.delete()); 2093 final File file = new File(archive, "entry"); 2094 try { 2095 final OutputStream out = new FileOutputStream(file); 2096 try { 2097 out.write(data); 2098 } finally { 2099 out.close(); 2100 } 2101 try { 2102 if (updateIndividually) 2103 File.update(archive); 2104 else 2105 File.update(false); 2106 } catch (ArchiveBusyException mayHappen) { 2107 if (updateIndividually) 2117 throw new AssertionError (mayHappen); 2118 } 2119 } finally { 2120 assertTrue(archive.deleteAll()); 2121 } 2122 } catch (Throwable exception) { 2123 failure = exception; 2124 } 2125 } 2126 } 2128 final WritingThread[] threads = new WritingThread[nThreads]; 2130 for (int i = 0; i < nThreads; i++) { 2131 final WritingThread thread = new WritingThread(); 2132 thread.start(); 2133 threads[i] = thread; 2134 } 2135 2136 for (int i = 0; i < nThreads; i++) { 2138 final WritingThread thread = threads[i]; 2139 thread.join(); 2140 if (thread.failure != null) 2141 throw new Exception (thread.failure); 2142 } 2143 } 2144 2145 private java.io.File createTempFile( 2146 String prefix, 2147 String suffix) 2148 throws IOException { 2149 return File.createTempFile(prefix, suffix, baseDir).getCanonicalFile(); 2150 } 2151} 2152 | Popular Tags |