1 6 21 22 package de.schlichtherle.io.archive.tar; 23 24 import de.schlichtherle.io.ChainableIOException; 25 import de.schlichtherle.io.InputIOException; 26 import de.schlichtherle.io.OutputArchiveMetaData; 27 import de.schlichtherle.io.archive.spi.ArchiveEntry; 28 import de.schlichtherle.io.archive.spi.OutputArchive; 29 import de.schlichtherle.io.archive.spi.OutputArchiveBusyException; 30 31 import java.io.File ; 32 import java.io.FileInputStream ; 33 import java.io.FileNotFoundException ; 34 import java.io.FileOutputStream ; 35 import java.io.FilterOutputStream ; 36 import java.io.IOException ; 37 import java.io.InputStream ; 38 import java.io.OutputStream ; 39 import java.util.Collections ; 40 import java.util.Enumeration ; 41 import java.util.HashMap ; 42 import java.util.Iterator ; 43 import java.util.Map ; 44 45 import org.apache.tools.tar.TarOutputStream; 46 47 57 public class TarOutputArchive 58 extends TarOutputStream 59 implements OutputArchive { 60 61 64 private final Map entries = new HashMap (); 65 66 private boolean busy; 67 68 private final Map temps = new HashMap (); 69 70 private OutputArchiveMetaData metaData; 71 72 public TarOutputArchive(OutputStream out) { 73 super(out); 74 } 75 76 public int getNumArchiveEntries() { 77 return entries.size(); 78 } 79 80 public Enumeration getArchiveEntries() { 81 return Collections.enumeration(entries.values()); 82 } 83 84 public ArchiveEntry getArchiveEntry(String name) { 85 return (TarEntry) entries.get(name); 86 } 87 88 public OutputStream getOutputStream( 89 final ArchiveEntry entry, 90 final ArchiveEntry srcEntry) 91 throws IOException { 92 final TarEntry tarEntry = (TarEntry) entry; 93 if (srcEntry instanceof TarEntry) 94 tarEntry.setSize(((TarEntry) srcEntry).getSize()); 95 96 return createEntryOutputStream(tarEntry, srcEntry); 97 } 98 99 protected boolean busy() { 100 return busy; 101 } 102 103 protected OutputStream createEntryOutputStream( 104 final TarEntry entry, 105 final ArchiveEntry srcEntry) 106 throws IOException { 107 if (srcEntry instanceof TarEntry && !busy()) { return new EntryOutputStream(entry); 109 } else { 110 final File temp = File.createTempFile("tar", null); 111 return new EntryTempOutputStream(entry, temp); 112 } 113 } 114 115 122 protected class EntryOutputStream extends FilterOutputStream { 123 124 private boolean closed; 125 126 public EntryOutputStream(TarEntry entry) 127 throws IOException { 128 super(TarOutputArchive.this); 129 assert !busy(); 130 putNextEntry(entry); 131 busy = true; 132 entries.put(entry.getName(), entry); 133 } 134 135 public void write(int b) throws IOException { 136 out.write(b); 137 } 138 139 public void write(byte[] b) throws IOException { 140 out.write(b); 141 } 142 143 public void write(byte[] b, int off, int len) throws IOException { 144 out.write(b, off, len); 145 } 146 147 public void close() throws IOException { 148 if (closed) 149 return; 150 151 closed = true; 153 busy = false; 154 closeEntry(); 155 storeAllRemainingTempEntries(); 156 } 157 } 158 159 165 protected class EntryTempOutputStream extends FileOutputStream { 166 167 private final TarEntry entry; 168 private final File temp; 169 private boolean closed; 170 171 public EntryTempOutputStream( 172 final TarEntry entry, 173 final File temp) 174 throws IOException { 175 super(temp); 176 this.entry = entry; 177 this.temp = temp; 178 entries.put(entry.getName(), entry); 179 } 180 181 public void close() throws IOException { 182 if (closed) 186 return; 187 188 closed = true; 190 super.close(); 191 temps.put(entry, temp); 192 if (!busy()) 193 storeAllRemainingTempEntries(); 194 } 195 } 196 197 private void storeAllRemainingTempEntries() 198 throws IOException { 199 ChainableIOException exception = null; 200 201 for (Iterator it = temps.entrySet().iterator(); it.hasNext();) { 202 final Map.Entry elem = (Map.Entry ) it.next(); 203 final TarEntry entry = (TarEntry) elem.getKey(); 204 final File temp = (File ) elem.getValue(); 205 try { 206 storeTempEntry(entry, temp); 207 } catch (FileNotFoundException failure) { 208 exception = new ChainableIOException(exception, failure); 210 } catch (InputIOException failure) { 211 exception = new ChainableIOException(exception, failure); 213 } catch (IOException failure) { 214 throw new ChainableIOException(exception, failure); 216 } finally { 217 it.remove(); 224 } 225 } 226 227 if (exception != null) 228 throw exception.sortPriority(); 229 230 assert temps.isEmpty(); 231 } 232 233 private void storeTempEntry(final TarEntry entry, final File temp) 234 throws IOException { 235 assert !busy(); 236 237 try { 238 final InputStream in = new FileInputStream (temp); 239 try { 240 entry.setSize(temp.length()); 241 putNextEntry(entry); 242 try { 243 de.schlichtherle.io.File.cat(in, this); 245 } finally { 246 closeEntry(); 247 } 248 } finally { 249 in.close(); 250 } 251 } finally { 252 if (!temp.delete()) temp.deleteOnExit(); } 255 } 256 257 public void storeDirectory(ArchiveEntry entry) 258 throws IOException { 259 assert entry.isDirectory(); 260 final TarEntry te = (TarEntry) entry; 261 te.setSize(0); 262 263 putNextEntry(te); 265 entries.put(te.getName(), te); 266 closeEntry(); 267 } 268 269 public void close() throws IOException { 270 try { 271 super.close(); 272 } finally { 273 deleteAllRemainingTempEntries(); 274 } 275 } 276 277 private void deleteAllRemainingTempEntries() 278 throws IOException { 279 for (Iterator it = temps.entrySet().iterator(); it.hasNext();) { 280 final Map.Entry elem = (Map.Entry ) it.next(); 281 final File temp = (File ) elem.getValue(); 282 if (!temp.delete()) temp.deleteOnExit(); it.remove(); 285 } 286 assert temps.isEmpty(); 287 } 288 289 293 public OutputArchiveMetaData getMetaData() { 294 return metaData; 295 } 296 297 public void setMetaData(OutputArchiveMetaData metaData) { 298 this.metaData = metaData; 299 } 300 } 301 | Popular Tags |