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 }