FileSystem.java
上传用户:quxuerui
上传日期:2018-01-08
资源大小:41811k
文件大小:51k
源码类别:

网格计算

开发平台:

Java

  1. /**
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *     http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing, software
  13.  * distributed under the License is distributed on an "AS IS" BASIS,
  14.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15.  * See the License for the specific language governing permissions and
  16.  * limitations under the License.
  17.  */
  18. package org.apache.hadoop.fs;
  19. import java.io.Closeable;
  20. import java.io.FileNotFoundException;
  21. import java.io.IOException;
  22. import java.net.URI;
  23. import java.util.ArrayList;
  24. import java.util.Arrays;
  25. import java.util.Collection;
  26. import java.util.HashMap;
  27. import java.util.IdentityHashMap;
  28. import java.util.Iterator;
  29. import java.util.List;
  30. import java.util.Map;
  31. import java.util.Set;
  32. import java.util.TreeSet;
  33. import java.util.concurrent.atomic.AtomicLong;
  34. import java.util.regex.Pattern;
  35. import javax.security.auth.login.LoginException;
  36. import org.apache.commons.logging.*;
  37. import org.apache.hadoop.conf.*;
  38. import org.apache.hadoop.net.NetUtils;
  39. import org.apache.hadoop.util.*;
  40. import org.apache.hadoop.fs.permission.FsPermission;
  41. import org.apache.hadoop.io.MultipleIOException;
  42. import org.apache.hadoop.security.UserGroupInformation;
  43. /****************************************************************
  44.  * An abstract base class for a fairly generic filesystem.  It
  45.  * may be implemented as a distributed filesystem, or as a "local"
  46.  * one that reflects the locally-connected disk.  The local version
  47.  * exists for small Hadoop instances and for testing.
  48.  *
  49.  * <p>
  50.  *
  51.  * All user code that may potentially use the Hadoop Distributed
  52.  * File System should be written to use a FileSystem object.  The
  53.  * Hadoop DFS is a multi-machine system that appears as a single
  54.  * disk.  It's useful because of its fault tolerance and potentially
  55.  * very large capacity.
  56.  * 
  57.  * <p>
  58.  * The local implementation is {@link LocalFileSystem} and distributed
  59.  * implementation is DistributedFileSystem.
  60.  *****************************************************************/
  61. public abstract class FileSystem extends Configured implements Closeable {
  62.   private static final String FS_DEFAULT_NAME_KEY = "fs.default.name";
  63.   public static final Log LOG = LogFactory.getLog(FileSystem.class);
  64.   /** FileSystem cache */
  65.   private static final Cache CACHE = new Cache();
  66.   /** The key this instance is stored under in the cache. */
  67.   private Cache.Key key;
  68.   /** Recording statistics per a FileSystem class */
  69.   private static final Map<Class<? extends FileSystem>, Statistics> 
  70.     statisticsTable =
  71.       new IdentityHashMap<Class<? extends FileSystem>, Statistics>();
  72.   
  73.   /**
  74.    * The statistics for this file system.
  75.    */
  76.   protected Statistics statistics;
  77.   /**
  78.    * A cache of files that should be deleted when filsystem is closed
  79.    * or the JVM is exited.
  80.    */
  81.   private Set<Path> deleteOnExit = new TreeSet<Path>();
  82.   /** Returns the configured filesystem implementation.*/
  83.   public static FileSystem get(Configuration conf) throws IOException {
  84.     return get(getDefaultUri(conf), conf);
  85.   }
  86.   
  87.   /** Get the default filesystem URI from a configuration.
  88.    * @param conf the configuration to access
  89.    * @return the uri of the default filesystem
  90.    */
  91.   public static URI getDefaultUri(Configuration conf) {
  92.     return URI.create(fixName(conf.get(FS_DEFAULT_NAME_KEY, "file:///")));
  93.   }
  94.   /** Set the default filesystem URI in a configuration.
  95.    * @param conf the configuration to alter
  96.    * @param uri the new default filesystem uri
  97.    */
  98.   public static void setDefaultUri(Configuration conf, URI uri) {
  99.     conf.set(FS_DEFAULT_NAME_KEY, uri.toString());
  100.   }
  101.   /** Set the default filesystem URI in a configuration.
  102.    * @param conf the configuration to alter
  103.    * @param uri the new default filesystem uri
  104.    */
  105.   public static void setDefaultUri(Configuration conf, String uri) {
  106.     setDefaultUri(conf, URI.create(fixName(uri)));
  107.   }
  108.   /** Called after a new FileSystem instance is constructed.
  109.    * @param name a uri whose authority section names the host, port, etc.
  110.    *   for this FileSystem
  111.    * @param conf the configuration
  112.    */
  113.   public void initialize(URI name, Configuration conf) throws IOException {
  114.     statistics = getStatistics(name.getScheme(), getClass());    
  115.   }
  116.   /** Returns a URI whose scheme and authority identify this FileSystem.*/
  117.   public abstract URI getUri();
  118.   
  119.   /** @deprecated call #getUri() instead.*/
  120.   public String getName() { return getUri().toString(); }
  121.   /** @deprecated call #get(URI,Configuration) instead. */
  122.   public static FileSystem getNamed(String name, Configuration conf)
  123.     throws IOException {
  124.     return get(URI.create(fixName(name)), conf);
  125.   }
  126.   /** Update old-format filesystem names, for back-compatibility.  This should
  127.    * eventually be replaced with a checkName() method that throws an exception
  128.    * for old-format names. */ 
  129.   private static String fixName(String name) {
  130.     // convert old-format name to new-format name
  131.     if (name.equals("local")) {         // "local" is now "file:///".
  132.       LOG.warn(""local" is a deprecated filesystem name."
  133.                +" Use "file:///" instead.");
  134.       name = "file:///";
  135.     } else if (name.indexOf('/')==-1) {   // unqualified is "hdfs://"
  136.       LOG.warn("""+name+"" is a deprecated filesystem name."
  137.                +" Use "hdfs://"+name+"/" instead.");
  138.       name = "hdfs://"+name;
  139.     }
  140.     return name;
  141.   }
  142.   /**
  143.    * Get the local file syste
  144.    * @param conf the configuration to configure the file system with
  145.    * @return a LocalFileSystem
  146.    */
  147.   public static LocalFileSystem getLocal(Configuration conf)
  148.     throws IOException {
  149.     return (LocalFileSystem)get(LocalFileSystem.NAME, conf);
  150.   }
  151.   /** Returns the FileSystem for this URI's scheme and authority.  The scheme
  152.    * of the URI determines a configuration property name,
  153.    * <tt>fs.<i>scheme</i>.class</tt> whose value names the FileSystem class.
  154.    * The entire URI is passed to the FileSystem instance's initialize method.
  155.    */
  156.   public static FileSystem get(URI uri, Configuration conf) throws IOException {
  157.     String scheme = uri.getScheme();
  158.     String authority = uri.getAuthority();
  159.     if (scheme == null) {                       // no scheme: use default FS
  160.       return get(conf);
  161.     }
  162.     if (authority == null) {                       // no authority
  163.       URI defaultUri = getDefaultUri(conf);
  164.       if (scheme.equals(defaultUri.getScheme())    // if scheme matches default
  165.           && defaultUri.getAuthority() != null) {  // & default has authority
  166.         return get(defaultUri, conf);              // return default
  167.       }
  168.     }
  169.     return CACHE.get(uri, conf);
  170.   }
  171.   private static class ClientFinalizer extends Thread {
  172.     public synchronized void run() {
  173.       try {
  174.         FileSystem.closeAll();
  175.       } catch (IOException e) {
  176.         LOG.info("FileSystem.closeAll() threw an exception:n" + e);
  177.       }
  178.     }
  179.   }
  180.   private static final ClientFinalizer clientFinalizer = new ClientFinalizer();
  181.   /**
  182.    * Close all cached filesystems. Be sure those filesystems are not
  183.    * used anymore.
  184.    * 
  185.    * @throws IOException
  186.    */
  187.   public static void closeAll() throws IOException {
  188.     CACHE.closeAll();
  189.   }
  190.   /** Make sure that a path specifies a FileSystem. */
  191.   public Path makeQualified(Path path) {
  192.     checkPath(path);
  193.     return path.makeQualified(this);
  194.   }
  195.     
  196.   /** create a file with the provided permission
  197.    * The permission of the file is set to be the provided permission as in
  198.    * setPermission, not permission&~umask
  199.    * 
  200.    * It is implemented using two RPCs. It is understood that it is inefficient,
  201.    * but the implementation is thread-safe. The other option is to change the
  202.    * value of umask in configuration to be 0, but it is not thread-safe.
  203.    * 
  204.    * @param fs file system handle
  205.    * @param file the name of the file to be created
  206.    * @param permission the permission of the file
  207.    * @return an output stream
  208.    * @throws IOException
  209.    */
  210.   public static FSDataOutputStream create(FileSystem fs,
  211.       Path file, FsPermission permission) throws IOException {
  212.     // create the file with default permission
  213.     FSDataOutputStream out = fs.create(file);
  214.     // set its permission to the supplied one
  215.     fs.setPermission(file, permission);
  216.     return out;
  217.   }
  218.   /** create a directory with the provided permission
  219.    * The permission of the directory is set to be the provided permission as in
  220.    * setPermission, not permission&~umask
  221.    * 
  222.    * @see #create(FileSystem, Path, FsPermission)
  223.    * 
  224.    * @param fs file system handle
  225.    * @param dir the name of the directory to be created
  226.    * @param permission the permission of the directory
  227.    * @return true if the directory creation succeeds; false otherwise
  228.    * @throws IOException
  229.    */
  230.   public static boolean mkdirs(FileSystem fs, Path dir, FsPermission permission)
  231.   throws IOException {
  232.     // create the directory using the default permission
  233.     boolean result = fs.mkdirs(dir);
  234.     // set its permission to be the supplied one
  235.     fs.setPermission(dir, permission);
  236.     return result;
  237.   }
  238.   ///////////////////////////////////////////////////////////////
  239.   // FileSystem
  240.   ///////////////////////////////////////////////////////////////
  241.   protected FileSystem() {
  242.     super(null);
  243.   }
  244.   /** Check that a Path belongs to this FileSystem. */
  245.   protected void checkPath(Path path) {
  246.     URI uri = path.toUri();
  247.     if (uri.getScheme() == null)                // fs is relative 
  248.       return;
  249.     String thisScheme = this.getUri().getScheme();
  250.     String thatScheme = uri.getScheme();
  251.     String thisAuthority = this.getUri().getAuthority();
  252.     String thatAuthority = uri.getAuthority();
  253.     //authority and scheme are not case sensitive
  254.     if (thisScheme.equalsIgnoreCase(thatScheme)) {// schemes match
  255.       if (thisAuthority == thatAuthority ||       // & authorities match
  256.           (thisAuthority != null && 
  257.            thisAuthority.equalsIgnoreCase(thatAuthority)))
  258.         return;
  259.       if (thatAuthority == null &&                // path's authority is null
  260.           thisAuthority != null) {                // fs has an authority
  261.         URI defaultUri = getDefaultUri(getConf()); // & is the conf default 
  262.         if (thisScheme.equalsIgnoreCase(defaultUri.getScheme()) &&
  263.             thisAuthority.equalsIgnoreCase(defaultUri.getAuthority()))
  264.           return;
  265.         try {                                     // or the default fs's uri
  266.           defaultUri = get(getConf()).getUri();
  267.         } catch (IOException e) {
  268.           throw new RuntimeException(e);
  269.         }
  270.         if (thisScheme.equalsIgnoreCase(defaultUri.getScheme()) &&
  271.             thisAuthority.equalsIgnoreCase(defaultUri.getAuthority()))
  272.           return;
  273.       }
  274.     }
  275.     throw new IllegalArgumentException("Wrong FS: "+path+
  276.                                        ", expected: "+this.getUri());
  277.   }
  278.   /**
  279.    * Return an array containing hostnames, offset and size of 
  280.    * portions of the given file.  For a nonexistent 
  281.    * file or regions, null will be returned.
  282.    *
  283.    * This call is most helpful with DFS, where it returns 
  284.    * hostnames of machines that contain the given file.
  285.    *
  286.    * The FileSystem will simply return an elt containing 'localhost'.
  287.    */
  288.   public BlockLocation[] getFileBlockLocations(FileStatus file, 
  289.       long start, long len) throws IOException {
  290.     if (file == null) {
  291.       return null;
  292.     }
  293.     if ( (start<0) || (len < 0) ) {
  294.       throw new IllegalArgumentException("Invalid start or len parameter");
  295.     }
  296.     if (file.getLen() < start) {
  297.       return new BlockLocation[0];
  298.     }
  299.     String[] name = { "localhost:50010" };
  300.     String[] host = { "localhost" };
  301.     return new BlockLocation[] { new BlockLocation(name, host, 0, file.getLen()) };
  302.   }
  303.   
  304.   /**
  305.    * Opens an FSDataInputStream at the indicated Path.
  306.    * @param f the file name to open
  307.    * @param bufferSize the size of the buffer to be used.
  308.    */
  309.   public abstract FSDataInputStream open(Path f, int bufferSize)
  310.     throws IOException;
  311.     
  312.   /**
  313.    * Opens an FSDataInputStream at the indicated Path.
  314.    * @param f the file to open
  315.    */
  316.   public FSDataInputStream open(Path f) throws IOException {
  317.     return open(f, getConf().getInt("io.file.buffer.size", 4096));
  318.   }
  319.   /**
  320.    * Opens an FSDataOutputStream at the indicated Path.
  321.    * Files are overwritten by default.
  322.    */
  323.   public FSDataOutputStream create(Path f) throws IOException {
  324.     return create(f, true);
  325.   }
  326.   /**
  327.    * Opens an FSDataOutputStream at the indicated Path.
  328.    */
  329.   public FSDataOutputStream create(Path f, boolean overwrite)
  330.     throws IOException {
  331.     return create(f, overwrite, 
  332.                   getConf().getInt("io.file.buffer.size", 4096),
  333.                   getDefaultReplication(),
  334.                   getDefaultBlockSize());
  335.   }
  336.   /**
  337.    * Create an FSDataOutputStream at the indicated Path with write-progress
  338.    * reporting.
  339.    * Files are overwritten by default.
  340.    */
  341.   public FSDataOutputStream create(Path f, Progressable progress) throws IOException {
  342.     return create(f, true, 
  343.                   getConf().getInt("io.file.buffer.size", 4096),
  344.                   getDefaultReplication(),
  345.                   getDefaultBlockSize(), progress);
  346.   }
  347.   /**
  348.    * Opens an FSDataOutputStream at the indicated Path.
  349.    * Files are overwritten by default.
  350.    */
  351.   public FSDataOutputStream create(Path f, short replication)
  352.     throws IOException {
  353.     return create(f, true, 
  354.                   getConf().getInt("io.file.buffer.size", 4096),
  355.                   replication,
  356.                   getDefaultBlockSize());
  357.   }
  358.   /**
  359.    * Opens an FSDataOutputStream at the indicated Path with write-progress
  360.    * reporting.
  361.    * Files are overwritten by default.
  362.    */
  363.   public FSDataOutputStream create(Path f, short replication, Progressable progress)
  364.     throws IOException {
  365.     return create(f, true, 
  366.                   getConf().getInt("io.file.buffer.size", 4096),
  367.                   replication,
  368.                   getDefaultBlockSize(), progress);
  369.   }
  370.     
  371.   /**
  372.    * Opens an FSDataOutputStream at the indicated Path.
  373.    * @param f the file name to open
  374.    * @param overwrite if a file with this name already exists, then if true,
  375.    *   the file will be overwritten, and if false an error will be thrown.
  376.    * @param bufferSize the size of the buffer to be used.
  377.    */
  378.   public FSDataOutputStream create(Path f, 
  379.                                    boolean overwrite,
  380.                                    int bufferSize
  381.                                    ) throws IOException {
  382.     return create(f, overwrite, bufferSize, 
  383.                   getDefaultReplication(),
  384.                   getDefaultBlockSize());
  385.   }
  386.     
  387.   /**
  388.    * Opens an FSDataOutputStream at the indicated Path with write-progress
  389.    * reporting.
  390.    * @param f the file name to open
  391.    * @param overwrite if a file with this name already exists, then if true,
  392.    *   the file will be overwritten, and if false an error will be thrown.
  393.    * @param bufferSize the size of the buffer to be used.
  394.    */
  395.   public FSDataOutputStream create(Path f, 
  396.                                    boolean overwrite,
  397.                                    int bufferSize,
  398.                                    Progressable progress
  399.                                    ) throws IOException {
  400.     return create(f, overwrite, bufferSize, 
  401.                   getDefaultReplication(),
  402.                   getDefaultBlockSize(), progress);
  403.   }
  404.     
  405.     
  406.   /**
  407.    * Opens an FSDataOutputStream at the indicated Path.
  408.    * @param f the file name to open
  409.    * @param overwrite if a file with this name already exists, then if true,
  410.    *   the file will be overwritten, and if false an error will be thrown.
  411.    * @param bufferSize the size of the buffer to be used.
  412.    * @param replication required block replication for the file. 
  413.    */
  414.   public FSDataOutputStream create(Path f, 
  415.                                    boolean overwrite,
  416.                                    int bufferSize,
  417.                                    short replication,
  418.                                    long blockSize
  419.                                    ) throws IOException {
  420.     return create(f, overwrite, bufferSize, replication, blockSize, null);
  421.   }
  422.   /**
  423.    * Opens an FSDataOutputStream at the indicated Path with write-progress
  424.    * reporting.
  425.    * @param f the file name to open
  426.    * @param overwrite if a file with this name already exists, then if true,
  427.    *   the file will be overwritten, and if false an error will be thrown.
  428.    * @param bufferSize the size of the buffer to be used.
  429.    * @param replication required block replication for the file. 
  430.    */
  431.   public FSDataOutputStream create(Path f,
  432.                                             boolean overwrite,
  433.                                             int bufferSize,
  434.                                             short replication,
  435.                                             long blockSize,
  436.                                             Progressable progress
  437.                                             ) throws IOException {
  438.     return this.create(f, FsPermission.getDefault(),
  439.         overwrite, bufferSize, replication, blockSize, progress);
  440.   }
  441.   /**
  442.    * Opens an FSDataOutputStream at the indicated Path with write-progress
  443.    * reporting.
  444.    * @param f the file name to open
  445.    * @param permission
  446.    * @param overwrite if a file with this name already exists, then if true,
  447.    *   the file will be overwritten, and if false an error will be thrown.
  448.    * @param bufferSize the size of the buffer to be used.
  449.    * @param replication required block replication for the file.
  450.    * @param blockSize
  451.    * @param progress
  452.    * @throws IOException
  453.    * @see #setPermission(Path, FsPermission)
  454.    */
  455.   public abstract FSDataOutputStream create(Path f,
  456.       FsPermission permission,
  457.       boolean overwrite,
  458.       int bufferSize,
  459.       short replication,
  460.       long blockSize,
  461.       Progressable progress) throws IOException;
  462.   /**
  463.    * Creates the given Path as a brand-new zero-length file.  If
  464.    * create fails, or if it already existed, return false.
  465.    */
  466.   public boolean createNewFile(Path f) throws IOException {
  467.     if (exists(f)) {
  468.       return false;
  469.     } else {
  470.       create(f, false, getConf().getInt("io.file.buffer.size", 4096)).close();
  471.       return true;
  472.     }
  473.   }
  474.   /**
  475.    * Append to an existing file (optional operation).
  476.    * Same as append(f, getConf().getInt("io.file.buffer.size", 4096), null)
  477.    * @param f the existing file to be appended.
  478.    * @throws IOException
  479.    */
  480.   public FSDataOutputStream append(Path f) throws IOException {
  481.     return append(f, getConf().getInt("io.file.buffer.size", 4096), null);
  482.   }
  483.   /**
  484.    * Append to an existing file (optional operation).
  485.    * Same as append(f, bufferSize, null).
  486.    * @param f the existing file to be appended.
  487.    * @param bufferSize the size of the buffer to be used.
  488.    * @throws IOException
  489.    */
  490.   public FSDataOutputStream append(Path f, int bufferSize) throws IOException {
  491.     return append(f, bufferSize, null);
  492.   }
  493.   /**
  494.    * Append to an existing file (optional operation).
  495.    * @param f the existing file to be appended.
  496.    * @param bufferSize the size of the buffer to be used.
  497.    * @param progress for reporting progress if it is not null.
  498.    * @throws IOException
  499.    */
  500.   public abstract FSDataOutputStream append(Path f, int bufferSize,
  501.       Progressable progress) throws IOException;
  502.   
  503.   /**
  504.    * Get replication.
  505.    * 
  506.    * @deprecated Use getFileStatus() instead
  507.    * @param src file name
  508.    * @return file replication
  509.    * @throws IOException
  510.    */ 
  511.   @Deprecated
  512.   public short getReplication(Path src) throws IOException {
  513.     return getFileStatus(src).getReplication();
  514.   }
  515.   /**
  516.    * Set replication for an existing file.
  517.    * 
  518.    * @param src file name
  519.    * @param replication new replication
  520.    * @throws IOException
  521.    * @return true if successful;
  522.    *         false if file does not exist or is a directory
  523.    */
  524.   public boolean setReplication(Path src, short replication)
  525.     throws IOException {
  526.     return true;
  527.   }
  528.   /**
  529.    * Renames Path src to Path dst.  Can take place on local fs
  530.    * or remote DFS.
  531.    */
  532.   public abstract boolean rename(Path src, Path dst) throws IOException;
  533.     
  534.   /** Delete a file. */
  535.   /** @deprecated Use delete(Path, boolean) instead */ @Deprecated 
  536.   public abstract boolean delete(Path f) throws IOException;
  537.   
  538.   /** Delete a file.
  539.    *
  540.    * @param f the path to delete.
  541.    * @param recursive if path is a directory and set to 
  542.    * true, the directory is deleted else throws an exception. In
  543.    * case of a file the recursive can be set to either true or false. 
  544.    * @return  true if delete is successful else false. 
  545.    * @throws IOException
  546.    */
  547.   public abstract boolean delete(Path f, boolean recursive) throws IOException;
  548.   /**
  549.    * Mark a path to be deleted when FileSystem is closed.
  550.    * When the JVM shuts down,
  551.    * all FileSystem objects will be closed automatically.
  552.    * Then,
  553.    * the marked path will be deleted as a result of closing the FileSystem.
  554.    *
  555.    * The path has to exist in the file system.
  556.    * 
  557.    * @param f the path to delete.
  558.    * @return  true if deleteOnExit is successful, otherwise false.
  559.    * @throws IOException
  560.    */
  561.   public boolean deleteOnExit(Path f) throws IOException {
  562.     if (!exists(f)) {
  563.       return false;
  564.     }
  565.     synchronized (deleteOnExit) {
  566.       deleteOnExit.add(f);
  567.     }
  568.     return true;
  569.   }
  570.   /**
  571.    * Delete all files that were marked as delete-on-exit. This recursively
  572.    * deletes all files in the specified paths.
  573.    */
  574.   protected void processDeleteOnExit() {
  575.     synchronized (deleteOnExit) {
  576.       for (Iterator<Path> iter = deleteOnExit.iterator(); iter.hasNext();) {
  577.         Path path = iter.next();
  578.         try {
  579.           delete(path, true);
  580.         }
  581.         catch (IOException e) {
  582.           LOG.info("Ignoring failure to deleteOnExit for path " + path);
  583.         }
  584.         iter.remove();
  585.       }
  586.     }
  587.   }
  588.   
  589.   /** Check if exists.
  590.    * @param f source file
  591.    */
  592.   public boolean exists(Path f) throws IOException {
  593.     try {
  594.       return getFileStatus(f) != null;
  595.     } catch (FileNotFoundException e) {
  596.       return false;
  597.     }
  598.   }
  599.   /** True iff the named path is a directory. */
  600.   /** @deprecated Use getFileStatus() instead */ @Deprecated
  601.   public boolean isDirectory(Path f) throws IOException {
  602.     try {
  603.       return getFileStatus(f).isDir();
  604.     } catch (FileNotFoundException e) {
  605.       return false;               // f does not exist
  606.     }
  607.   }
  608.   /** True iff the named path is a regular file. */
  609.   public boolean isFile(Path f) throws IOException {
  610.     try {
  611.       return !getFileStatus(f).isDir();
  612.     } catch (FileNotFoundException e) {
  613.       return false;               // f does not exist
  614.     }
  615.   }
  616.     
  617.   /** The number of bytes in a file. */
  618.   /** @deprecated Use getFileStatus() instead */ @Deprecated
  619.   public long getLength(Path f) throws IOException {
  620.     return getFileStatus(f).getLen();
  621.   }
  622.     
  623.   /** Return the {@link ContentSummary} of a given {@link Path}. */
  624.   public ContentSummary getContentSummary(Path f) throws IOException {
  625.     FileStatus status = getFileStatus(f);
  626.     if (!status.isDir()) {
  627.       // f is a file
  628.       return new ContentSummary(status.getLen(), 1, 0);
  629.     }
  630.     // f is a directory
  631.     long[] summary = {0, 0, 1};
  632.     for(FileStatus s : listStatus(f)) {
  633.       ContentSummary c = s.isDir() ? getContentSummary(s.getPath()) :
  634.                                      new ContentSummary(s.getLen(), 1, 0);
  635.       summary[0] += c.getLength();
  636.       summary[1] += c.getFileCount();
  637.       summary[2] += c.getDirectoryCount();
  638.     }
  639.     return new ContentSummary(summary[0], summary[1], summary[2]);
  640.   }
  641.   final private static PathFilter DEFAULT_FILTER = new PathFilter() {
  642.       public boolean accept(Path file) {
  643.         return true;
  644.       }     
  645.     };
  646.     
  647.   /**
  648.    * List the statuses of the files/directories in the given path if the path is
  649.    * a directory.
  650.    * 
  651.    * @param f
  652.    *          given path
  653.    * @return the statuses of the files/directories in the given patch
  654.    * @throws IOException
  655.    */
  656.   public abstract FileStatus[] listStatus(Path f) throws IOException;
  657.     
  658.   /*
  659.    * Filter files/directories in the given path using the user-supplied path
  660.    * filter. Results are added to the given array <code>results</code>.
  661.    */
  662.   private void listStatus(ArrayList<FileStatus> results, Path f,
  663.       PathFilter filter) throws IOException {
  664.     FileStatus listing[] = listStatus(f);
  665.     if (listing != null) {
  666.       for (int i = 0; i < listing.length; i++) {
  667.         if (filter.accept(listing[i].getPath())) {
  668.           results.add(listing[i]);
  669.         }
  670.       }
  671.     }
  672.   }
  673.   /**
  674.    * Filter files/directories in the given path using the user-supplied path
  675.    * filter.
  676.    * 
  677.    * @param f
  678.    *          a path name
  679.    * @param filter
  680.    *          the user-supplied path filter
  681.    * @return an array of FileStatus objects for the files under the given path
  682.    *         after applying the filter
  683.    * @throws IOException
  684.    *           if encounter any problem while fetching the status
  685.    */
  686.   public FileStatus[] listStatus(Path f, PathFilter filter) throws IOException {
  687.     ArrayList<FileStatus> results = new ArrayList<FileStatus>();
  688.     listStatus(results, f, filter);
  689.     return results.toArray(new FileStatus[results.size()]);
  690.   }
  691.   /**
  692.    * Filter files/directories in the given list of paths using default
  693.    * path filter.
  694.    * 
  695.    * @param files
  696.    *          a list of paths
  697.    * @return a list of statuses for the files under the given paths after
  698.    *         applying the filter default Path filter
  699.    * @exception IOException
  700.    */
  701.   public FileStatus[] listStatus(Path[] files)
  702.       throws IOException {
  703.     return listStatus(files, DEFAULT_FILTER);
  704.   }
  705.   /**
  706.    * Filter files/directories in the given list of paths using user-supplied
  707.    * path filter.
  708.    * 
  709.    * @param files
  710.    *          a list of paths
  711.    * @param filter
  712.    *          the user-supplied path filter
  713.    * @return a list of statuses for the files under the given paths after
  714.    *         applying the filter
  715.    * @exception IOException
  716.    */
  717.   public FileStatus[] listStatus(Path[] files, PathFilter filter)
  718.       throws IOException {
  719.     ArrayList<FileStatus> results = new ArrayList<FileStatus>();
  720.     for (int i = 0; i < files.length; i++) {
  721.       listStatus(results, files[i], filter);
  722.     }
  723.     return results.toArray(new FileStatus[results.size()]);
  724.   }
  725.   /**
  726.    * <p>Return all the files that match filePattern and are not checksum
  727.    * files. Results are sorted by their names.
  728.    * 
  729.    * <p>
  730.    * A filename pattern is composed of <i>regular</i> characters and
  731.    * <i>special pattern matching</i> characters, which are:
  732.    *
  733.    * <dl>
  734.    *  <dd>
  735.    *   <dl>
  736.    *    <p>
  737.    *    <dt> <tt> ? </tt>
  738.    *    <dd> Matches any single character.
  739.    *
  740.    *    <p>
  741.    *    <dt> <tt> * </tt>
  742.    *    <dd> Matches zero or more characters.
  743.    *
  744.    *    <p>
  745.    *    <dt> <tt> [<i>abc</i>] </tt>
  746.    *    <dd> Matches a single character from character set
  747.    *     <tt>{<i>a,b,c</i>}</tt>.
  748.    *
  749.    *    <p>
  750.    *    <dt> <tt> [<i>a</i>-<i>b</i>] </tt>
  751.    *    <dd> Matches a single character from the character range
  752.    *     <tt>{<i>a...b</i>}</tt>.  Note that character <tt><i>a</i></tt> must be
  753.    *     lexicographically less than or equal to character <tt><i>b</i></tt>.
  754.    *
  755.    *    <p>
  756.    *    <dt> <tt> [^<i>a</i>] </tt>
  757.    *    <dd> Matches a single character that is not from character set or range
  758.    *     <tt>{<i>a</i>}</tt>.  Note that the <tt>^</tt> character must occur
  759.    *     immediately to the right of the opening bracket.
  760.    *
  761.    *    <p>
  762.    *    <dt> <tt> <i>c</i> </tt>
  763.    *    <dd> Removes (escapes) any special meaning of character <i>c</i>.
  764.    *
  765.    *    <p>
  766.    *    <dt> <tt> {ab,cd} </tt>
  767.    *    <dd> Matches a string from the string set <tt>{<i>ab, cd</i>} </tt>
  768.    *    
  769.    *    <p>
  770.    *    <dt> <tt> {ab,c{de,fh}} </tt>
  771.    *    <dd> Matches a string from the string set <tt>{<i>ab, cde, cfh</i>}</tt>
  772.    *
  773.    *   </dl>
  774.    *  </dd>
  775.    * </dl>
  776.    *
  777.    * @param pathPattern a regular expression specifying a pth pattern
  778.    * @return an array of paths that match the path pattern
  779.    * @throws IOException
  780.    */
  781.   public FileStatus[] globStatus(Path pathPattern) throws IOException {
  782.     return globStatus(pathPattern, DEFAULT_FILTER);
  783.   }
  784.   
  785.   /**
  786.    * Return an array of FileStatus objects whose path names match pathPattern
  787.    * and is accepted by the user-supplied path filter. Results are sorted by
  788.    * their path names.
  789.    * Return null if pathPattern has no glob and the path does not exist.
  790.    * Return an empty array if pathPattern has a glob and no path matches it. 
  791.    * 
  792.    * @param pathPattern
  793.    *          a regular expression specifying the path pattern
  794.    * @param filter
  795.    *          a user-supplied path filter
  796.    * @return an array of FileStatus objects
  797.    * @throws IOException if any I/O error occurs when fetching file status
  798.    */
  799.   public FileStatus[] globStatus(Path pathPattern, PathFilter filter)
  800.       throws IOException {
  801.     String filename = pathPattern.toUri().getPath();
  802.     List<String> filePatterns = GlobExpander.expand(filename);
  803.     if (filePatterns.size() == 1) {
  804.       return globStatusInternal(pathPattern, filter);
  805.     } else {
  806.       List<FileStatus> results = new ArrayList<FileStatus>();
  807.       for (String filePattern : filePatterns) {
  808.         FileStatus[] files = globStatusInternal(new Path(filePattern), filter);
  809.         for (FileStatus file : files) {
  810.           results.add(file);
  811.         }
  812.       }
  813.       return results.toArray(new FileStatus[results.size()]);
  814.     }
  815.   }
  816.   private FileStatus[] globStatusInternal(Path pathPattern, PathFilter filter)
  817.       throws IOException {
  818.     Path[] parents = new Path[1];
  819.     int level = 0;
  820.     String filename = pathPattern.toUri().getPath();
  821.     
  822.     // path has only zero component
  823.     if ("".equals(filename) || Path.SEPARATOR.equals(filename)) {
  824.       return getFileStatus(new Path[]{pathPattern});
  825.     }
  826.     // path has at least one component
  827.     String[] components = filename.split(Path.SEPARATOR);
  828.     // get the first component
  829.     if (pathPattern.isAbsolute()) {
  830.       parents[0] = new Path(Path.SEPARATOR);
  831.       level = 1;
  832.     } else {
  833.       parents[0] = new Path(Path.CUR_DIR);
  834.     }
  835.     // glob the paths that match the parent path, i.e., [0, components.length-1]
  836.     boolean[] hasGlob = new boolean[]{false};
  837.     Path[] parentPaths = globPathsLevel(parents, components, level, hasGlob);
  838.     FileStatus[] results;
  839.     if (parentPaths == null || parentPaths.length == 0) {
  840.       results = null;
  841.     } else {
  842.       // Now work on the last component of the path
  843.       GlobFilter fp = new GlobFilter(components[components.length - 1], filter);
  844.       if (fp.hasPattern()) { // last component has a pattern
  845.         // list parent directories and then glob the results
  846.         results = listStatus(parentPaths, fp);
  847.         hasGlob[0] = true;
  848.       } else { // last component does not have a pattern
  849.         // get all the path names
  850.         ArrayList<Path> filteredPaths = new ArrayList<Path>(parentPaths.length);
  851.         for (int i = 0; i < parentPaths.length; i++) {
  852.           parentPaths[i] = new Path(parentPaths[i],
  853.             components[components.length - 1]);
  854.           if (fp.accept(parentPaths[i])) {
  855.             filteredPaths.add(parentPaths[i]);
  856.           }
  857.         }
  858.         // get all their statuses
  859.         results = getFileStatus(
  860.             filteredPaths.toArray(new Path[filteredPaths.size()]));
  861.       }
  862.     }
  863.     // Decide if the pathPattern contains a glob or not
  864.     if (results == null) {
  865.       if (hasGlob[0]) {
  866.         results = new FileStatus[0];
  867.       }
  868.     } else {
  869.       if (results.length == 0 ) {
  870.         if (!hasGlob[0]) {
  871.           results = null;
  872.         }
  873.       } else {
  874.         Arrays.sort(results);
  875.       }
  876.     }
  877.     return results;
  878.   }
  879.   /*
  880.    * For a path of N components, return a list of paths that match the
  881.    * components [<code>level</code>, <code>N-1</code>].
  882.    */
  883.   private Path[] globPathsLevel(Path[] parents, String[] filePattern,
  884.       int level, boolean[] hasGlob) throws IOException {
  885.     if (level == filePattern.length - 1)
  886.       return parents;
  887.     if (parents == null || parents.length == 0) {
  888.       return null;
  889.     }
  890.     GlobFilter fp = new GlobFilter(filePattern[level]);
  891.     if (fp.hasPattern()) {
  892.       parents = FileUtil.stat2Paths(listStatus(parents, fp));
  893.       hasGlob[0] = true;
  894.     } else {
  895.       for (int i = 0; i < parents.length; i++) {
  896.         parents[i] = new Path(parents[i], filePattern[level]);
  897.       }
  898.     }
  899.     return globPathsLevel(parents, filePattern, level + 1, hasGlob);
  900.   }
  901.   /* A class that could decide if a string matches the glob or not */
  902.   private static class GlobFilter implements PathFilter {
  903.     private PathFilter userFilter = DEFAULT_FILTER;
  904.     private Pattern regex;
  905.     private boolean hasPattern = false;
  906.       
  907.     /** Default pattern character: Escape any special meaning. */
  908.     private static final char  PAT_ESCAPE = '\';
  909.     /** Default pattern character: Any single character. */
  910.     private static final char  PAT_ANY = '.';
  911.     /** Default pattern character: Character set close. */
  912.     private static final char  PAT_SET_CLOSE = ']';
  913.       
  914.     GlobFilter() {
  915.     }
  916.       
  917.     GlobFilter(String filePattern) throws IOException {
  918.       setRegex(filePattern);
  919.     }
  920.       
  921.     GlobFilter(String filePattern, PathFilter filter) throws IOException {
  922.       userFilter = filter;
  923.       setRegex(filePattern);
  924.     }
  925.       
  926.     private boolean isJavaRegexSpecialChar(char pChar) {
  927.       return pChar == '.' || pChar == '$' || pChar == '(' || pChar == ')' ||
  928.              pChar == '|' || pChar == '+';
  929.     }
  930.     void setRegex(String filePattern) throws IOException {
  931.       int len;
  932.       int setOpen;
  933.       int curlyOpen;
  934.       boolean setRange;
  935.       StringBuilder fileRegex = new StringBuilder();
  936.       // Validate the pattern
  937.       len = filePattern.length();
  938.       if (len == 0)
  939.         return;
  940.       setOpen = 0;
  941.       setRange = false;
  942.       curlyOpen = 0;
  943.       for (int i = 0; i < len; i++) {
  944.         char pCh;
  945.           
  946.         // Examine a single pattern character
  947.         pCh = filePattern.charAt(i);
  948.         if (pCh == PAT_ESCAPE) {
  949.           fileRegex.append(pCh);
  950.           i++;
  951.           if (i >= len)
  952.             error("An escaped character does not present", filePattern, i);
  953.           pCh = filePattern.charAt(i);
  954.         } else if (isJavaRegexSpecialChar(pCh)) {
  955.           fileRegex.append(PAT_ESCAPE);
  956.         } else if (pCh == '*') {
  957.           fileRegex.append(PAT_ANY);
  958.           hasPattern = true;
  959.         } else if (pCh == '?') {
  960.           pCh = PAT_ANY;
  961.           hasPattern = true;
  962.         } else if (pCh == '{') {
  963.           fileRegex.append('(');
  964.           pCh = '(';
  965.           curlyOpen++;
  966.           hasPattern = true;
  967.         } else if (pCh == ',' && curlyOpen > 0) {
  968.           fileRegex.append(")|");
  969.           pCh = '(';
  970.         } else if (pCh == '}' && curlyOpen > 0) {
  971.           // End of a group
  972.           curlyOpen--;
  973.           fileRegex.append(")");
  974.           pCh = ')';
  975.         } else if (pCh == '[' && setOpen == 0) {
  976.           setOpen++;
  977.           hasPattern = true;
  978.         } else if (pCh == '^' && setOpen > 0) {
  979.         } else if (pCh == '-' && setOpen > 0) {
  980.           // Character set range
  981.           setRange = true;
  982.         } else if (pCh == PAT_SET_CLOSE && setRange) {
  983.           // Incomplete character set range
  984.           error("Incomplete character set range", filePattern, i);
  985.         } else if (pCh == PAT_SET_CLOSE && setOpen > 0) {
  986.           // End of a character set
  987.           if (setOpen < 2)
  988.             error("Unexpected end of set", filePattern, i);
  989.           setOpen = 0;
  990.         } else if (setOpen > 0) {
  991.           // Normal character, or the end of a character set range
  992.           setOpen++;
  993.           setRange = false;
  994.         }
  995.         fileRegex.append(pCh);
  996.       }
  997.         
  998.       // Check for a well-formed pattern
  999.       if (setOpen > 0 || setRange || curlyOpen > 0) {
  1000.         // Incomplete character set or character range
  1001.         error("Expecting set closure character or end of range, or }", 
  1002.             filePattern, len);
  1003.       }
  1004.       regex = Pattern.compile(fileRegex.toString());
  1005.     }
  1006.       
  1007.     boolean hasPattern() {
  1008.       return hasPattern;
  1009.     }
  1010.       
  1011.     public boolean accept(Path path) {
  1012.       return regex.matcher(path.getName()).matches() && userFilter.accept(path);
  1013.     }
  1014.       
  1015.     private void error(String s, String pattern, int pos) throws IOException {
  1016.       throw new IOException("Illegal file pattern: "
  1017.                             +s+ " for glob "+ pattern + " at " + pos);
  1018.     }
  1019.   }
  1020.     
  1021.   /** Return the current user's home directory in this filesystem.
  1022.    * The default implementation returns "/user/$USER/".
  1023.    */
  1024.   public Path getHomeDirectory() {
  1025.     return new Path("/user/"+System.getProperty("user.name"))
  1026.       .makeQualified(this);
  1027.   }
  1028.   /**
  1029.    * Set the current working directory for the given file system. All relative
  1030.    * paths will be resolved relative to it.
  1031.    * 
  1032.    * @param new_dir
  1033.    */
  1034.   public abstract void setWorkingDirectory(Path new_dir);
  1035.     
  1036.   /**
  1037.    * Get the current working directory for the given file system
  1038.    * @return the directory pathname
  1039.    */
  1040.   public abstract Path getWorkingDirectory();
  1041.   /**
  1042.    * Call {@link #mkdirs(Path, FsPermission)} with default permission.
  1043.    */
  1044.   public boolean mkdirs(Path f) throws IOException {
  1045.     return mkdirs(f, FsPermission.getDefault());
  1046.   }
  1047.   /**
  1048.    * Make the given file and all non-existent parents into
  1049.    * directories. Has the semantics of Unix 'mkdir -p'.
  1050.    * Existence of the directory hierarchy is not an error.
  1051.    */
  1052.   public abstract boolean mkdirs(Path f, FsPermission permission
  1053.       ) throws IOException;
  1054.   /**
  1055.    * The src file is on the local disk.  Add it to FS at
  1056.    * the given dst name and the source is kept intact afterwards
  1057.    */
  1058.   public void copyFromLocalFile(Path src, Path dst)
  1059.     throws IOException {
  1060.     copyFromLocalFile(false, src, dst);
  1061.   }
  1062.   /**
  1063.    * The src files is on the local disk.  Add it to FS at
  1064.    * the given dst name, removing the source afterwards.
  1065.    */
  1066.   public void moveFromLocalFile(Path[] srcs, Path dst)
  1067.     throws IOException {
  1068.     copyFromLocalFile(true, true, srcs, dst);
  1069.   }
  1070.   /**
  1071.    * The src file is on the local disk.  Add it to FS at
  1072.    * the given dst name, removing the source afterwards.
  1073.    */
  1074.   public void moveFromLocalFile(Path src, Path dst)
  1075.     throws IOException {
  1076.     copyFromLocalFile(true, src, dst);
  1077.   }
  1078.   /**
  1079.    * The src file is on the local disk.  Add it to FS at
  1080.    * the given dst name.
  1081.    * delSrc indicates if the source should be removed
  1082.    */
  1083.   public void copyFromLocalFile(boolean delSrc, Path src, Path dst)
  1084.     throws IOException {
  1085.     copyFromLocalFile(delSrc, true, src, dst);
  1086.   }
  1087.   
  1088.   /**
  1089.    * The src files are on the local disk.  Add it to FS at
  1090.    * the given dst name.
  1091.    * delSrc indicates if the source should be removed
  1092.    */
  1093.   public void copyFromLocalFile(boolean delSrc, boolean overwrite, 
  1094.                                 Path[] srcs, Path dst)
  1095.     throws IOException {
  1096.     Configuration conf = getConf();
  1097.     FileUtil.copy(getLocal(conf), srcs, this, dst, delSrc, overwrite, conf);
  1098.   }
  1099.   
  1100.   /**
  1101.    * The src file is on the local disk.  Add it to FS at
  1102.    * the given dst name.
  1103.    * delSrc indicates if the source should be removed
  1104.    */
  1105.   public void copyFromLocalFile(boolean delSrc, boolean overwrite, 
  1106.                                 Path src, Path dst)
  1107.     throws IOException {
  1108.     Configuration conf = getConf();
  1109.     FileUtil.copy(getLocal(conf), src, this, dst, delSrc, overwrite, conf);
  1110.   }
  1111.     
  1112.   /**
  1113.    * The src file is under FS, and the dst is on the local disk.
  1114.    * Copy it from FS control to the local dst name.
  1115.    */
  1116.   public void copyToLocalFile(Path src, Path dst) throws IOException {
  1117.     copyToLocalFile(false, src, dst);
  1118.   }
  1119.     
  1120.   /**
  1121.    * The src file is under FS, and the dst is on the local disk.
  1122.    * Copy it from FS control to the local dst name.
  1123.    * Remove the source afterwards
  1124.    */
  1125.   public void moveToLocalFile(Path src, Path dst) throws IOException {
  1126.     copyToLocalFile(true, src, dst);
  1127.   }
  1128.   /**
  1129.    * The src file is under FS, and the dst is on the local disk.
  1130.    * Copy it from FS control to the local dst name.
  1131.    * delSrc indicates if the src will be removed or not.
  1132.    */   
  1133.   public void copyToLocalFile(boolean delSrc, Path src, Path dst)
  1134.     throws IOException {
  1135.     FileUtil.copy(this, src, getLocal(getConf()), dst, delSrc, getConf());
  1136.   }
  1137.   /**
  1138.    * Returns a local File that the user can write output to.  The caller
  1139.    * provides both the eventual FS target name and the local working
  1140.    * file.  If the FS is local, we write directly into the target.  If
  1141.    * the FS is remote, we write into the tmp local area.
  1142.    */
  1143.   public Path startLocalOutput(Path fsOutputFile, Path tmpLocalFile)
  1144.     throws IOException {
  1145.     return tmpLocalFile;
  1146.   }
  1147.   /**
  1148.    * Called when we're all done writing to the target.  A local FS will
  1149.    * do nothing, because we've written to exactly the right place.  A remote
  1150.    * FS will copy the contents of tmpLocalFile to the correct target at
  1151.    * fsOutputFile.
  1152.    */
  1153.   public void completeLocalOutput(Path fsOutputFile, Path tmpLocalFile)
  1154.     throws IOException {
  1155.     moveFromLocalFile(tmpLocalFile, fsOutputFile);
  1156.   }
  1157.   /**
  1158.    * No more filesystem operations are needed.  Will
  1159.    * release any held locks.
  1160.    */
  1161.   public void close() throws IOException {
  1162.     // delete all files that were marked as delete-on-exit.
  1163.     processDeleteOnExit();
  1164.     CACHE.remove(this.key, this);
  1165.   }
  1166.   /** Return the total size of all files in the filesystem.*/
  1167.   public long getUsed() throws IOException{
  1168.     long used = 0;
  1169.     FileStatus[] files = listStatus(new Path("/"));
  1170.     for(FileStatus file:files){
  1171.       used += file.getLen();
  1172.     }
  1173.     return used;
  1174.   }
  1175.   /**
  1176.    * Get the block size for a particular file.
  1177.    * @param f the filename
  1178.    * @return the number of bytes in a block
  1179.    */
  1180.   /** @deprecated Use getFileStatus() instead */ @Deprecated
  1181.   public long getBlockSize(Path f) throws IOException {
  1182.     return getFileStatus(f).getBlockSize();
  1183.   }
  1184.     
  1185.   /** Return the number of bytes that large input files should be optimally
  1186.    * be split into to minimize i/o time. */
  1187.   public long getDefaultBlockSize() {
  1188.     // default to 32MB: large enough to minimize the impact of seeks
  1189.     return getConf().getLong("fs.local.block.size", 32 * 1024 * 1024);
  1190.   }
  1191.     
  1192.   /**
  1193.    * Get the default replication.
  1194.    */
  1195.   public short getDefaultReplication() { return 1; }
  1196.   /**
  1197.    * Return a file status object that represents the path.
  1198.    * @param f The path we want information from
  1199.    * @return a FileStatus object
  1200.    * @throws FileNotFoundException when the path does not exist;
  1201.    *         IOException see specific implementation
  1202.    */
  1203.   public abstract FileStatus getFileStatus(Path f) throws IOException;
  1204.   /**
  1205.    * Get the checksum of a file.
  1206.    *
  1207.    * @param f The file path
  1208.    * @return The file checksum.  The default return value is null,
  1209.    *  which indicates that no checksum algorithm is implemented
  1210.    *  in the corresponding FileSystem.
  1211.    */
  1212.   public FileChecksum getFileChecksum(Path f) throws IOException {
  1213.     return null;
  1214.   }
  1215.   
  1216.   /**
  1217.    * Set the verify checksum flag. This is only applicable if the 
  1218.    * corresponding FileSystem supports checksum. By default doesn't do anything.
  1219.    * @param verifyChecksum
  1220.    */
  1221.   public void setVerifyChecksum(boolean verifyChecksum) {
  1222.     //doesn't do anything
  1223.   }
  1224.   /**
  1225.    * Return a list of file status objects that corresponds to the list of paths
  1226.    * excluding those non-existent paths.
  1227.    * 
  1228.    * @param paths
  1229.    *          the list of paths we want information from
  1230.    * @return a list of FileStatus objects
  1231.    * @throws IOException
  1232.    *           see specific implementation
  1233.    */
  1234.   private FileStatus[] getFileStatus(Path[] paths) throws IOException {
  1235.     if (paths == null) {
  1236.       return null;
  1237.     }
  1238.     ArrayList<FileStatus> results = new ArrayList<FileStatus>(paths.length);
  1239.     for (int i = 0; i < paths.length; i++) {
  1240.       try {
  1241.         results.add(getFileStatus(paths[i]));
  1242.       } catch (FileNotFoundException e) { // do nothing
  1243.       }
  1244.     }
  1245.     return results.toArray(new FileStatus[results.size()]);
  1246.   }
  1247.   /**
  1248.    * Set permission of a path.
  1249.    * @param p
  1250.    * @param permission
  1251.    */
  1252.   public void setPermission(Path p, FsPermission permission
  1253.       ) throws IOException {
  1254.   }
  1255.   /**
  1256.    * Set owner of a path (i.e. a file or a directory).
  1257.    * The parameters username and groupname cannot both be null.
  1258.    * @param p The path
  1259.    * @param username If it is null, the original username remains unchanged.
  1260.    * @param groupname If it is null, the original groupname remains unchanged.
  1261.    */
  1262.   public void setOwner(Path p, String username, String groupname
  1263.       ) throws IOException {
  1264.   }
  1265.   /**
  1266.    * Set access time of a file
  1267.    * @param p The path
  1268.    * @param mtime Set the modification time of this file.
  1269.    *              The number of milliseconds since Jan 1, 1970. 
  1270.    *              A value of -1 means that this call should not set modification time.
  1271.    * @param atime Set the access time of this file.
  1272.    *              The number of milliseconds since Jan 1, 1970. 
  1273.    *              A value of -1 means that this call should not set access time.
  1274.    */
  1275.   public void setTimes(Path p, long mtime, long atime
  1276.       ) throws IOException {
  1277.   }
  1278.   private static FileSystem createFileSystem(URI uri, Configuration conf
  1279.       ) throws IOException {
  1280.     Class<?> clazz = conf.getClass("fs." + uri.getScheme() + ".impl", null);
  1281.     if (clazz == null) {
  1282.       throw new IOException("No FileSystem for scheme: " + uri.getScheme());
  1283.     }
  1284.     FileSystem fs = (FileSystem)ReflectionUtils.newInstance(clazz, conf);
  1285.     fs.initialize(uri, conf);
  1286.     return fs;
  1287.   }
  1288.   /** Caching FileSystem objects */
  1289.   static class Cache {
  1290.     private final Map<Key, FileSystem> map = new HashMap<Key, FileSystem>();
  1291.     synchronized FileSystem get(URI uri, Configuration conf) throws IOException{
  1292.       Key key = new Key(uri, conf);
  1293.       FileSystem fs = map.get(key);
  1294.       if (fs == null) {
  1295.         fs = createFileSystem(uri, conf);
  1296.         if (map.isEmpty() && !clientFinalizer.isAlive()) {
  1297.           Runtime.getRuntime().addShutdownHook(clientFinalizer);
  1298.         }
  1299.         fs.key = key;
  1300.         map.put(key, fs);
  1301.       }
  1302.       return fs;
  1303.     }
  1304.     synchronized void remove(Key key, FileSystem fs) {
  1305.       if (map.containsKey(key) && fs == map.get(key)) {
  1306.         map.remove(key);
  1307.         if (map.isEmpty() && !clientFinalizer.isAlive()) {
  1308.           if (!Runtime.getRuntime().removeShutdownHook(clientFinalizer)) {
  1309.             LOG.info("Could not cancel cleanup thread, though no " +
  1310.                      "FileSystems are open");
  1311.           }
  1312.         }
  1313.       }
  1314.     }
  1315.     synchronized void closeAll() throws IOException {
  1316.       List<IOException> exceptions = new ArrayList<IOException>();
  1317.       for(; !map.isEmpty(); ) {
  1318.         Map.Entry<Key, FileSystem> e = map.entrySet().iterator().next();
  1319.         final Key key = e.getKey();
  1320.         final FileSystem fs = e.getValue();
  1321.         //remove from cache
  1322.         remove(key, fs);
  1323.         if (fs != null) {
  1324.           try {
  1325.             fs.close();
  1326.           }
  1327.           catch(IOException ioe) {
  1328.             exceptions.add(ioe);
  1329.           }
  1330.         }
  1331.       }
  1332.       if (!exceptions.isEmpty()) {
  1333.         throw MultipleIOException.createIOException(exceptions);
  1334.       }
  1335.     }
  1336.     /** FileSystem.Cache.Key */
  1337.     static class Key {
  1338.       final String scheme;
  1339.       final String authority;
  1340.       final String username;
  1341.       Key(URI uri, Configuration conf) throws IOException {
  1342.         scheme = uri.getScheme()==null?"":uri.getScheme().toLowerCase();
  1343.         authority = uri.getAuthority()==null?"":uri.getAuthority().toLowerCase();
  1344.         UserGroupInformation ugi = UserGroupInformation.readFrom(conf);
  1345.         if (ugi == null) {
  1346.           try {
  1347.             ugi = UserGroupInformation.login(conf);
  1348.           } catch(LoginException e) {
  1349.             LOG.warn("uri=" + uri, e);
  1350.           }
  1351.         }
  1352.         username = ugi == null? null: ugi.getUserName();
  1353.       }
  1354.       /** {@inheritDoc} */
  1355.       public int hashCode() {
  1356.         return (scheme + authority + username).hashCode();
  1357.       }
  1358.       static boolean isEqual(Object a, Object b) {
  1359.         return a == b || (a != null && a.equals(b));        
  1360.       }
  1361.       /** {@inheritDoc} */
  1362.       public boolean equals(Object obj) {
  1363.         if (obj == this) {
  1364.           return true;
  1365.         }
  1366.         if (obj != null && obj instanceof Key) {
  1367.           Key that = (Key)obj;
  1368.           return isEqual(this.scheme, that.scheme)
  1369.                  && isEqual(this.authority, that.authority)
  1370.                  && isEqual(this.username, that.username);
  1371.         }
  1372.         return false;        
  1373.       }
  1374.       /** {@inheritDoc} */
  1375.       public String toString() {
  1376.         return username + "@" + scheme + "://" + authority;        
  1377.       }
  1378.     }
  1379.   }
  1380.   
  1381.   public static final class Statistics {
  1382.     private final String scheme;
  1383.     private AtomicLong bytesRead = new AtomicLong();
  1384.     private AtomicLong bytesWritten = new AtomicLong();
  1385.     
  1386.     public Statistics(String scheme) {
  1387.       this.scheme = scheme;
  1388.     }
  1389.     /**
  1390.      * Increment the bytes read in the statistics
  1391.      * @param newBytes the additional bytes read
  1392.      */
  1393.     public void incrementBytesRead(long newBytes) {
  1394.       bytesRead.getAndAdd(newBytes);
  1395.     }
  1396.     
  1397.     /**
  1398.      * Increment the bytes written in the statistics
  1399.      * @param newBytes the additional bytes written
  1400.      */
  1401.     public void incrementBytesWritten(long newBytes) {
  1402.       bytesWritten.getAndAdd(newBytes);
  1403.     }
  1404.     
  1405.     /**
  1406.      * Get the total number of bytes read
  1407.      * @return the number of bytes
  1408.      */
  1409.     public long getBytesRead() {
  1410.       return bytesRead.get();
  1411.     }
  1412.     
  1413.     /**
  1414.      * Get the total number of bytes written
  1415.      * @return the number of bytes
  1416.      */
  1417.     public long getBytesWritten() {
  1418.       return bytesWritten.get();
  1419.     }
  1420.     
  1421.     public String toString() {
  1422.       return bytesRead + " bytes read and " + bytesWritten + 
  1423.              " bytes written";
  1424.     }
  1425.     
  1426.     /**
  1427.      * Reset the counts of bytes to 0.
  1428.      */
  1429.     public void reset() {
  1430.       bytesWritten.set(0);
  1431.       bytesRead.set(0);
  1432.     }
  1433.     
  1434.     /**
  1435.      * Get the uri scheme associated with this statistics object.
  1436.      * @return the schema associated with this set of statistics
  1437.      */
  1438.     public String getScheme() {
  1439.       return scheme;
  1440.     }
  1441.   }
  1442.   
  1443.   /**
  1444.    * Get the Map of Statistics object indexed by URI Scheme.
  1445.    * @return a Map having a key as URI scheme and value as Statistics object
  1446.    * @deprecated use {@link #getAllStatistics} instead
  1447.    */
  1448.   public static synchronized Map<String, Statistics> getStatistics() {
  1449.     Map<String, Statistics> result = new HashMap<String, Statistics>();
  1450.     for(Statistics stat: statisticsTable.values()) {
  1451.       result.put(stat.getScheme(), stat);
  1452.     }
  1453.     return result;
  1454.   }
  1455.   /**
  1456.    * Return the FileSystem classes that have Statistics
  1457.    */
  1458.   public static synchronized List<Statistics> getAllStatistics() {
  1459.     return new ArrayList<Statistics>(statisticsTable.values());
  1460.   }
  1461.   
  1462.   /**
  1463.    * Get the statistics for a particular file system
  1464.    * @param cls the class to lookup
  1465.    * @return a statistics object
  1466.    */
  1467.   public static synchronized 
  1468.   Statistics getStatistics(String scheme, Class<? extends FileSystem> cls) {
  1469.     Statistics result = statisticsTable.get(cls);
  1470.     if (result == null) {
  1471.       result = new Statistics(scheme);
  1472.       statisticsTable.put(cls, result);
  1473.     }
  1474.     return result;
  1475.   }
  1476.   
  1477.   public static synchronized void clearStatistics() {
  1478.     for(Statistics stat: statisticsTable.values()) {
  1479.       stat.reset();
  1480.     }
  1481.   }
  1482.   public static synchronized
  1483.   void printStatistics() throws IOException {
  1484.     for (Map.Entry<Class<? extends FileSystem>, Statistics> pair: 
  1485.             statisticsTable.entrySet()) {
  1486.       System.out.println("  FileSystem " + pair.getKey().getName() + 
  1487.                          ": " + pair.getValue());
  1488.     }
  1489.   }
  1490. }