1 6 21 22 package de.schlichtherle.io.archive.tar; 23 24 import de.schlichtherle.io.*; 25 import de.schlichtherle.io.archive.*; 26 import de.schlichtherle.io.archive.spi.*; 27 import de.schlichtherle.io.util.*; 28 29 import java.io.*; 30 import java.io.File ; 31 import java.io.FileInputStream ; 32 import java.io.FileOutputStream ; 33 import java.util.*; 34 import java.util.zip.*; 35 36 import org.apache.tools.tar.*; 37 38 53 public class TarInputArchive implements InputArchive, TarConstants { 54 55 56 static final String TEMP_FILE_PREFIX = "tzp-tar"; 57 58 private static final byte[] NULL_RECORD = new byte[TarBuffer.DEFAULT_RCDSIZE]; 59 60 private static final int CHECKSUM_OFFSET 61 = NAMELEN + MODELEN + UIDLEN + GIDLEN + SIZELEN + MODTIMELEN; 62 63 66 private final Map entries = new HashMap(); 67 68 private InputArchiveMetaData metaData; 69 70 81 public TarInputArchive(final Archive archive, final InputStream in) 82 throws IOException { 83 final TarInputStream tin = createValidatedTarInputStream(in); 84 try { 85 org.apache.tools.tar.TarEntry tinEntry; 86 while ((tinEntry = tin.getNextEntry()) != null) { 87 final File tmp; 88 try { 89 tmp = File.createTempFile(TEMP_FILE_PREFIX, null); 90 } catch (IOException ex) { 91 throw new TransientIOException( 92 new TempFileException(archive, tinEntry, ex)); 93 } 94 boolean ok = tmp.delete(); 95 assert ok; 96 if (tinEntry.isDirectory()) { 97 ok = tmp.mkdirs(); 98 } else { 99 final FileOutputStream out = new FileOutputStream (tmp); 100 try { 101 de.schlichtherle.io.File.cat(tin, out); } finally { 103 out.close(); 104 } 105 } 106 if (!tmp.setLastModified(tinEntry.getModTime().getTime())) 107 throw new TransientIOException( 108 new TempFileException( 109 archive, tinEntry, tmp, 110 "could not set last modification time")); 111 final TarEntry entry = new TarEntry(tmp); 112 entry.setName(Paths.normalize(tinEntry.getName(), '/')); 113 entries.put(entry.getName(), entry); 114 } 115 } catch (IOException failure) { 116 closeImpl(); 117 throw failure; 118 } 119 } 120 121 128 private static TarInputStream createValidatedTarInputStream( 129 final InputStream in) 130 throws IOException { 131 final byte[] buf = new byte[TarBuffer.DEFAULT_RCDSIZE]; 132 final InputStream vin = readAhead(in, buf); 133 if (!Arrays.equals(buf, NULL_RECORD)) { 136 final long expected = TarUtils.parseOctal(buf, CHECKSUM_OFFSET, 8); 137 for (int i = 0; i < 8; i++) 138 buf[CHECKSUM_OFFSET + i] = ' '; 139 final long is = TarUtils.computeCheckSum(buf); 140 if (expected != is) 141 throw new IOException( 142 "Illegal initial record in TAR file: Expected checksum " + expected + ", is " + is + "!"); 143 } 144 return new TarInputStream( 145 vin, TarBuffer.DEFAULT_BLKSIZE, TarBuffer.DEFAULT_RCDSIZE); 146 } 147 148 158 static InputStream readAhead(final InputStream in, final byte[] buf) 159 throws IOException { 160 if (!(in instanceof InflaterInputStream) && in.markSupported()) { 165 in.mark(buf.length); 166 readFully(in, buf); 167 in.reset(); 168 return in; 169 } else { 170 final PushbackInputStream pin 171 = new PushbackInputStream(in, buf.length); 172 readFully(pin, buf); 173 pin.unread(buf); 174 return pin; 175 } 176 } 177 178 private static void readFully(final InputStream in, final byte[] buf) 179 throws IOException { 180 final int l = buf.length; 181 int n = 0; 182 do { 183 final int r = in.read(buf, n, l - n); 184 if (r == -1) 185 throw new EOFException(); 186 n += r; 187 } while (n < l); 188 } 189 190 public int getNumArchiveEntries() { 191 return entries.size(); 192 } 193 194 public Enumeration getArchiveEntries() { 195 return Collections.enumeration(entries.values()); 196 } 197 198 public ArchiveEntry getArchiveEntry(String name) { 199 return (TarEntry) entries.get(name); 200 } 201 202 public InputStream getInputStream( 203 final ArchiveEntry entry, 204 final ArchiveEntry dstEntry) 205 throws IOException { 206 return new FileInputStream (((TarEntry) entry).getFile()); 207 } 208 209 public void close() throws IOException { 210 closeImpl(); 211 } 212 213 private void closeImpl() throws IOException { 214 final Enumeration e = Collections.enumeration(entries.values()); 215 while (e.hasMoreElements()) { 216 final TarEntry entry = (TarEntry) e.nextElement(); 217 final File file = entry.getFile(); 218 if (file.exists() && !file.delete()) { 219 file.deleteOnExit(); 221 } 222 } 223 } 224 225 229 public InputArchiveMetaData getMetaData() { 230 return metaData; 231 } 232 233 public void setMetaData(InputArchiveMetaData metaData) { 234 this.metaData = metaData; 235 } 236 237 241 245 private static final class TempFileException extends FileNotFoundException { 246 private final Archive archive; 247 private final org.apache.tools.tar.TarEntry entry; 248 private final File tmp; 249 250 public TempFileException( 251 final Archive archive, 252 final org.apache.tools.tar.TarEntry entry, 253 final File tmp, 254 final String msg) { 255 this(archive, entry, tmp, msg, null); 256 } 257 258 public TempFileException( 259 final Archive archive, 260 final org.apache.tools.tar.TarEntry entry, 261 final IOException cause) { 262 this(archive, entry, null, null, cause); 263 } 264 265 private TempFileException( 266 final Archive archive, 267 final org.apache.tools.tar.TarEntry entry, 268 final File tmp, 269 final String msg, 270 final IOException cause) { 271 super(msg); 272 initCause(cause); 273 this.archive = archive; 274 this.entry = entry; 275 this.tmp = tmp; 276 } 277 278 public String getMessage() { 279 String msg = super.getMessage(); 280 if (tmp != null) 281 msg += " for \"" + tmp.getPath() + "\""; 282 msg += " (temp file for entry \"" + entry.getName() 283 + "\" in archive file \"" + archive.getPath() + "\")"; 284 return msg; 285 } 286 } 287 } 288 | Popular Tags |