1 6 21 22 package de.schlichtherle.io; 23 24 import de.schlichtherle.io.archive.spi.*; 25 import de.schlichtherle.io.rof.*; 26 27 import java.io.*; 28 import java.util.*; 29 import java.util.logging.*; 30 31 48 final class UpdatingArchiveController extends GeneralArchiveController { 51 52 56 private static final String CLASS_NAME 57 = "de/schlichtherle/io/UpdatingArchiveController".replace('/', '.'); private static final Logger logger = Logger.getLogger(CLASS_NAME, CLASS_NAME); 59 60 61 static final String TEMP_FILE_PREFIX = "tzp-ctrl"; 62 63 67 static final String TEMP_FILE_SUFFIX = ".tmp"; 68 69 73 80 private java.io.File inFile; 81 82 86 private InputArchive inArchive; 87 88 92 private java.io.File outFile; 93 94 98 private OutputArchive outArchive; 99 100 104 private boolean needsReassembly; 105 106 110 UpdatingArchiveController( 111 java.io.File target, 112 ArchiveController enclController, 113 String enclEntryName, 114 ArchiveDriver driver) { 115 super(target, enclController, enclEntryName, driver); 116 } 117 118 122 protected void mount(final boolean autoCreate) 123 throws IOException { 124 assert writeLock().isLocked(); 125 assert inArchive == null; 126 assert outFile == null; 127 assert outArchive == null; 128 assert getFileSystem() == null; 129 130 logger.log(Level.FINER, "mount.entering", new Object [] { 133 getPath(), 134 Boolean.valueOf(autoCreate), 135 }); 136 try { 137 mount0(autoCreate); 138 } catch (IOException failure) { 139 assert writeLock().isLocked(); 140 assert inArchive == null; 141 assert outFile == null; 142 assert outArchive == null; 143 assert getFileSystem() == null; 144 145 logger.log(Level.FINER, "mount.throwing", failure); throw failure; 148 } 149 logger.log(Level.FINER, "mount.exiting"); 151 assert writeLock().isLocked(); 152 assert autoCreate || inArchive != null; 153 assert autoCreate || outFile == null; 154 assert autoCreate || outArchive == null; 155 assert getFileSystem() != null; 156 } 157 158 private void mount0(final boolean autoCreate) 159 throws IOException { 160 if (usesNativeTargetFile()) { 163 if (inFile == null) 167 inFile = getTarget(); 168 final long time = inFile.lastModified(); 169 if (time != 0) { 170 final boolean isReadOnly = !File.isWritableOrCreatable(inFile); 174 try { 175 initInArchive(inFile); 176 } catch (IOException failure) { 177 throw new FalsePositiveNativeException(failure); 180 } 181 setFileSystem(new ArchiveFileSystem( 182 this, inArchive, time, isReadOnly)); 183 } else if (!autoCreate) { 184 throw new ArchiveNotFoundException("may not create"); 187 } else { 188 ensureOutArchive(); setFileSystem(new ArchiveFileSystem(this)); 196 } 197 } else { 198 if (inFile == null) { 201 unwrap(getEnclController(), getEnclEntryName(), autoCreate); 202 } else { 203 try { 209 initInArchive(inFile); 210 } catch (IOException failure) { 211 assert false : "We should've never got here! Read the source code comments for the full details."; 226 throw new FalsePositiveFileEntryException( 227 getEnclController(), getEnclEntryName(), failure); 230 } 231 setFileSystem(new ArchiveFileSystem( 239 this, inArchive, inFile.lastModified(), false)); 240 } 241 } 242 } 243 244 private void unwrap( 245 final ArchiveController controller, 246 final String entryName, 247 final boolean autoCreate) 248 throws IOException { 249 assert controller != null; 250 assert entryName != null; 253 assert File.EMPTY != entryName; 254 assert inFile == null; 255 256 try { 257 final ReentrantLock lock = autoCreate 261 ? controller.writeLock() 262 : controller.readLock(); 263 controller.readLock().lock(); 264 if (controller.hasNewData(entryName) || autoCreate) { 265 controller.readLock().unlock(); 266 controller.runWriteLocked(new IORunnable() { 267 public void run() throws IOException { 268 if (controller.hasNewData(entryName)) 274 controller.update(); 275 276 lock.lock(); } 291 }); 292 } 293 try { 294 unwrapFromLockedController(controller, entryName, autoCreate); 295 } finally { 296 lock.unlock(); 297 } 298 } catch (FalsePositiveDirectoryEntryException failure) { 299 if (failure.getTarget() == controller) 305 throw failure; 307 unwrap( controller.getEnclController(), 308 controller.enclEntryName(entryName), 309 autoCreate); 310 } 311 } 312 313 private void unwrapFromLockedController( 314 final ArchiveController controller, 315 final String entryName, 316 final boolean autoCreate) 317 throws IOException { 318 assert controller != null; 319 assert controller.readLock().isLocked() || controller.writeLock().isLocked(); 320 assert entryName != null; 321 assert File.EMPTY != entryName; 322 assert inFile == null; 323 324 final ArchiveFileSystem controllerFileSystem; 325 try { 326 controllerFileSystem = controller.getFileSystem( 327 autoCreate && File.isLenient()); 328 } catch (FalsePositiveNativeException failure) { 329 throw (IOException) failure.getCause(); 332 } 333 if (controllerFileSystem.isFile(entryName)) { 334 final java.io.File tmp = File.createTempFile( 338 TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX); 339 try { 345 File.cp(controller.getInputStream(entryName), 347 new java.io.FileOutputStream (tmp)); 348 try { 352 initInArchive(tmp); 353 } catch (IOException failure) { 354 throw new FalsePositiveFileEntryException( 355 controller, entryName, failure); 356 } 357 setFileSystem(new ArchiveFileSystem(this, inArchive, 358 controllerFileSystem.lastModified(entryName), 359 controllerFileSystem.isReadOnly())); 360 inFile = tmp; } catch (Throwable failure) { 362 if (!tmp.delete()) { 371 final IOException ioe = new IOException( 373 tmp.getPath() 374 + " (couldn't delete corrupted input file)"); 375 ioe.initCause(failure); 376 throw ioe; 377 } 378 if (failure instanceof IOException) 379 throw (IOException) failure; 380 else if (failure instanceof RuntimeException ) 381 throw (RuntimeException ) failure; 382 else 383 throw (Error ) failure; } 385 } else if (controllerFileSystem.isDirectory(entryName)) { 386 throw new FalsePositiveDirectoryEntryException( 387 controller, entryName); 388 } else if (!autoCreate) { 389 throw new ArchiveNotFoundException("may not create"); 392 } else { 393 assert autoCreate; 394 assert controller.writeLock().isLocked(); 395 396 final ArchiveFileSystem.Delta delta 401 = controllerFileSystem.beginCreateAndLink( 402 entryName, File.isLenient()); 403 404 ensureOutArchive(); 408 409 try { 411 delta.commit(); 412 } catch (IOException failure) { 413 try { 416 try { 417 outArchive.close(); 418 } finally { 419 outArchive = null; 420 } 421 } finally { 422 boolean deleted = outFile.delete(); 423 assert deleted; 424 outFile = null; 425 } 426 427 throw failure; 428 } 429 430 setFileSystem(new ArchiveFileSystem(this)); 431 } 432 } 433 434 440 private void initInArchive(final java.io.File inFile) 441 throws IOException { 442 assert writeLock().isLocked(); 443 assert inArchive == null; 444 445 logger.log(Level.FINEST, "initInArchive.entering", inFile); try { 447 final ReadOnlyFile rof; 448 if (usesNativeTargetFile()) 449 rof = new CountingReadOnlyFile(inFile); 450 else 451 rof = new SimpleReadOnlyFile(inFile); 452 try { 453 inArchive = getDriver().createInputArchive(this, rof); 454 } catch (Throwable failure) { 455 rof.close(); 462 if (failure instanceof IOException) 463 throw (IOException) failure; 464 else if (failure instanceof RuntimeException ) 465 throw (RuntimeException ) failure; 466 else if (failure instanceof Error ) 467 throw (Error ) failure; 468 else 469 throw new AssertionError (failure); } 471 new InputArchiveMetaData(this, inArchive); 472 } catch (IOException failure) { 473 assert inArchive == null; 474 logger.log(Level.FINEST, "initInArchive.throwing", failure); throw failure; 476 } 477 logger.log(Level.FINEST, "initInArchive.exiting", new Integer (inArchive.getNumArchiveEntries())); 479 480 assert inArchive != null; 481 } 482 483 protected InputStream getInputStreamImpl( 484 final ArchiveEntry entry, 485 final ArchiveEntry dstEntry) 486 throws IOException { 487 assert readLock().isLocked() || writeLock().isLocked(); 488 assert !hasNewData(entry.getName()); 489 490 if (entry.isDirectory()) 491 throw new ArchiveEntryNotFoundException( 492 entry.getName(), "cannot read directory entry"); 493 494 final InputStream in = inArchive.getMetaData().getInputStream(entry, dstEntry); 495 if (in == null) { 496 throw new ArchiveEntryNotFoundException( 500 entry.getName(), "illegal access to archive file"); 501 } 502 return in; 503 } 504 505 protected OutputStream getOutputStreamImpl( 506 final ArchiveEntry entry, 507 final ArchiveEntry srcEntry) 508 throws IOException { 509 assert writeLock().isLocked(); 510 assert !hasNewData(entry.getName()); 511 512 ensureOutArchive(); 513 final OutputStream out = outArchive.getMetaData().getOutputStream(entry, srcEntry); 514 if (out == null) { 515 throw new ArchiveEntryNotFoundException( 518 entry.getName(), "archive driver bug: illegal null value returned"); 519 } 520 return out; 521 } 522 523 protected void touch() throws IOException { 524 assert writeLock().isLocked(); 525 ensureOutArchive(); 526 super.touch(); 527 } 528 529 private void ensureOutArchive() 530 throws IOException { 531 assert writeLock().isLocked(); 532 533 if (outArchive != null) 534 return; 535 536 java.io.File tmp = outFile; 537 if (tmp == null) { 538 if (usesNativeTargetFile() && !getTarget().isFile()) { 539 tmp = getTarget(); 540 } else { 541 tmp = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX); 543 } 549 } 550 551 try { 552 initOutArchive(tmp); 553 } catch (TransientIOException failure) { 554 throw failure.getTransientCause(); 558 } 559 outFile = tmp; } 561 562 570 private void initOutArchive(final java.io.File outFile) 571 throws IOException { 572 assert writeLock().isLocked(); 573 assert outArchive == null; 574 575 logger.log(Level.FINEST, "initOutArchive.entering", outFile); try { 577 OutputStream out = new java.io.FileOutputStream (outFile); 578 if (outFile == getTarget()) 581 out = new CountingOutputStream(out); 582 try { 583 outArchive = getDriver().createOutputArchive(this, out, inArchive); 584 } catch (Throwable failure) { 585 out.close(); 592 if (!outFile.delete()) { 593 final IOException ioe = new IOException(outFile.getPath() 600 + " (couldn't delete corrupted output file)"); 601 ioe.initCause(failure); 602 throw ioe; 603 } 604 if (failure instanceof IOException) 605 throw (IOException) failure; 606 else if (failure instanceof RuntimeException ) 607 throw (RuntimeException ) failure; 608 else if (failure instanceof Error ) 609 throw (Error ) failure; 610 else 611 throw new AssertionError (failure); } 613 new OutputArchiveMetaData(this, outArchive); 614 } catch (IOException failure) { 615 assert outArchive == null; 616 logger.log(Level.FINEST, "initOutArchive.throwing", failure); throw failure; 618 } 619 logger.log(Level.FINEST, "initOutArchive.exiting"); 621 assert outArchive != null; 622 } 623 624 protected boolean hasNewData(String entryName) { 625 assert readLock().isLocked() || writeLock().isLocked(); 626 return outArchive != null && outArchive.getArchiveEntry(entryName) != null; 627 } 628 629 protected void update( 630 final ArchiveException exceptionChain, 631 final boolean waitInputStreams, 632 final boolean closeInputStreams, 633 final boolean waitOutputStreams, 634 final boolean closeOutputStreams, 635 final boolean umount, 636 final boolean reassemble) 637 throws ArchiveException { 638 assert closeInputStreams || !closeOutputStreams; assert !umount || reassemble; assert writeLock().isLocked(); 641 assert inArchive == null || inFile != null; assert !isTouched() || outArchive != null; assert outArchive == null || outFile != null; 645 logger.log(Level.FINER, "update.entering", new Object [] { 648 getPath(), 649 exceptionChain, 650 Boolean.valueOf(waitInputStreams), 651 Boolean.valueOf(closeInputStreams), 652 Boolean.valueOf(waitOutputStreams), 653 Boolean.valueOf(closeOutputStreams), 654 Boolean.valueOf(umount), 655 Boolean.valueOf(reassemble), 656 }); 657 try { 658 update0(exceptionChain, 659 waitInputStreams, closeInputStreams, 660 waitOutputStreams, closeOutputStreams, 661 umount, reassemble); 662 } catch (ArchiveException failure) { 663 logger.log(Level.FINER, "update.throwing", failure); throw failure; 665 } 666 logger.log(Level.FINER, "update.exiting"); } 668 669 private void update0( 670 final ArchiveException exceptionChain, 671 final boolean waitInputStreams, 672 final boolean closeInputStreams, 673 final boolean waitOutputStreams, 674 final boolean closeOutputStreams, 675 final boolean umount, 676 final boolean reassemble) 677 throws ArchiveException { 678 ArchiveException newExceptionChain = exceptionChain; 679 680 if (outArchive != null) { 685 final OutputArchiveMetaData outMetaData = outArchive.getMetaData(); 686 final int outStreams = outMetaData.waitAllOutputStreamsByOtherThreads( 687 waitOutputStreams ? 0 : 50); 688 if (outStreams > 0) { 689 if (!closeOutputStreams) 690 throw new ArchiveOutputBusyException( 691 newExceptionChain, getPath(), outStreams); 692 newExceptionChain = new ArchiveOutputBusyWarningException( 693 newExceptionChain, getPath(), outStreams); 694 } 695 } 696 if (inArchive != null) { 697 final InputArchiveMetaData inMetaData = inArchive.getMetaData(); 698 final int inStreams = inMetaData.waitAllInputStreamsByOtherThreads( 699 waitInputStreams ? 0 : 50); 700 if (inStreams > 0) { 701 if (!closeInputStreams) 702 throw new ArchiveInputBusyException( 703 newExceptionChain, getPath(), inStreams); 704 newExceptionChain = new ArchiveInputBusyWarningException( 705 newExceptionChain, getPath(), inStreams); 706 } 707 } 708 709 try { 710 if (isTouched()) { 711 needsReassembly = true; 712 try { 713 newExceptionChain = updateOutArchive(newExceptionChain); 714 assert getFileSystem() == null; 715 assert inArchive == null; 716 } finally { 717 assert outArchive == null; 718 } 719 try { 720 if (reassemble) { 721 newExceptionChain = reassembleTargetFile(newExceptionChain); 722 needsReassembly = false; 723 } 724 } finally { 725 shutdownStep3(umount && !needsReassembly); 726 } 727 } else if (reassemble && needsReassembly) { 728 assert outFile == null; assert inFile != null; shutdownStep2(newExceptionChain); 734 outFile = inFile; 735 inFile = null; 736 try { 737 newExceptionChain = reassembleTargetFile(newExceptionChain); 738 needsReassembly = false; 739 } finally { 740 shutdownStep3(umount && !needsReassembly); 741 } 742 } else if (umount) { 743 assert reassemble; 744 assert !needsReassembly; 745 shutdownStep2(newExceptionChain); 746 shutdownStep3(true); 747 } else { 748 assert outArchive == null; 752 } 753 } catch (IOException failure) { 754 throw new ArchiveException(newExceptionChain, failure); 755 } finally { 756 setScheduled(needsReassembly); 757 } 758 759 if (newExceptionChain != exceptionChain) 760 throw newExceptionChain; 761 } 762 763 protected final int waitAllInputStreamsByOtherThreads(long timeout) { 764 return inArchive != null 765 ? inArchive.getMetaData().waitAllInputStreamsByOtherThreads(timeout) 766 : 0; 767 } 768 769 protected final int waitAllOutputStreamsByOtherThreads(long timeout) { 770 return outArchive != null 771 ? outArchive.getMetaData().waitAllOutputStreamsByOtherThreads(timeout) 772 : 0; 773 } 774 775 795 private ArchiveException updateOutArchive( 796 ArchiveException exceptionChain) 797 throws ArchiveException { 798 assert writeLock().isLocked(); 799 assert isTouched(); 800 assert outArchive != null; 801 assert getFileSystem() != null; 802 assert checkNoDeletedEntriesWithNewData(exceptionChain) == exceptionChain; 803 804 final long rootTime; 805 try { 806 try { 807 try { 808 exceptionChain = shutdownStep1(exceptionChain); 809 810 ArchiveWarningException inputEntryCorrupted = null; 811 ArchiveWarningException outputEntryCorrupted = null; 812 813 final Enumeration e = getFileSystem().getReversedEntries(); 822 while (e.hasMoreElements()) { 823 final ArchiveEntry entry = (ArchiveEntry) e.nextElement(); 824 final String name = entry.getName(); 825 if (hasNewData(name)) 826 continue; if (entry.isDirectory()) { 828 if (name.equals(ArchiveFileSystem.ROOT)) 829 continue; if (entry.getTime() < 0) 831 continue; outArchive.storeDirectory(entry); 836 } else if (inArchive != null && inArchive.getArchiveEntry(name) != null) { 837 assert entry == inArchive.getArchiveEntry(name); 838 InputStream in; 839 try { 840 in = inArchive.getInputStream(entry, entry); 841 } catch (IOException failure) { 842 if (inputEntryCorrupted == null) { 843 exceptionChain = inputEntryCorrupted 844 = new ArchiveWarningException( 845 exceptionChain, 846 getPath() 847 + " (skipped one or more corrupted archive entries from the input)", 848 failure); 849 } 850 continue; 851 } 852 try { 853 final OutputStream out = outArchive 857 .getOutputStream(entry, entry); 858 try { 859 File.cat(in, out); 860 } catch (InputIOException failure) { 861 if (outputEntryCorrupted == null) { 862 exceptionChain = outputEntryCorrupted 863 = new ArchiveWarningException( 864 exceptionChain, 865 getPath() 866 + " (one or more archive entries in the output may be corrupted)", 867 failure); 868 } 869 } finally { 870 out.close(); 871 } 872 } finally { 873 in.close(); 874 } 875 } else { 876 outArchive.getOutputStream(entry, null).close(); 883 } 884 } } finally { 886 rootTime = getFileSystem().lastModified(ArchiveFileSystem.ROOT); 893 shutdownStep2(exceptionChain); 894 } 895 } catch (IOException failure) { 896 boolean deleted = outFile.delete(); 906 outFile = null; 907 assert deleted; 908 throw failure; 909 } 910 } catch (ArchiveException failure) { 911 throw failure; 912 } catch (IOException failure) { 913 throw new ArchiveException( 914 exceptionChain, 915 getPath() 916 + " (could not update archive file - all changes are lost)", 917 failure); 918 } 919 920 if (!outFile.setLastModified(rootTime)) { 924 exceptionChain = new ArchiveWarningException( 925 exceptionChain, 926 getPath() 927 + " (couldn't preserve last modification time)"); 928 } 929 930 return exceptionChain; 931 } 932 933 private ArchiveException checkNoDeletedEntriesWithNewData( 934 ArchiveException exceptionChain) { 935 assert isTouched(); 936 assert getFileSystem() != null; 937 938 final Enumeration e = outArchive.getArchiveEntries(); 942 while (e.hasMoreElements()) { 943 final String name = ((ArchiveEntry) e.nextElement()).getName(); 944 if (getFileSystem().get(name) == null) { 945 exceptionChain = new ArchiveWarningException( 949 exceptionChain, 950 getPath() 951 + " (couldn't remove archive entry: " 952 + name + ")"); 953 } 954 } 955 956 return exceptionChain; 957 } 958 959 987 private ArchiveException reassembleTargetFile( 988 ArchiveException exceptionChain) 989 throws ArchiveException { 990 assert writeLock().isLocked(); 991 992 if (usesNativeTargetFile()) { 993 if (outFile != getTarget()) { 996 try { 1002 final OutputStream out = new CountingOutputStream( 1003 new java.io.FileOutputStream (getTarget())); 1004 final InputStream in; 1005 try { 1006 in = new java.io.FileInputStream (outFile); 1007 } catch (IOException failure) { 1008 out.close(); 1009 throw failure; 1010 } 1011 File.cp(in , out); } catch (IOException cause) { 1013 throw new ArchiveException( 1014 exceptionChain, 1015 getPath() 1016 + " (could not reassemble archive file - all changes are lost)", 1017 cause); 1018 } 1019 1020 final long time = outFile.lastModified(); 1025 if (time != 0 && !getTarget().setLastModified(time)) { 1026 exceptionChain = new ArchiveWarningException( 1027 exceptionChain, 1028 getPath() 1029 + " (couldn't preserve last modification time)"); 1030 } 1031 } 1032 } else { 1033 try { 1036 wrap(getEnclController(), getEnclEntryName()); 1037 } catch (IOException cause) { 1038 throw new ArchiveException( 1039 exceptionChain, 1040 getEnclController().getPath() + "/" + getEnclEntryName() 1041 + " (could not update archive entry - all changes are lost)", 1042 cause); 1043 } 1044 } 1045 1046 return exceptionChain; 1047 } 1048 1049 private void wrap( 1050 final ArchiveController controller, 1051 final String entryName) 1052 throws IOException { 1053 assert writeLock().isLocked(); 1054 assert controller != null; 1055 assert entryName != null; 1058 assert File.EMPTY != entryName; 1059 1060 controller.runWriteLocked(new IORunnable() { 1061 public void run() throws IOException { 1062 wrapToWriteLockedController(controller, entryName); 1063 } 1064 }); 1065 } 1066 1067 private void wrapToWriteLockedController( 1068 final ArchiveController controller, 1069 final String entryName) 1070 throws IOException { 1071 assert controller != null; 1072 assert controller.writeLock().isLocked(); 1073 assert entryName != null; 1074 assert File.EMPTY != entryName; 1075 1076 final InputStream in = new java.io.FileInputStream (outFile); 1081 try { 1082 cp( outFile, in, 1086 null , controller, entryName, 1087 true); 1088 } finally { 1089 in.close(); 1090 } 1091 } 1092 1093 1101 protected void reset() throws IOException { 1102 assert writeLock().isLocked(); 1103 1104 ArchiveException exceptionChain = shutdownStep1(null); 1105 shutdownStep2(exceptionChain); 1106 shutdownStep3(true); 1107 setScheduled(false); 1108 1109 if (exceptionChain != null) 1110 throw exceptionChain; 1111 } 1112 1113 protected void finalize() 1114 throws Throwable { 1115 logger.log(Level.FINEST, "finalize.entering", getPath()); if (isTouched()) 1126 logger.log(Level.SEVERE, "finalize.hasUpdatedEntries", getPath()); 1127 shutdownStep1(null); 1128 shutdownStep2(null); 1129 shutdownStep3(true); 1130 super.finalize(); 1131 } 1132 1133 1137 private ArchiveException shutdownStep1(ArchiveException exceptionChain) { 1138 if (outArchive != null) 1139 exceptionChain = outArchive.getMetaData().closeAllStreams( 1140 exceptionChain); 1141 if (inArchive != null) 1142 exceptionChain = inArchive.getMetaData().closeAllStreams( 1143 exceptionChain); 1144 1145 return exceptionChain; 1146 } 1147 1148 1151 private void shutdownStep2(ArchiveException exceptionChain) 1152 throws IOException { 1153 final ArchiveException oldExceptionChain = exceptionChain; 1154 1155 super.reset(); 1157 if (outArchive != null) { 1165 try { 1166 outArchive.close(); 1167 } catch (IOException failure) { 1168 exceptionChain = new ArchiveException(exceptionChain, failure); 1169 } finally { 1170 outArchive = null; 1171 } 1172 } 1173 1174 if (inArchive != null) { 1175 try { 1176 inArchive.close(); 1177 } catch (IOException failure) { 1178 exceptionChain = new ArchiveException(exceptionChain, failure); 1179 } finally { 1180 inArchive = null; 1181 } 1182 } 1183 1184 if (exceptionChain != oldExceptionChain) 1185 throw exceptionChain; 1186 } 1187 1188 1196 private void shutdownStep3(final boolean deleteOutFile) { 1197 if (inFile != null) { 1198 if (inFile != getTarget()) { 1199 boolean deleted = inFile.delete(); 1200 assert deleted; 1201 } 1202 inFile = null; 1203 } 1204 1205 if (outFile != null) { 1206 if (deleteOutFile) { 1207 if (outFile != getTarget()) { 1208 boolean deleted = outFile.delete(); 1209 assert deleted; 1210 } 1211 } else { 1212 assert outFile.isFile(); 1214 inFile = outFile; 1215 } 1216 outFile = null; 1217 } 1218 1219 if (deleteOutFile) 1220 needsReassembly = false; 1221 } 1222} 1223 | Popular Tags |