View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.vfs.provider.tar;
18  
19  //TODO: Revert to [compress]
20  //import org.apache.commons.compress.tar.TarEntry;
21  //import org.apache.commons.compress.tar.TarInputStream;
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  import org.apache.commons.vfs.FileName;
25  import org.apache.commons.vfs.FileObject;
26  import org.apache.commons.vfs.FileSystem;
27  import org.apache.commons.vfs.FileSystemException;
28  import org.apache.commons.vfs.FileSystemOptions;
29  import org.apache.commons.vfs.Selectors;
30  import org.apache.commons.vfs.VfsLog;
31  import org.apache.commons.vfs.provider.AbstractFileSystem;
32  import org.apache.commons.vfs.provider.UriParser;
33  import org.apache.commons.vfs.provider.bzip2.Bzip2FileObject;
34  
35  import java.io.File;
36  import java.io.FileInputStream;
37  import java.io.IOException;
38  import java.io.InputStream;
39  import java.util.ArrayList;
40  import java.util.Collection;
41  import java.util.List;
42  import java.util.zip.GZIPInputStream;
43  
44  /***
45   * A read-only file system for Tar files.
46   *
47   * @author <a href="mailto:adammurdoch@apache.org">Adam Murdoch</a>
48   * @version $Revision: 484648 $ $Date: 2006-12-08 17:18:36 +0100 (Fr, 08 Dez 2006) $
49   */
50  public class TarFileSystem
51      extends AbstractFileSystem
52      implements FileSystem
53  {
54      private final static Log log = LogFactory.getLog(TarFileSystem.class);
55  
56      private final File file;
57      private TarInputStream tarFile;
58  
59      protected TarFileSystem(final FileName rootName,
60                              final FileObject parentLayer,
61                              final FileSystemOptions fileSystemOptions)
62          throws FileSystemException
63      {
64          super(rootName, parentLayer, fileSystemOptions);
65  
66          // Make a local copy of the file
67          file = parentLayer.getFileSystem().replicateFile(parentLayer, Selectors.SELECT_SELF);
68  
69          // Open the Tar file
70          if (!file.exists())
71          {
72              // Don't need to do anything
73              tarFile = null;
74              return;
75          }
76  
77          // tarFile = createTarFile(this.file);
78      }
79  
80      public void init() throws FileSystemException
81      {
82          super.init();
83  
84          // Build the index
85          try
86          {
87              List strongRef = new ArrayList(100);
88              TarEntry entry;
89              while ((entry = getTarFile().getNextEntry()) != null)
90              {
91                  FileName name = getFileSystemManager().resolveName(getRootName(), UriParser.encode(entry.getName()));
92  
93                  // Create the file
94                  TarFileObject fileObj;
95                  if (entry.isDirectory() && getFileFromCache(name) != null)
96                  {
97                      fileObj = (TarFileObject) getFileFromCache(name);
98                      fileObj.setTarEntry(entry);
99                      continue;
100                 }
101 
102                 fileObj = createTarFileObject(name, entry);
103                 putFileToCache(fileObj);
104                 strongRef.add(fileObj);
105                 fileObj.holdObject(strongRef);
106 
107                 // Make sure all ancestors exist
108                 // TODO - create these on demand
109                 TarFileObject parent = null;
110                 for (FileName parentName = name.getParent();
111                      parentName != null;
112                      fileObj = parent, parentName = parentName.getParent())
113                 {
114                     // Locate the parent
115                     parent = (TarFileObject) getFileFromCache(parentName);
116                     if (parent == null)
117                     {
118                         parent = createTarFileObject(parentName, null);
119                         putFileToCache(parent);
120                         strongRef.add(parent);
121                         parent.holdObject(strongRef);
122                     }
123 
124                     // Attach child to parent
125                     parent.attachChild(fileObj.getName());
126                 }
127             }
128         }
129         catch (IOException e)
130         {
131             throw new FileSystemException(e);
132         }
133         finally
134         {
135             closeCommunicationLink();
136         }
137     }
138 
139     public InputStream getInputStream(TarEntry entry) throws FileSystemException
140     {
141         resetTarFile();
142         try
143         {
144             while (!tarFile.getNextEntry().equals(entry))
145             {
146             }
147             return tarFile;
148         }
149         catch (IOException e)
150         {
151             throw new FileSystemException(e);
152         }
153     }
154 
155     protected void resetTarFile() throws FileSystemException
156     {
157         // Reading specific entries requires skipping through the tar file from the beginning
158         // Not especially elegant, but we don't have the ability to seek to specific positions
159         // with an input stream.
160         if (this.file.exists())
161         {
162             recreateTarFile();
163         }
164     }
165 
166     private void recreateTarFile() throws FileSystemException
167     {
168         if (this.tarFile != null)
169         {
170             try
171             {
172                 this.tarFile.close();
173             }
174             catch (IOException e)
175             {
176                 throw new FileSystemException("vfs.provider.tar/close-tar-file.error", file, e);
177             }
178             tarFile = null;
179         }
180         TarInputStream tarFile = createTarFile(this.file);
181         this.tarFile = tarFile;
182     }
183 
184     protected TarInputStream getTarFile() throws FileSystemException
185     {
186         if (tarFile == null && this.file.exists())
187         {
188             recreateTarFile();
189         }
190 
191         return tarFile;
192     }
193 
194     protected TarFileObject createTarFileObject(final FileName name,
195                                                 final TarEntry entry) throws FileSystemException
196     {
197         return new TarFileObject(name, entry, this, true);
198     }
199 
200     protected TarInputStream createTarFile(final File file) throws FileSystemException
201     {
202         try
203         {
204             if ("tgz".equalsIgnoreCase(getRootName().getScheme()))
205             {
206                 return new TarInputStream(new GZIPInputStream(new FileInputStream(file)));
207             }
208             else if ("tbz2".equalsIgnoreCase(getRootName().getScheme()))
209             {
210                 return new TarInputStream(Bzip2FileObject.wrapInputStream(file.getAbsolutePath(), new FileInputStream(file)));
211             }
212             return new TarInputStream(new FileInputStream(file));
213         }
214         catch (IOException ioe)
215         {
216             throw new FileSystemException("vfs.provider.tar/open-tar-file.error", file, ioe);
217         }
218     }
219 
220     protected void doCloseCommunicationLink()
221     {
222         // Release the tar file
223         try
224         {
225             if (tarFile != null)
226             {
227                 tarFile.close();
228                 tarFile = null;
229             }
230         }
231         catch (final IOException e)
232         {
233             // getLogger().warn("vfs.provider.tar/close-tar-file.error :" + file, e);
234             VfsLog.warn(getLogger(), log, "vfs.provider.tar/close-tar-file.error :" + file, e);
235         }
236     }
237 
238     /***
239      * Returns the capabilities of this file system.
240      */
241     protected void addCapabilities(final Collection caps)
242     {
243         caps.addAll(TarFileProvider.capabilities);
244     }
245 
246     /***
247      * Creates a file object.
248      */
249     protected FileObject createFile(final FileName name) throws FileSystemException
250     {
251         // This is only called for files which do not exist in the Tar file
252         return new TarFileObject(name, null, this, false);
253     }
254 
255     /***
256      * will be called after all file-objects closed their streams.
257     protected void notifyAllStreamsClosed()
258     {
259         closeCommunicationLink();
260     }
261 	 */
262 }