001 /*
002 * Copyright 2005 The Apache Software Foundation.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.vafer.jdeb.producers;
017
018 import java.io.File;
019 import java.io.FileInputStream;
020 import java.io.IOException;
021 import java.io.InputStream;
022 import java.io.PushbackInputStream;
023 import java.util.zip.GZIPInputStream;
024
025 import org.apache.tools.bzip2.CBZip2InputStream;
026 import org.apache.tools.tar.TarEntry;
027 import org.apache.tools.tar.TarInputStream;
028 import org.vafer.jdeb.DataConsumer;
029 import org.vafer.jdeb.DataProducer;
030 import org.vafer.jdeb.mapping.Mapper;
031
032 /**
033 * Providing data from an archive keeping permissions and ownerships.
034 *
035 * @author Torsten Curdt <tcurdt@vafer.org>
036 */
037 public final class DataProducerArchive extends AbstractDataProducer implements DataProducer {
038
039 private final File archive;
040
041 public DataProducerArchive( final File pArchive, final String[] pIncludes, final String[] pExcludes, final Mapper[] pMappers ) {
042 super(pIncludes, pExcludes, pMappers);
043 archive = pArchive;
044 }
045
046 public void produce( final DataConsumer receiver ) throws IOException {
047
048 TarInputStream archiveInputStream = null;
049 try {
050 archiveInputStream = new TarInputStream(getCompressedInputStream(new FileInputStream(archive)));
051
052 while(true) {
053
054 TarEntry entry = archiveInputStream.getNextEntry();
055
056 if (entry == null) {
057 break;
058 }
059
060 if (!isIncluded(entry.getName())) {
061 continue;
062 }
063
064 entry = map(entry);
065
066 if (entry.isDirectory()) {
067 receiver.onEachDir(entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize());
068 continue;
069 }
070 receiver.onEachFile(archiveInputStream, entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize());
071 }
072
073 } finally {
074 if (archiveInputStream != null) {
075 archiveInputStream.close();
076 }
077 }
078 }
079
080
081 /**
082 * Guess the compression used by looking at the first bytes of the stream.
083 */
084 private InputStream getCompressedInputStream(InputStream in) throws IOException {
085 PushbackInputStream pin = new PushbackInputStream(in, 2);
086 byte[] header = new byte[2];
087 if (pin.read(header) != header.length) {
088 throw new IOException("Could not read header");
089 }
090
091 if (header[0] == (byte) 0x1f && header[1] == (byte) 0x8b) {
092 pin.unread(header);
093 return new GZIPInputStream(pin);
094 } else if (header[0] == 'B' && header[1] == 'Z') {
095 return new CBZip2InputStream(pin);
096 } else {
097 throw new IOException("Unsupported archive format : " + archive);
098 }
099 }
100
101 }