001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.vfs.provider.tar;
018:
019: //TODO: Revert to [compress]
020: //import org.apache.commons.compress.tar.TarEntry;
021: //import org.apache.commons.compress.tar.TarInputStream;
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.apache.commons.vfs.FileName;
025: import org.apache.commons.vfs.FileObject;
026: import org.apache.commons.vfs.FileSystem;
027: import org.apache.commons.vfs.FileSystemException;
028: import org.apache.commons.vfs.FileSystemOptions;
029: import org.apache.commons.vfs.Selectors;
030: import org.apache.commons.vfs.VfsLog;
031: import org.apache.commons.vfs.provider.AbstractFileSystem;
032: import org.apache.commons.vfs.provider.UriParser;
033: import org.apache.commons.vfs.provider.bzip2.Bzip2FileObject;
034:
035: import java.io.File;
036: import java.io.FileInputStream;
037: import java.io.IOException;
038: import java.io.InputStream;
039: import java.util.ArrayList;
040: import java.util.Collection;
041: import java.util.List;
042: import java.util.zip.GZIPInputStream;
043:
044: /**
045: * A read-only file system for Tar files.
046: *
047: * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
048: * @version $Revision: 484648 $ $Date: 2006-12-08 08:18:36 -0800 (Fri, 08 Dec 2006) $
049: */
050: public class TarFileSystem extends AbstractFileSystem implements
051: FileSystem {
052: private final static Log log = LogFactory
053: .getLog(TarFileSystem.class);
054:
055: private final File file;
056: private TarInputStream tarFile;
057:
058: protected TarFileSystem(final FileName rootName,
059: final FileObject parentLayer,
060: final FileSystemOptions fileSystemOptions)
061: throws FileSystemException {
062: super (rootName, parentLayer, fileSystemOptions);
063:
064: // Make a local copy of the file
065: file = parentLayer.getFileSystem().replicateFile(parentLayer,
066: Selectors.SELECT_SELF);
067:
068: // Open the Tar file
069: if (!file.exists()) {
070: // Don't need to do anything
071: tarFile = null;
072: return;
073: }
074:
075: // tarFile = createTarFile(this.file);
076: }
077:
078: public void init() throws FileSystemException {
079: super .init();
080:
081: // Build the index
082: try {
083: List strongRef = new ArrayList(100);
084: TarEntry entry;
085: while ((entry = getTarFile().getNextEntry()) != null) {
086: FileName name = getFileSystemManager().resolveName(
087: getRootName(),
088: UriParser.encode(entry.getName()));
089:
090: // Create the file
091: TarFileObject fileObj;
092: if (entry.isDirectory()
093: && getFileFromCache(name) != null) {
094: fileObj = (TarFileObject) getFileFromCache(name);
095: fileObj.setTarEntry(entry);
096: continue;
097: }
098:
099: fileObj = createTarFileObject(name, entry);
100: putFileToCache(fileObj);
101: strongRef.add(fileObj);
102: fileObj.holdObject(strongRef);
103:
104: // Make sure all ancestors exist
105: // TODO - create these on demand
106: TarFileObject parent = null;
107: for (FileName parentName = name.getParent(); parentName != null; fileObj = parent, parentName = parentName
108: .getParent()) {
109: // Locate the parent
110: parent = (TarFileObject) getFileFromCache(parentName);
111: if (parent == null) {
112: parent = createTarFileObject(parentName, null);
113: putFileToCache(parent);
114: strongRef.add(parent);
115: parent.holdObject(strongRef);
116: }
117:
118: // Attach child to parent
119: parent.attachChild(fileObj.getName());
120: }
121: }
122: } catch (IOException e) {
123: throw new FileSystemException(e);
124: } finally {
125: closeCommunicationLink();
126: }
127: }
128:
129: public InputStream getInputStream(TarEntry entry)
130: throws FileSystemException {
131: resetTarFile();
132: try {
133: while (!tarFile.getNextEntry().equals(entry)) {
134: }
135: return tarFile;
136: } catch (IOException e) {
137: throw new FileSystemException(e);
138: }
139: }
140:
141: protected void resetTarFile() throws FileSystemException {
142: // Reading specific entries requires skipping through the tar file from the beginning
143: // Not especially elegant, but we don't have the ability to seek to specific positions
144: // with an input stream.
145: if (this .file.exists()) {
146: recreateTarFile();
147: }
148: }
149:
150: private void recreateTarFile() throws FileSystemException {
151: if (this .tarFile != null) {
152: try {
153: this .tarFile.close();
154: } catch (IOException e) {
155: throw new FileSystemException(
156: "vfs.provider.tar/close-tar-file.error", file,
157: e);
158: }
159: tarFile = null;
160: }
161: TarInputStream tarFile = createTarFile(this .file);
162: this .tarFile = tarFile;
163: }
164:
165: protected TarInputStream getTarFile() throws FileSystemException {
166: if (tarFile == null && this .file.exists()) {
167: recreateTarFile();
168: }
169:
170: return tarFile;
171: }
172:
173: protected TarFileObject createTarFileObject(final FileName name,
174: final TarEntry entry) throws FileSystemException {
175: return new TarFileObject(name, entry, this , true);
176: }
177:
178: protected TarInputStream createTarFile(final File file)
179: throws FileSystemException {
180: try {
181: if ("tgz".equalsIgnoreCase(getRootName().getScheme())) {
182: return new TarInputStream(new GZIPInputStream(
183: new FileInputStream(file)));
184: } else if ("tbz2".equalsIgnoreCase(getRootName()
185: .getScheme())) {
186: return new TarInputStream(Bzip2FileObject
187: .wrapInputStream(file.getAbsolutePath(),
188: new FileInputStream(file)));
189: }
190: return new TarInputStream(new FileInputStream(file));
191: } catch (IOException ioe) {
192: throw new FileSystemException(
193: "vfs.provider.tar/open-tar-file.error", file, ioe);
194: }
195: }
196:
197: protected void doCloseCommunicationLink() {
198: // Release the tar file
199: try {
200: if (tarFile != null) {
201: tarFile.close();
202: tarFile = null;
203: }
204: } catch (final IOException e) {
205: // getLogger().warn("vfs.provider.tar/close-tar-file.error :" + file, e);
206: VfsLog
207: .warn(getLogger(), log,
208: "vfs.provider.tar/close-tar-file.error :"
209: + file, e);
210: }
211: }
212:
213: /**
214: * Returns the capabilities of this file system.
215: */
216: protected void addCapabilities(final Collection caps) {
217: caps.addAll(TarFileProvider.capabilities);
218: }
219:
220: /**
221: * Creates a file object.
222: */
223: protected FileObject createFile(final FileName name)
224: throws FileSystemException {
225: // This is only called for files which do not exist in the Tar file
226: return new TarFileObject(name, null, this , false);
227: }
228:
229: /**
230: * will be called after all file-objects closed their streams.
231: protected void notifyAllStreamsClosed()
232: {
233: closeCommunicationLink();
234: }
235: */
236: }
|