001 /*
002 * Copyright 2010 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 pReceiver ) 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 pReceiver.onEachDir(entry.getName(), entry.getLinkName(), entry.getUserName(), entry.getUserId(), entry.getGroupName(), entry.getGroupId(), entry.getMode(), entry.getSize());
068 continue;
069 }
070 pReceiver.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 * TODO: replace by commons compress
083 *
084 * Guess the compression used by looking at the first bytes of the stream.
085 */
086 private InputStream getCompressedInputStream(InputStream in) throws IOException {
087
088 PushbackInputStream pin = new PushbackInputStream(in, 2);
089 byte[] header = new byte[2];
090 if (pin.read(header) != header.length) {
091 throw new IOException("Could not read header");
092 }
093
094 if (header[0] == (byte) 0x1f && header[1] == (byte) 0x8b) {
095 pin.unread(header);
096 return new GZIPInputStream(pin);
097 } else if (header[0] == 'B' && header[1] == 'Z') {
098 return new CBZip2InputStream(pin);
099 } else {
100 throw new IOException("Unsupported archive format : " + archive);
101 }
102 }
103
104 }