001/* 002 * Copyright 2007-2018 The jdeb developers. 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 */ 016package org.vafer.jdeb.producers; 017 018import java.io.BufferedInputStream; 019import java.io.File; 020import java.io.FileInputStream; 021import java.io.IOException; 022import java.io.InputStream; 023 024import org.apache.commons.compress.archivers.ArchiveEntry; 025import org.apache.commons.compress.archivers.ArchiveException; 026import org.apache.commons.compress.archivers.ArchiveInputStream; 027import org.apache.commons.compress.archivers.ArchiveStreamFactory; 028import org.apache.commons.compress.archivers.tar.TarArchiveEntry; 029import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; 030import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; 031import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream; 032import org.apache.commons.compress.compressors.CompressorException; 033import org.apache.commons.compress.compressors.CompressorInputStream; 034import org.apache.commons.compress.compressors.CompressorStreamFactory; 035import org.vafer.jdeb.DataConsumer; 036import org.vafer.jdeb.DataProducer; 037import org.vafer.jdeb.mapping.Mapper; 038 039/** 040 * Providing data from an archive keeping permissions and ownerships. 041 */ 042public final class DataProducerArchive extends AbstractDataProducer implements DataProducer { 043 044 private final File archive; 045 046 public DataProducerArchive( final File pArchive, final String[] pIncludes, final String[] pExcludes, final Mapper[] pMappers ) { 047 super(pIncludes, pExcludes, pMappers); 048 archive = pArchive; 049 } 050 051 public void produce( final DataConsumer pReceiver ) throws IOException { 052 053 InputStream is = new BufferedInputStream(new FileInputStream(archive)); 054 055 CompressorInputStream compressorInputStream = null; 056 057 try { 058 compressorInputStream = new CompressorStreamFactory().createCompressorInputStream(is); 059 } catch (CompressorException e) { 060 // expected if the input file is a zip archive 061 } 062 063 if (compressorInputStream != null) { 064 is = new BufferedInputStream(compressorInputStream); 065 } 066 067 ArchiveInputStream archiveInputStream = null; 068 069 try { 070 archiveInputStream = new ArchiveStreamFactory().createArchiveInputStream(is); 071 } catch (ArchiveException e) { 072 throw new IOException("Unsupported archive format: " + archive, e); 073 } 074 075 EntryConverter converter = null; 076 077 if (archiveInputStream instanceof TarArchiveInputStream) { 078 079 converter = new EntryConverter() { 080 public TarArchiveEntry convert( ArchiveEntry entry ) { 081 return (TarArchiveEntry) entry; 082 } 083 }; 084 085 } else if (archiveInputStream instanceof ZipArchiveInputStream) { 086 087 converter = new EntryConverter() { 088 public TarArchiveEntry convert( ArchiveEntry entry ) { 089 ZipArchiveEntry src = (ZipArchiveEntry) entry; 090 final TarArchiveEntry dst = new TarArchiveEntry(src.getName(), true); 091 //TODO: if (src.isUnixSymlink()) { 092 //} 093 094 dst.setSize(src.getSize()); 095 dst.setMode(src.getUnixMode()); 096 dst.setModTime(src.getTime()); 097 098 return dst; 099 } 100 }; 101 102 } else { 103 throw new IOException("Unsupported archive format: " + archive); 104 } 105 106 107 try { 108 while (true) { 109 110 ArchiveEntry archiveEntry = archiveInputStream.getNextEntry(); 111 112 if (archiveEntry == null) { 113 break; 114 } 115 116 if (!isIncluded(archiveEntry.getName())) { 117 continue; 118 } 119 120 TarArchiveEntry entry = converter.convert(archiveEntry); 121 122 entry = map(entry); 123 124 if (entry.isSymbolicLink()) { 125 pReceiver.onEachLink(entry); 126 continue; 127 } 128 129 if (entry.isDirectory()) { 130 pReceiver.onEachDir(entry); 131 continue; 132 } 133 134 pReceiver.onEachFile(archiveInputStream, entry); 135 } 136 137 } finally { 138 if (archiveInputStream != null) { 139 archiveInputStream.close(); 140 } 141 } 142 } 143 144 private interface EntryConverter { 145 public TarArchiveEntry convert( ArchiveEntry entry ); 146 } 147}