001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.fs;
019
020import java.io.FileNotFoundException;
021import java.io.IOException;
022import java.io.InputStream;
023import java.io.OutputStream;
024import java.net.URI;
025import java.security.PrivilegedExceptionAction;
026import java.util.ArrayList;
027import java.util.EnumSet;
028import java.util.HashSet;
029import java.util.IdentityHashMap;
030import java.util.List;
031import java.util.Map;
032import java.util.Set;
033import java.util.Stack;
034import java.util.TreeSet;
035import java.util.Map.Entry;
036
037import org.apache.commons.logging.Log;
038import org.apache.commons.logging.LogFactory;
039import org.apache.hadoop.HadoopIllegalArgumentException;
040import org.apache.hadoop.classification.InterfaceAudience;
041import org.apache.hadoop.classification.InterfaceStability;
042import org.apache.hadoop.conf.Configuration;
043import org.apache.hadoop.fs.FileSystem.Statistics;
044import org.apache.hadoop.fs.Options.CreateOpts;
045import org.apache.hadoop.fs.permission.AclEntry;
046import org.apache.hadoop.fs.permission.AclStatus;
047import org.apache.hadoop.fs.permission.FsAction;
048import org.apache.hadoop.fs.permission.FsPermission;
049import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY;
050import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_DEFAULT;
051import org.apache.hadoop.io.IOUtils;
052import org.apache.hadoop.ipc.RpcClientException;
053import org.apache.hadoop.ipc.RpcServerException;
054import org.apache.hadoop.ipc.UnexpectedServerException;
055import org.apache.hadoop.fs.InvalidPathException;
056import org.apache.hadoop.security.AccessControlException;
057import org.apache.hadoop.security.UserGroupInformation;
058import org.apache.hadoop.security.token.Token;
059import org.apache.hadoop.util.ShutdownHookManager;
060import org.apache.htrace.core.Tracer;
061
062/**
063 * The FileContext class provides an interface to the application writer for
064 * using the Hadoop file system.
065 * It provides a set of methods for the usual operation: create, open, 
066 * list, etc 
067 * 
068 * <p>
069 * <b> *** Path Names *** </b>
070 * <p>
071 * 
072 * The Hadoop file system supports a URI name space and URI names.
073 * It offers a forest of file systems that can be referenced using fully
074 * qualified URIs.
075 * Two common Hadoop file systems implementations are
076 * <ul>
077 * <li> the local file system: file:///path
078 * <li> the hdfs file system hdfs://nnAddress:nnPort/path
079 * </ul>
080 * 
081 * While URI names are very flexible, it requires knowing the name or address
082 * of the server. For convenience one often wants to access the default system
083 * in one's environment without knowing its name/address. This has an
084 * additional benefit that it allows one to change one's default fs
085 *  (e.g. admin moves application from cluster1 to cluster2).
086 * <p>
087 * 
088 * To facilitate this, Hadoop supports a notion of a default file system.
089 * The user can set his default file system, although this is
090 * typically set up for you in your environment via your default config.
091 * A default file system implies a default scheme and authority; slash-relative
092 * names (such as /for/bar) are resolved relative to that default FS.
093 * Similarly a user can also have working-directory-relative names (i.e. names
094 * not starting with a slash). While the working directory is generally in the
095 * same default FS, the wd can be in a different FS.
096 * <p>
097 *  Hence Hadoop path names can be one of:
098 *  <ul>
099 *  <li> fully qualified URI: scheme://authority/path
100 *  <li> slash relative names: /path relative to the default file system
101 *  <li> wd-relative names: path  relative to the working dir
102 *  </ul>   
103 *  Relative paths with scheme (scheme:foo/bar) are illegal.
104 *  
105 *  <p>
106 *  <b>****The Role of the FileContext and configuration defaults****</b>
107 *  <p>
108 *  The FileContext provides file namespace context for resolving file names;
109 *  it also contains the umask for permissions, In that sense it is like the
110 *  per-process file-related state in Unix system.
111 *  These two properties
112 *  <ul> 
113 *  <li> default file system i.e your slash)
114 *  <li> umask
115 *  </ul>
116 *  in general, are obtained from the default configuration file
117 *  in your environment,  (@see {@link Configuration}).
118 *  
119 *  No other configuration parameters are obtained from the default config as 
120 *  far as the file context layer is concerned. All file system instances
121 *  (i.e. deployments of file systems) have default properties; we call these
122 *  server side (SS) defaults. Operation like create allow one to select many 
123 *  properties: either pass them in as explicit parameters or use
124 *  the SS properties.
125 *  <p>
126 *  The file system related SS defaults are
127 *  <ul>
128 *  <li> the home directory (default is "/user/userName")
129 *  <li> the initial wd (only for local fs)
130 *  <li> replication factor
131 *  <li> block size
132 *  <li> buffer size
133 *  <li> encryptDataTransfer 
134 *  <li> checksum option. (checksumType and  bytesPerChecksum)
135 *  </ul>
136 *
137 * <p>
138 * <b> *** Usage Model for the FileContext class *** </b>
139 * <p>
140 * Example 1: use the default config read from the $HADOOP_CONFIG/core.xml.
141 *   Unspecified values come from core-defaults.xml in the release jar.
142 *  <ul>  
143 *  <li> myFContext = FileContext.getFileContext(); // uses the default config
144 *                                                // which has your default FS 
145 *  <li>  myFContext.create(path, ...);
146 *  <li>  myFContext.setWorkingDir(path)
147 *  <li>  myFContext.open (path, ...);  
148 *  </ul>  
149 * Example 2: Get a FileContext with a specific URI as the default FS
150 *  <ul>  
151 *  <li> myFContext = FileContext.getFileContext(URI)
152 *  <li> myFContext.create(path, ...);
153 *   ...
154 * </ul> 
155 * Example 3: FileContext with local file system as the default
156 *  <ul> 
157 *  <li> myFContext = FileContext.getLocalFSFileContext()
158 *  <li> myFContext.create(path, ...);
159 *  <li> ...
160 *  </ul> 
161 * Example 4: Use a specific config, ignoring $HADOOP_CONFIG
162 *  Generally you should not need use a config unless you are doing
163 *   <ul> 
164 *   <li> configX = someConfigSomeOnePassedToYou.
165 *   <li> myFContext = getFileContext(configX); // configX is not changed,
166 *                                              // is passed down 
167 *   <li> myFContext.create(path, ...);
168 *   <li>...
169 *  </ul>                                          
170 *    
171 */
172
173@InterfaceAudience.Public
174@InterfaceStability.Evolving /*Evolving for a release,to be changed to Stable */
175public class FileContext {
176  
177  public static final Log LOG = LogFactory.getLog(FileContext.class);
178  /**
179   * Default permission for directory and symlink
180   * In previous versions, this default permission was also used to
181   * create files, so files created end up with ugo+x permission.
182   * See HADOOP-9155 for detail. 
183   * Two new constants are added to solve this, please use 
184   * {@link FileContext#DIR_DEFAULT_PERM} for directory, and use
185   * {@link FileContext#FILE_DEFAULT_PERM} for file.
186   * This constant is kept for compatibility.
187   */
188  public static final FsPermission DEFAULT_PERM = FsPermission.getDefault();
189  /**
190   * Default permission for directory
191   */
192  public static final FsPermission DIR_DEFAULT_PERM = FsPermission.getDirDefault();
193  /**
194   * Default permission for file
195   */
196  public static final FsPermission FILE_DEFAULT_PERM = FsPermission.getFileDefault();
197
198  /**
199   * Priority of the FileContext shutdown hook.
200   */
201  public static final int SHUTDOWN_HOOK_PRIORITY = 20;
202
203  /**
204   * List of files that should be deleted on JVM shutdown.
205   */
206  static final Map<FileContext, Set<Path>> DELETE_ON_EXIT = 
207    new IdentityHashMap<FileContext, Set<Path>>();
208
209  /** JVM shutdown hook thread. */
210  static final FileContextFinalizer FINALIZER = 
211    new FileContextFinalizer();
212  
213  private static final PathFilter DEFAULT_FILTER = new PathFilter() {
214    @Override
215    public boolean accept(final Path file) {
216      return true;
217    }
218  };
219  
220  /**
221   * The FileContext is defined by.
222   *  1) defaultFS (slash)
223   *  2) wd
224   *  3) umask
225   */   
226  private final AbstractFileSystem defaultFS; //default FS for this FileContext.
227  private Path workingDir;          // Fully qualified
228  private FsPermission umask;
229  private final Configuration conf;
230  private final UserGroupInformation ugi;
231  final boolean resolveSymlinks;
232  private final Tracer tracer;
233
234  private FileContext(final AbstractFileSystem defFs,
235    final FsPermission theUmask, final Configuration aConf) {
236    defaultFS = defFs;
237    umask = FsPermission.getUMask(aConf);
238    conf = aConf;
239    tracer = FsTracer.get(aConf);
240    try {
241      ugi = UserGroupInformation.getCurrentUser();
242    } catch (IOException e) {
243      LOG.error("Exception in getCurrentUser: ",e);
244      throw new RuntimeException("Failed to get the current user " +
245                "while creating a FileContext", e);
246    }
247    /*
248     * Init the wd.
249     * WorkingDir is implemented at the FileContext layer 
250     * NOT at the AbstractFileSystem layer. 
251     * If the DefaultFS, such as localFilesystem has a notion of
252     *  builtin WD, we use that as the initial WD.
253     *  Otherwise the WD is initialized to the home directory.
254     */
255    workingDir = defaultFS.getInitialWorkingDirectory();
256    if (workingDir == null) {
257      workingDir = defaultFS.getHomeDirectory();
258    }
259    resolveSymlinks = conf.getBoolean(
260        CommonConfigurationKeys.FS_CLIENT_RESOLVE_REMOTE_SYMLINKS_KEY,
261        CommonConfigurationKeys.FS_CLIENT_RESOLVE_REMOTE_SYMLINKS_DEFAULT);
262    util = new Util(); // for the inner class
263  }
264
265  /* 
266   * Remove relative part - return "absolute":
267   * If input is relative path ("foo/bar") add wd: ie "/<workingDir>/foo/bar"
268   * A fully qualified uri ("hdfs://nn:p/foo/bar") or a slash-relative path
269   * ("/foo/bar") are returned unchanged.
270   * 
271   * Applications that use FileContext should use #makeQualified() since
272   * they really want a fully qualified URI.
273   * Hence this method is not called makeAbsolute() and 
274   * has been deliberately declared private.
275   */
276  Path fixRelativePart(Path p) {
277    if (p.isUriPathAbsolute()) {
278      return p;
279    } else {
280      return new Path(workingDir, p);
281    }
282  }
283
284  /**
285   * Delete all the paths that were marked as delete-on-exit.
286   */
287  static void processDeleteOnExit() {
288    synchronized (DELETE_ON_EXIT) {
289      Set<Entry<FileContext, Set<Path>>> set = DELETE_ON_EXIT.entrySet();
290      for (Entry<FileContext, Set<Path>> entry : set) {
291        FileContext fc = entry.getKey();
292        Set<Path> paths = entry.getValue();
293        for (Path path : paths) {
294          try {
295            fc.delete(path, true);
296          } catch (IOException e) {
297            LOG.warn("Ignoring failure to deleteOnExit for path " + path);
298          }
299        }
300      }
301      DELETE_ON_EXIT.clear();
302    }
303  }
304
305  /**
306   * Get the file system of supplied path.
307   * 
308   * @param absOrFqPath - absolute or fully qualified path
309   * @return the file system of the path
310   * 
311   * @throws UnsupportedFileSystemException If the file system for
312   *           <code>absOrFqPath</code> is not supported.
313   * @throws IOExcepton If the file system for <code>absOrFqPath</code> could
314   *         not be instantiated.
315   */
316  protected AbstractFileSystem getFSofPath(final Path absOrFqPath)
317      throws UnsupportedFileSystemException, IOException {
318    absOrFqPath.checkNotSchemeWithRelative();
319    absOrFqPath.checkNotRelative();
320
321    try { 
322      // Is it the default FS for this FileContext?
323      defaultFS.checkPath(absOrFqPath);
324      return defaultFS;
325    } catch (Exception e) { // it is different FileSystem
326      return getAbstractFileSystem(ugi, absOrFqPath.toUri(), conf);
327    }
328  }
329  
330  private static AbstractFileSystem getAbstractFileSystem(
331      UserGroupInformation user, final URI uri, final Configuration conf)
332      throws UnsupportedFileSystemException, IOException {
333    try {
334      return user.doAs(new PrivilegedExceptionAction<AbstractFileSystem>() {
335        @Override
336        public AbstractFileSystem run() throws UnsupportedFileSystemException {
337          return AbstractFileSystem.get(uri, conf);
338        }
339      });
340    } catch (InterruptedException ex) {
341      LOG.error(ex);
342      throw new IOException("Failed to get the AbstractFileSystem for path: "
343          + uri, ex);
344    }
345  }
346  
347  /**
348   * Protected Static Factory methods for getting a FileContexts
349   * that take a AbstractFileSystem as input. To be used for testing.
350   */
351
352  /**
353   * Create a FileContext with specified FS as default using the specified
354   * config.
355   * 
356   * @param defFS
357   * @param aConf
358   * @return new FileContext with specifed FS as default.
359   */
360  public static FileContext getFileContext(final AbstractFileSystem defFS,
361                    final Configuration aConf) {
362    return new FileContext(defFS, FsPermission.getUMask(aConf), aConf);
363  }
364  
365  /**
366   * Create a FileContext for specified file system using the default config.
367   * 
368   * @param defaultFS
369   * @return a FileContext with the specified AbstractFileSystem
370   *                 as the default FS.
371   */
372  protected static FileContext getFileContext(
373    final AbstractFileSystem defaultFS) {
374    return getFileContext(defaultFS, new Configuration());
375  }
376 
377  /**
378   * Static Factory methods for getting a FileContext.
379   * Note new file contexts are created for each call.
380   * The only singleton is the local FS context using the default config.
381   * 
382   * Methods that use the default config: the default config read from the
383   * $HADOOP_CONFIG/core.xml,
384   * Unspecified key-values for config are defaulted from core-defaults.xml
385   * in the release jar.
386   * 
387   * The keys relevant to the FileContext layer are extracted at time of
388   * construction. Changes to the config after the call are ignore
389   * by the FileContext layer. 
390   * The conf is passed to lower layers like AbstractFileSystem and HDFS which
391   * pick up their own config variables.
392   */
393
394  /**
395   * Create a FileContext using the default config read from the
396   * $HADOOP_CONFIG/core.xml, Unspecified key-values for config are defaulted
397   * from core-defaults.xml in the release jar.
398   * 
399   * @throws UnsupportedFileSystemException If the file system from the default
400   *           configuration is not supported
401   */
402  public static FileContext getFileContext()
403      throws UnsupportedFileSystemException {
404    return getFileContext(new Configuration());
405  }
406
407  /**
408   * @return a FileContext for the local file system using the default config.
409   * @throws UnsupportedFileSystemException If the file system for
410   *           {@link FsConstants#LOCAL_FS_URI} is not supported.
411   */
412  public static FileContext getLocalFSFileContext()
413      throws UnsupportedFileSystemException {
414    return getFileContext(FsConstants.LOCAL_FS_URI);
415  }
416
417  /**
418   * Create a FileContext for specified URI using the default config.
419   * 
420   * @param defaultFsUri
421   * @return a FileContext with the specified URI as the default FS.
422   * 
423   * @throws UnsupportedFileSystemException If the file system for
424   *           <code>defaultFsUri</code> is not supported
425   */
426  public static FileContext getFileContext(final URI defaultFsUri)
427      throws UnsupportedFileSystemException {
428    return getFileContext(defaultFsUri, new Configuration());
429  }
430
431  /**
432   * Create a FileContext for specified default URI using the specified config.
433   * 
434   * @param defaultFsUri
435   * @param aConf
436   * @return new FileContext for specified uri
437   * @throws UnsupportedFileSystemException If the file system with specified is
438   *           not supported
439   * @throws RuntimeException If the file system specified is supported but
440   *         could not be instantiated, or if login fails.
441   */
442  public static FileContext getFileContext(final URI defaultFsUri,
443      final Configuration aConf) throws UnsupportedFileSystemException {
444    UserGroupInformation currentUser = null;
445    AbstractFileSystem defaultAfs = null;
446    if (defaultFsUri.getScheme() == null) {
447      return getFileContext(aConf);
448    }
449    try {
450      currentUser = UserGroupInformation.getCurrentUser();
451      defaultAfs = getAbstractFileSystem(currentUser, defaultFsUri, aConf);
452    } catch (UnsupportedFileSystemException ex) {
453      throw ex;
454    } catch (IOException ex) {
455      LOG.error(ex);
456      throw new RuntimeException(ex);
457    }
458    return getFileContext(defaultAfs, aConf);
459  }
460
461  /**
462   * Create a FileContext using the passed config. Generally it is better to use
463   * {@link #getFileContext(URI, Configuration)} instead of this one.
464   * 
465   * 
466   * @param aConf
467   * @return new FileContext
468   * @throws UnsupportedFileSystemException If file system in the config
469   *           is not supported
470   */
471  public static FileContext getFileContext(final Configuration aConf)
472      throws UnsupportedFileSystemException {
473    return getFileContext(
474      URI.create(aConf.get(FS_DEFAULT_NAME_KEY, FS_DEFAULT_NAME_DEFAULT)), 
475      aConf);
476  }
477
478  /**
479   * @param aConf - from which the FileContext is configured
480   * @return a FileContext for the local file system using the specified config.
481   * 
482   * @throws UnsupportedFileSystemException If default file system in the config
483   *           is not supported
484   * 
485   */
486  public static FileContext getLocalFSFileContext(final Configuration aConf)
487      throws UnsupportedFileSystemException {
488    return getFileContext(FsConstants.LOCAL_FS_URI, aConf);
489  }
490
491  /* This method is needed for tests. */
492  @InterfaceAudience.Private
493  @InterfaceStability.Unstable /* return type will change to AFS once
494                                  HADOOP-6223 is completed */
495  public AbstractFileSystem getDefaultFileSystem() {
496    return defaultFS;
497  }
498  
499  /**
500   * Set the working directory for wd-relative names (such a "foo/bar"). Working
501   * directory feature is provided by simply prefixing relative names with the
502   * working dir. Note this is different from Unix where the wd is actually set
503   * to the inode. Hence setWorkingDir does not follow symlinks etc. This works
504   * better in a distributed environment that has multiple independent roots.
505   * {@link #getWorkingDirectory()} should return what setWorkingDir() set.
506   * 
507   * @param newWDir new working directory
508   * @throws IOException 
509   * <br>
510   *           NewWdir can be one of:
511   *           <ul>
512   *           <li>relative path: "foo/bar";</li>
513   *           <li>absolute without scheme: "/foo/bar"</li>
514   *           <li>fully qualified with scheme: "xx://auth/foo/bar"</li>
515   *           </ul>
516   * <br>
517   *           Illegal WDs:
518   *           <ul>
519   *           <li>relative with scheme: "xx:foo/bar"</li>
520   *           <li>non existent directory</li>
521   *           </ul>
522   */
523  public void setWorkingDirectory(final Path newWDir) throws IOException {
524    newWDir.checkNotSchemeWithRelative();
525    /* wd is stored as a fully qualified path. We check if the given 
526     * path is not relative first since resolve requires and returns 
527     * an absolute path.
528     */  
529    final Path newWorkingDir = new Path(workingDir, newWDir);
530    FileStatus status = getFileStatus(newWorkingDir);
531    if (status.isFile()) {
532      throw new FileNotFoundException("Cannot setWD to a file");
533    }
534    workingDir = newWorkingDir;
535  }
536  
537  /**
538   * Gets the working directory for wd-relative names (such a "foo/bar").
539   */
540  public Path getWorkingDirectory() {
541    return workingDir;
542  }
543  
544  /**
545   * Gets the ugi in the file-context
546   * @return UserGroupInformation
547   */
548  public UserGroupInformation getUgi() {
549    return ugi;
550  }
551  
552  /**
553   * Return the current user's home directory in this file system.
554   * The default implementation returns "/user/$USER/".
555   * @return the home directory
556   */
557  public Path getHomeDirectory() {
558    return defaultFS.getHomeDirectory();
559  }
560  
561  /**
562   * 
563   * @return the umask of this FileContext
564   */
565  public FsPermission getUMask() {
566    return umask;
567  }
568  
569  /**
570   * Set umask to the supplied parameter.
571   * @param newUmask  the new umask
572   */
573  public void setUMask(final FsPermission newUmask) {
574    umask = newUmask;
575  }
576  
577  
578  /**
579   * Resolve the path following any symlinks or mount points
580   * @param f to be resolved
581   * @return fully qualified resolved path
582   * 
583   * @throws FileNotFoundException  If <code>f</code> does not exist
584   * @throws AccessControlException if access denied
585   * @throws IOException If an IO Error occurred
586   * 
587   * Exceptions applicable to file systems accessed over RPC:
588   * @throws RpcClientException If an exception occurred in the RPC client
589   * @throws RpcServerException If an exception occurred in the RPC server
590   * @throws UnexpectedServerException If server implementation throws
591   *           undeclared exception to RPC server
592   * 
593   * RuntimeExceptions:
594   * @throws InvalidPathException If path <code>f</code> is not valid
595   */
596  public Path resolvePath(final Path f) throws FileNotFoundException,
597      UnresolvedLinkException, AccessControlException, IOException {
598    return resolve(f);
599  }
600  
601  /**
602   * Make the path fully qualified if it is isn't. 
603   * A Fully-qualified path has scheme and authority specified and an absolute
604   * path.
605   * Use the default file system and working dir in this FileContext to qualify.
606   * @param path
607   * @return qualified path
608   */
609  public Path makeQualified(final Path path) {
610    return path.makeQualified(defaultFS.getUri(), getWorkingDirectory());
611  }
612
613  /**
614   * Create or overwrite file on indicated path and returns an output stream for
615   * writing into the file.
616   * 
617   * @param f the file name to open
618   * @param createFlag gives the semantics of create; see {@link CreateFlag}
619   * @param opts file creation options; see {@link Options.CreateOpts}.
620   *          <ul>
621   *          <li>Progress - to report progress on the operation - default null
622   *          <li>Permission - umask is applied against permisssion: default is
623   *          FsPermissions:getDefault()
624   * 
625   *          <li>CreateParent - create missing parent path; default is to not
626   *          to create parents
627   *          <li>The defaults for the following are SS defaults of the file
628   *          server implementing the target path. Not all parameters make sense
629   *          for all kinds of file system - eg. localFS ignores Blocksize,
630   *          replication, checksum
631   *          <ul>
632   *          <li>BufferSize - buffersize used in FSDataOutputStream
633   *          <li>Blocksize - block size for file blocks
634   *          <li>ReplicationFactor - replication for blocks
635   *          <li>ChecksumParam - Checksum parameters. server default is used
636   *          if not specified.
637   *          </ul>
638   *          </ul>
639   * 
640   * @return {@link FSDataOutputStream} for created file
641   * 
642   * @throws AccessControlException If access is denied
643   * @throws FileAlreadyExistsException If file <code>f</code> already exists
644   * @throws FileNotFoundException If parent of <code>f</code> does not exist
645   *           and <code>createParent</code> is false
646   * @throws ParentNotDirectoryException If parent of <code>f</code> is not a
647   *           directory.
648   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
649   *           not supported
650   * @throws IOException If an I/O error occurred
651   * 
652   * Exceptions applicable to file systems accessed over RPC:
653   * @throws RpcClientException If an exception occurred in the RPC client
654   * @throws RpcServerException If an exception occurred in the RPC server
655   * @throws UnexpectedServerException If server implementation throws
656   *           undeclared exception to RPC server
657   * 
658   * RuntimeExceptions:
659   * @throws InvalidPathException If path <code>f</code> is not valid
660   */
661  public FSDataOutputStream create(final Path f,
662      final EnumSet<CreateFlag> createFlag, Options.CreateOpts... opts)
663      throws AccessControlException, FileAlreadyExistsException,
664      FileNotFoundException, ParentNotDirectoryException,
665      UnsupportedFileSystemException, IOException {
666    Path absF = fixRelativePart(f);
667
668    // If one of the options is a permission, extract it & apply umask
669    // If not, add a default Perms and apply umask;
670    // AbstractFileSystem#create
671
672    CreateOpts.Perms permOpt = CreateOpts.getOpt(CreateOpts.Perms.class, opts);
673    FsPermission permission = (permOpt != null) ? permOpt.getValue() :
674                                      FILE_DEFAULT_PERM;
675    permission = permission.applyUMask(umask);
676
677    final CreateOpts[] updatedOpts = 
678                      CreateOpts.setOpt(CreateOpts.perms(permission), opts);
679    return new FSLinkResolver<FSDataOutputStream>() {
680      @Override
681      public FSDataOutputStream next(final AbstractFileSystem fs, final Path p) 
682        throws IOException {
683        return fs.create(p, createFlag, updatedOpts);
684      }
685    }.resolve(this, absF);
686  }
687
688  /**
689   * Make(create) a directory and all the non-existent parents.
690   * 
691   * @param dir - the dir to make
692   * @param permission - permissions is set permission&~umask
693   * @param createParent - if true then missing parent dirs are created if false
694   *          then parent must exist
695   * 
696   * @throws AccessControlException If access is denied
697   * @throws FileAlreadyExistsException If directory <code>dir</code> already
698   *           exists
699   * @throws FileNotFoundException If parent of <code>dir</code> does not exist
700   *           and <code>createParent</code> is false
701   * @throws ParentNotDirectoryException If parent of <code>dir</code> is not a
702   *           directory
703   * @throws UnsupportedFileSystemException If file system for <code>dir</code>
704   *         is not supported
705   * @throws IOException If an I/O error occurred
706   * 
707   * Exceptions applicable to file systems accessed over RPC:
708   * @throws RpcClientException If an exception occurred in the RPC client
709   * @throws UnexpectedServerException If server implementation throws 
710   *           undeclared exception to RPC server
711   * 
712   * RuntimeExceptions:
713   * @throws InvalidPathException If path <code>dir</code> is not valid
714   */
715  public void mkdir(final Path dir, final FsPermission permission,
716      final boolean createParent) throws AccessControlException,
717      FileAlreadyExistsException, FileNotFoundException,
718      ParentNotDirectoryException, UnsupportedFileSystemException, 
719      IOException {
720    final Path absDir = fixRelativePart(dir);
721    final FsPermission absFerms = (permission == null ? 
722          FsPermission.getDirDefault() : permission).applyUMask(umask);
723    new FSLinkResolver<Void>() {
724      @Override
725      public Void next(final AbstractFileSystem fs, final Path p) 
726        throws IOException, UnresolvedLinkException {
727        fs.mkdir(p, absFerms, createParent);
728        return null;
729      }
730    }.resolve(this, absDir);
731  }
732
733  /**
734   * Delete a file.
735   * @param f the path to delete.
736   * @param recursive if path is a directory and set to 
737   * true, the directory is deleted else throws an exception. In
738   * case of a file the recursive can be set to either true or false.
739   *
740   * @throws AccessControlException If access is denied
741   * @throws FileNotFoundException If <code>f</code> does not exist
742   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
743   *           not supported
744   * @throws IOException If an I/O error occurred
745   * 
746   * Exceptions applicable to file systems accessed over RPC:
747   * @throws RpcClientException If an exception occurred in the RPC client
748   * @throws RpcServerException If an exception occurred in the RPC server
749   * @throws UnexpectedServerException If server implementation throws 
750   *           undeclared exception to RPC server
751   * 
752   * RuntimeExceptions:
753   * @throws InvalidPathException If path <code>f</code> is invalid
754   */
755  public boolean delete(final Path f, final boolean recursive)
756      throws AccessControlException, FileNotFoundException,
757      UnsupportedFileSystemException, IOException {
758    Path absF = fixRelativePart(f);
759    return new FSLinkResolver<Boolean>() {
760      @Override
761      public Boolean next(final AbstractFileSystem fs, final Path p) 
762        throws IOException, UnresolvedLinkException {
763        return Boolean.valueOf(fs.delete(p, recursive));
764      }
765    }.resolve(this, absF);
766  }
767 
768  /**
769   * Opens an FSDataInputStream at the indicated Path using
770   * default buffersize.
771   * @param f the file name to open
772   *
773   * @throws AccessControlException If access is denied
774   * @throws FileNotFoundException If file <code>f</code> does not exist
775   * @throws UnsupportedFileSystemException If file system for <code>f</code>
776   *         is not supported
777   * @throws IOException If an I/O error occurred
778   * 
779   * Exceptions applicable to file systems accessed over RPC:
780   * @throws RpcClientException If an exception occurred in the RPC client
781   * @throws RpcServerException If an exception occurred in the RPC server
782   * @throws UnexpectedServerException If server implementation throws 
783   *           undeclared exception to RPC server
784   */
785  public FSDataInputStream open(final Path f) throws AccessControlException,
786      FileNotFoundException, UnsupportedFileSystemException, IOException {
787    final Path absF = fixRelativePart(f);
788    return new FSLinkResolver<FSDataInputStream>() {
789      @Override
790      public FSDataInputStream next(final AbstractFileSystem fs, final Path p) 
791        throws IOException, UnresolvedLinkException {
792        return fs.open(p);
793      }
794    }.resolve(this, absF);
795  }
796
797  /**
798   * Opens an FSDataInputStream at the indicated Path.
799   * 
800   * @param f the file name to open
801   * @param bufferSize the size of the buffer to be used.
802   * 
803   * @throws AccessControlException If access is denied
804   * @throws FileNotFoundException If file <code>f</code> does not exist
805   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
806   *           not supported
807   * @throws IOException If an I/O error occurred
808   * 
809   * Exceptions applicable to file systems accessed over RPC:
810   * @throws RpcClientException If an exception occurred in the RPC client
811   * @throws RpcServerException If an exception occurred in the RPC server
812   * @throws UnexpectedServerException If server implementation throws 
813   *           undeclared exception to RPC server
814   */
815  public FSDataInputStream open(final Path f, final int bufferSize)
816      throws AccessControlException, FileNotFoundException,
817      UnsupportedFileSystemException, IOException {
818    final Path absF = fixRelativePart(f);
819    return new FSLinkResolver<FSDataInputStream>() {
820      @Override
821      public FSDataInputStream next(final AbstractFileSystem fs, final Path p) 
822        throws IOException, UnresolvedLinkException {
823        return fs.open(p, bufferSize);
824      }
825    }.resolve(this, absF);
826  }
827
828  /**
829   * Set replication for an existing file.
830   * 
831   * @param f file name
832   * @param replication new replication
833   *
834   * @return true if successful
835   *
836   * @throws AccessControlException If access is denied
837   * @throws FileNotFoundException If file <code>f</code> does not exist
838   * @throws IOException If an I/O error occurred
839   * 
840   * Exceptions applicable to file systems accessed over RPC:
841   * @throws RpcClientException If an exception occurred in the RPC client
842   * @throws RpcServerException If an exception occurred in the RPC server
843   * @throws UnexpectedServerException If server implementation throws 
844   *           undeclared exception to RPC server
845   */
846  public boolean setReplication(final Path f, final short replication)
847      throws AccessControlException, FileNotFoundException,
848      IOException {
849    final Path absF = fixRelativePart(f);
850    return new FSLinkResolver<Boolean>() {
851      @Override
852      public Boolean next(final AbstractFileSystem fs, final Path p) 
853        throws IOException, UnresolvedLinkException {
854        return Boolean.valueOf(fs.setReplication(p, replication));
855      }
856    }.resolve(this, absF);
857  }
858
859  /**
860   * Renames Path src to Path dst
861   * <ul>
862   * <li
863   * <li>Fails if src is a file and dst is a directory.
864   * <li>Fails if src is a directory and dst is a file.
865   * <li>Fails if the parent of dst does not exist or is a file.
866   * </ul>
867   * <p>
868   * If OVERWRITE option is not passed as an argument, rename fails if the dst
869   * already exists.
870   * <p>
871   * If OVERWRITE option is passed as an argument, rename overwrites the dst if
872   * it is a file or an empty directory. Rename fails if dst is a non-empty
873   * directory.
874   * <p>
875   * Note that atomicity of rename is dependent on the file system
876   * implementation. Please refer to the file system documentation for details
877   * <p>
878   * 
879   * @param src path to be renamed
880   * @param dst new path after rename
881   * 
882   * @throws AccessControlException If access is denied
883   * @throws FileAlreadyExistsException If <code>dst</code> already exists and
884   *           <code>options</options> has {@link Options.Rename#OVERWRITE} 
885   *           option false.
886   * @throws FileNotFoundException If <code>src</code> does not exist
887   * @throws ParentNotDirectoryException If parent of <code>dst</code> is not a
888   *           directory
889   * @throws UnsupportedFileSystemException If file system for <code>src</code>
890   *           and <code>dst</code> is not supported
891   * @throws IOException If an I/O error occurred
892   * 
893   * Exceptions applicable to file systems accessed over RPC:
894   * @throws RpcClientException If an exception occurred in the RPC client
895   * @throws RpcServerException If an exception occurred in the RPC server
896   * @throws UnexpectedServerException If server implementation throws
897   *           undeclared exception to RPC server
898   */
899  public void rename(final Path src, final Path dst,
900      final Options.Rename... options) throws AccessControlException,
901      FileAlreadyExistsException, FileNotFoundException,
902      ParentNotDirectoryException, UnsupportedFileSystemException,
903      IOException {
904    final Path absSrc = fixRelativePart(src);
905    final Path absDst = fixRelativePart(dst);
906    AbstractFileSystem srcFS = getFSofPath(absSrc);
907    AbstractFileSystem dstFS = getFSofPath(absDst);
908    if(!srcFS.getUri().equals(dstFS.getUri())) {
909      throw new IOException("Renames across AbstractFileSystems not supported");
910    }
911    try {
912      srcFS.rename(absSrc, absDst, options);
913    } catch (UnresolvedLinkException e) {
914      /* We do not know whether the source or the destination path
915       * was unresolved. Resolve the source path up until the final
916       * path component, then fully resolve the destination. 
917       */
918      final Path source = resolveIntermediate(absSrc);    
919      new FSLinkResolver<Void>() {
920        @Override
921        public Void next(final AbstractFileSystem fs, final Path p) 
922          throws IOException, UnresolvedLinkException {
923          fs.rename(source, p, options);
924          return null;
925        }
926      }.resolve(this, absDst);
927    }
928  }
929  
930  /**
931   * Set permission of a path.
932   * @param f
933   * @param permission - the new absolute permission (umask is not applied)
934   *
935   * @throws AccessControlException If access is denied
936   * @throws FileNotFoundException If <code>f</code> does not exist
937   * @throws UnsupportedFileSystemException If file system for <code>f</code>
938   *         is not supported
939   * @throws IOException If an I/O error occurred
940   * 
941   * Exceptions applicable to file systems accessed over RPC:
942   * @throws RpcClientException If an exception occurred in the RPC client
943   * @throws RpcServerException If an exception occurred in the RPC server
944   * @throws UnexpectedServerException If server implementation throws 
945   *           undeclared exception to RPC server
946   */
947  public void setPermission(final Path f, final FsPermission permission)
948      throws AccessControlException, FileNotFoundException,
949      UnsupportedFileSystemException, IOException {
950    final Path absF = fixRelativePart(f);
951    new FSLinkResolver<Void>() {
952      @Override
953      public Void next(final AbstractFileSystem fs, final Path p) 
954        throws IOException, UnresolvedLinkException {
955        fs.setPermission(p, permission);
956        return null;
957      }
958    }.resolve(this, absF);
959  }
960
961  /**
962   * Set owner of a path (i.e. a file or a directory). The parameters username
963   * and groupname cannot both be null.
964   * 
965   * @param f The path
966   * @param username If it is null, the original username remains unchanged.
967   * @param groupname If it is null, the original groupname remains unchanged.
968   * 
969   * @throws AccessControlException If access is denied
970   * @throws FileNotFoundException If <code>f</code> does not exist
971   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
972   *           not supported
973   * @throws IOException If an I/O error occurred
974   * 
975   * Exceptions applicable to file systems accessed over RPC:
976   * @throws RpcClientException If an exception occurred in the RPC client
977   * @throws RpcServerException If an exception occurred in the RPC server
978   * @throws UnexpectedServerException If server implementation throws 
979   *           undeclared exception to RPC server
980   * 
981   * RuntimeExceptions:
982   * @throws HadoopIllegalArgumentException If <code>username</code> or
983   *           <code>groupname</code> is invalid.
984   */
985  public void setOwner(final Path f, final String username,
986      final String groupname) throws AccessControlException,
987      UnsupportedFileSystemException, FileNotFoundException,
988      IOException {
989    if ((username == null) && (groupname == null)) {
990      throw new HadoopIllegalArgumentException(
991          "username and groupname cannot both be null");
992    }
993    final Path absF = fixRelativePart(f);
994    new FSLinkResolver<Void>() {
995      @Override
996      public Void next(final AbstractFileSystem fs, final Path p) 
997        throws IOException, UnresolvedLinkException {
998        fs.setOwner(p, username, groupname);
999        return null;
1000      }
1001    }.resolve(this, absF);
1002  }
1003
1004  /**
1005   * Set access time of a file.
1006   * @param f The path
1007   * @param mtime Set the modification time of this file.
1008   *        The number of milliseconds since epoch (Jan 1, 1970). 
1009   *        A value of -1 means that this call should not set modification time.
1010   * @param atime Set the access time of this file.
1011   *        The number of milliseconds since Jan 1, 1970. 
1012   *        A value of -1 means that this call should not set access time.
1013   *
1014   * @throws AccessControlException If access is denied
1015   * @throws FileNotFoundException If <code>f</code> does not exist
1016   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1017   *           not supported
1018   * @throws IOException If an I/O error occurred
1019   * 
1020   * Exceptions applicable to file systems accessed over RPC:
1021   * @throws RpcClientException If an exception occurred in the RPC client
1022   * @throws RpcServerException If an exception occurred in the RPC server
1023   * @throws UnexpectedServerException If server implementation throws 
1024   *           undeclared exception to RPC server
1025   */
1026  public void setTimes(final Path f, final long mtime, final long atime)
1027      throws AccessControlException, FileNotFoundException,
1028      UnsupportedFileSystemException, IOException {
1029    final Path absF = fixRelativePart(f);
1030    new FSLinkResolver<Void>() {
1031      @Override
1032      public Void next(final AbstractFileSystem fs, final Path p) 
1033        throws IOException, UnresolvedLinkException {
1034        fs.setTimes(p, mtime, atime);
1035        return null;
1036      }
1037    }.resolve(this, absF);
1038  }
1039
1040  /**
1041   * Get the checksum of a file.
1042   *
1043   * @param f file path
1044   *
1045   * @return The file checksum.  The default return value is null,
1046   *  which indicates that no checksum algorithm is implemented
1047   *  in the corresponding FileSystem.
1048   *
1049   * @throws AccessControlException If access is denied
1050   * @throws FileNotFoundException If <code>f</code> does not exist
1051   * @throws IOException If an I/O error occurred
1052   * 
1053   * Exceptions applicable to file systems accessed over RPC:
1054   * @throws RpcClientException If an exception occurred in the RPC client
1055   * @throws RpcServerException If an exception occurred in the RPC server
1056   * @throws UnexpectedServerException If server implementation throws 
1057   *           undeclared exception to RPC server
1058   */
1059  public FileChecksum getFileChecksum(final Path f)
1060      throws AccessControlException, FileNotFoundException,
1061      IOException {
1062    final Path absF = fixRelativePart(f);
1063    return new FSLinkResolver<FileChecksum>() {
1064      @Override
1065      public FileChecksum next(final AbstractFileSystem fs, final Path p) 
1066        throws IOException, UnresolvedLinkException {
1067        return fs.getFileChecksum(p);
1068      }
1069    }.resolve(this, absF);
1070  }
1071
1072  /**
1073   * Set the verify checksum flag for the  file system denoted by the path.
1074   * This is only applicable if the 
1075   * corresponding FileSystem supports checksum. By default doesn't do anything.
1076   * @param verifyChecksum
1077   * @param f set the verifyChecksum for the Filesystem containing this path
1078   *
1079   * @throws AccessControlException If access is denied
1080   * @throws FileNotFoundException If <code>f</code> does not exist
1081   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1082   *           not supported
1083   * @throws IOException If an I/O error occurred
1084   * 
1085   * Exceptions applicable to file systems accessed over RPC:
1086   * @throws RpcClientException If an exception occurred in the RPC client
1087   * @throws RpcServerException If an exception occurred in the RPC server
1088   * @throws UnexpectedServerException If server implementation throws 
1089   *           undeclared exception to RPC server
1090   */
1091  public void setVerifyChecksum(final boolean verifyChecksum, final Path f)
1092      throws AccessControlException, FileNotFoundException,
1093      UnsupportedFileSystemException, IOException {
1094    final Path absF = resolve(fixRelativePart(f));
1095    getFSofPath(absF).setVerifyChecksum(verifyChecksum);
1096  }
1097
1098  /**
1099   * Return a file status object that represents the path.
1100   * @param f The path we want information from
1101   *
1102   * @return a FileStatus object
1103   *
1104   * @throws AccessControlException If access is denied
1105   * @throws FileNotFoundException If <code>f</code> does not exist
1106   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1107   *           not supported
1108   * @throws IOException If an I/O error occurred
1109   * 
1110   * Exceptions applicable to file systems accessed over RPC:
1111   * @throws RpcClientException If an exception occurred in the RPC client
1112   * @throws RpcServerException If an exception occurred in the RPC server
1113   * @throws UnexpectedServerException If server implementation throws 
1114   *           undeclared exception to RPC server
1115   */
1116  public FileStatus getFileStatus(final Path f) throws AccessControlException,
1117      FileNotFoundException, UnsupportedFileSystemException, IOException {
1118    final Path absF = fixRelativePart(f);
1119    return new FSLinkResolver<FileStatus>() {
1120      @Override
1121      public FileStatus next(final AbstractFileSystem fs, final Path p) 
1122        throws IOException, UnresolvedLinkException {
1123        return fs.getFileStatus(p);
1124      }
1125    }.resolve(this, absF);
1126  }
1127
1128  /**
1129   * Checks if the user can access a path.  The mode specifies which access
1130   * checks to perform.  If the requested permissions are granted, then the
1131   * method returns normally.  If access is denied, then the method throws an
1132   * {@link AccessControlException}.
1133   * <p/>
1134   * The default implementation of this method calls {@link #getFileStatus(Path)}
1135   * and checks the returned permissions against the requested permissions.
1136   * Note that the getFileStatus call will be subject to authorization checks.
1137   * Typically, this requires search (execute) permissions on each directory in
1138   * the path's prefix, but this is implementation-defined.  Any file system
1139   * that provides a richer authorization model (such as ACLs) may override the
1140   * default implementation so that it checks against that model instead.
1141   * <p>
1142   * In general, applications should avoid using this method, due to the risk of
1143   * time-of-check/time-of-use race conditions.  The permissions on a file may
1144   * change immediately after the access call returns.  Most applications should
1145   * prefer running specific file system actions as the desired user represented
1146   * by a {@link UserGroupInformation}.
1147   *
1148   * @param path Path to check
1149   * @param mode type of access to check
1150   * @throws AccessControlException if access is denied
1151   * @throws FileNotFoundException if the path does not exist
1152   * @throws UnsupportedFileSystemException if file system for <code>path</code>
1153   *   is not supported
1154   * @throws IOException see specific implementation
1155   * 
1156   * Exceptions applicable to file systems accessed over RPC:
1157   * @throws RpcClientException If an exception occurred in the RPC client
1158   * @throws RpcServerException If an exception occurred in the RPC server
1159   * @throws UnexpectedServerException If server implementation throws 
1160   *           undeclared exception to RPC server
1161   */
1162  @InterfaceAudience.LimitedPrivate({"HDFS", "Hive"})
1163  public void access(final Path path, final FsAction mode)
1164      throws AccessControlException, FileNotFoundException,
1165      UnsupportedFileSystemException, IOException {
1166    final Path absPath = fixRelativePart(path);
1167    new FSLinkResolver<Void>() {
1168      @Override
1169      public Void next(AbstractFileSystem fs, Path p) throws IOException,
1170          UnresolvedLinkException {
1171        fs.access(p, mode);
1172        return null;
1173      }
1174    }.resolve(this, absPath);
1175  }
1176
1177  /**
1178   * Return a file status object that represents the path. If the path 
1179   * refers to a symlink then the FileStatus of the symlink is returned.
1180   * The behavior is equivalent to #getFileStatus() if the underlying
1181   * file system does not support symbolic links.
1182   * @param  f The path we want information from.
1183   * @return A FileStatus object
1184   * 
1185   * @throws AccessControlException If access is denied
1186   * @throws FileNotFoundException If <code>f</code> does not exist
1187   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1188   *           not supported
1189   * @throws IOException If an I/O error occurred
1190   */
1191  public FileStatus getFileLinkStatus(final Path f)
1192      throws AccessControlException, FileNotFoundException,
1193      UnsupportedFileSystemException, IOException {
1194    final Path absF = fixRelativePart(f);
1195    return new FSLinkResolver<FileStatus>() {
1196      @Override
1197      public FileStatus next(final AbstractFileSystem fs, final Path p) 
1198        throws IOException, UnresolvedLinkException {
1199        FileStatus fi = fs.getFileLinkStatus(p);
1200        if (fi.isSymlink()) {
1201          fi.setSymlink(FSLinkResolver.qualifySymlinkTarget(fs.getUri(), p,
1202              fi.getSymlink()));
1203        }
1204        return fi;
1205      }
1206    }.resolve(this, absF);
1207  }
1208  
1209  /**
1210   * Returns the target of the given symbolic link as it was specified
1211   * when the link was created.  Links in the path leading up to the
1212   * final path component are resolved transparently.
1213   *
1214   * @param f the path to return the target of
1215   * @return The un-interpreted target of the symbolic link.
1216   * 
1217   * @throws AccessControlException If access is denied
1218   * @throws FileNotFoundException If path <code>f</code> does not exist
1219   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1220   *           not supported
1221   * @throws IOException If the given path does not refer to a symlink
1222   *           or an I/O error occurred
1223   */
1224  public Path getLinkTarget(final Path f) throws AccessControlException,
1225      FileNotFoundException, UnsupportedFileSystemException, IOException {
1226    final Path absF = fixRelativePart(f);
1227    return new FSLinkResolver<Path>() {
1228      @Override
1229      public Path next(final AbstractFileSystem fs, final Path p) 
1230        throws IOException, UnresolvedLinkException {
1231        FileStatus fi = fs.getFileLinkStatus(p);
1232        return fi.getSymlink();
1233      }
1234    }.resolve(this, absF);
1235  }
1236  
1237  /**
1238   * Return blockLocation of the given file for the given offset and len.
1239   *  For a nonexistent file or regions, null will be returned.
1240   *
1241   * This call is most helpful with DFS, where it returns 
1242   * hostnames of machines that contain the given file.
1243   * 
1244   * @param f - get blocklocations of this file
1245   * @param start position (byte offset)
1246   * @param len (in bytes)
1247   *
1248   * @return block locations for given file at specified offset of len
1249   *
1250   * @throws AccessControlException If access is denied
1251   * @throws FileNotFoundException If <code>f</code> does not exist
1252   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1253   *           not supported
1254   * @throws IOException If an I/O error occurred
1255   * 
1256   * Exceptions applicable to file systems accessed over RPC:
1257   * @throws RpcClientException If an exception occurred in the RPC client
1258   * @throws RpcServerException If an exception occurred in the RPC server
1259   * @throws UnexpectedServerException If server implementation throws 
1260   *           undeclared exception to RPC server
1261   * 
1262   * RuntimeExceptions:
1263   * @throws InvalidPathException If path <code>f</code> is invalid
1264   */
1265  @InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
1266  @InterfaceStability.Evolving
1267  public BlockLocation[] getFileBlockLocations(final Path f, final long start,
1268      final long len) throws AccessControlException, FileNotFoundException,
1269      UnsupportedFileSystemException, IOException {
1270    final Path absF = fixRelativePart(f);
1271    return new FSLinkResolver<BlockLocation[]>() {
1272      @Override
1273      public BlockLocation[] next(final AbstractFileSystem fs, final Path p) 
1274        throws IOException, UnresolvedLinkException {
1275        return fs.getFileBlockLocations(p, start, len);
1276      }
1277    }.resolve(this, absF);
1278  }
1279  
1280  /**
1281   * Returns a status object describing the use and capacity of the
1282   * file system denoted by the Parh argument p.
1283   * If the file system has multiple partitions, the
1284   * use and capacity of the partition pointed to by the specified
1285   * path is reflected.
1286   * 
1287   * @param f Path for which status should be obtained. null means the
1288   * root partition of the default file system. 
1289   *
1290   * @return a FsStatus object
1291   *
1292   * @throws AccessControlException If access is denied
1293   * @throws FileNotFoundException If <code>f</code> does not exist
1294   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1295   *           not supported
1296   * @throws IOException If an I/O error occurred
1297   * 
1298   * Exceptions applicable to file systems accessed over RPC:
1299   * @throws RpcClientException If an exception occurred in the RPC client
1300   * @throws RpcServerException If an exception occurred in the RPC server
1301   * @throws UnexpectedServerException If server implementation throws 
1302   *           undeclared exception to RPC server
1303   */
1304  public FsStatus getFsStatus(final Path f) throws AccessControlException,
1305      FileNotFoundException, UnsupportedFileSystemException, IOException {
1306    if (f == null) {
1307      return defaultFS.getFsStatus();
1308    }
1309    final Path absF = fixRelativePart(f);
1310    return new FSLinkResolver<FsStatus>() {
1311      @Override
1312      public FsStatus next(final AbstractFileSystem fs, final Path p) 
1313        throws IOException, UnresolvedLinkException {
1314        return fs.getFsStatus(p);
1315      }
1316    }.resolve(this, absF);
1317  }
1318
1319  /**
1320   * Creates a symbolic link to an existing file. An exception is thrown if 
1321   * the symlink exits, the user does not have permission to create symlink,
1322   * or the underlying file system does not support symlinks.
1323   * 
1324   * Symlink permissions are ignored, access to a symlink is determined by
1325   * the permissions of the symlink target.
1326   * 
1327   * Symlinks in paths leading up to the final path component are resolved 
1328   * transparently. If the final path component refers to a symlink some 
1329   * functions operate on the symlink itself, these are:
1330   * - delete(f) and deleteOnExit(f) - Deletes the symlink.
1331   * - rename(src, dst) - If src refers to a symlink, the symlink is 
1332   *   renamed. If dst refers to a symlink, the symlink is over-written.
1333   * - getLinkTarget(f) - Returns the target of the symlink. 
1334   * - getFileLinkStatus(f) - Returns a FileStatus object describing
1335   *   the symlink.
1336   * Some functions, create() and mkdir(), expect the final path component
1337   * does not exist. If they are given a path that refers to a symlink that 
1338   * does exist they behave as if the path referred to an existing file or 
1339   * directory. All other functions fully resolve, ie follow, the symlink. 
1340   * These are: open, setReplication, setOwner, setTimes, setWorkingDirectory,
1341   * setPermission, getFileChecksum, setVerifyChecksum, getFileBlockLocations,
1342   * getFsStatus, getFileStatus, exists, and listStatus.
1343   * 
1344   * Symlink targets are stored as given to createSymlink, assuming the 
1345   * underlying file system is capable of storing a fully qualified URI.
1346   * Dangling symlinks are permitted. FileContext supports four types of 
1347   * symlink targets, and resolves them as follows
1348   * <pre>
1349   * Given a path referring to a symlink of form:
1350   * 
1351   *   <---X---> 
1352   *   fs://host/A/B/link 
1353   *   <-----Y----->
1354   * 
1355   * In this path X is the scheme and authority that identify the file system,
1356   * and Y is the path leading up to the final path component "link". If Y is
1357   * a symlink  itself then let Y' be the target of Y and X' be the scheme and
1358   * authority of Y'. Symlink targets may:
1359   * 
1360   * 1. Fully qualified URIs
1361   * 
1362   * fs://hostX/A/B/file  Resolved according to the target file system.
1363   * 
1364   * 2. Partially qualified URIs (eg scheme but no host)
1365   * 
1366   * fs:///A/B/file  Resolved according to the target file system. Eg resolving
1367   *                 a symlink to hdfs:///A results in an exception because
1368   *                 HDFS URIs must be fully qualified, while a symlink to 
1369   *                 file:///A will not since Hadoop's local file systems 
1370   *                 require partially qualified URIs.
1371   * 
1372   * 3. Relative paths
1373   * 
1374   * path  Resolves to [Y'][path]. Eg if Y resolves to hdfs://host/A and path 
1375   *       is "../B/file" then [Y'][path] is hdfs://host/B/file
1376   * 
1377   * 4. Absolute paths
1378   * 
1379   * path  Resolves to [X'][path]. Eg if Y resolves hdfs://host/A/B and path
1380   *       is "/file" then [X][path] is hdfs://host/file
1381   * </pre>
1382   * 
1383   * @param target the target of the symbolic link
1384   * @param link the path to be created that points to target
1385   * @param createParent if true then missing parent dirs are created if 
1386   *                     false then parent must exist
1387   *
1388   *
1389   * @throws AccessControlException If access is denied
1390   * @throws FileAlreadyExistsException If file <code>linkcode> already exists
1391   * @throws FileNotFoundException If <code>target</code> does not exist
1392   * @throws ParentNotDirectoryException If parent of <code>link</code> is not a
1393   *           directory.
1394   * @throws UnsupportedFileSystemException If file system for 
1395   *           <code>target</code> or <code>link</code> is not supported
1396   * @throws IOException If an I/O error occurred
1397   */
1398  @SuppressWarnings("deprecation")
1399  public void createSymlink(final Path target, final Path link,
1400      final boolean createParent) throws AccessControlException,
1401      FileAlreadyExistsException, FileNotFoundException,
1402      ParentNotDirectoryException, UnsupportedFileSystemException, 
1403      IOException { 
1404    if (!FileSystem.areSymlinksEnabled()) {
1405      throw new UnsupportedOperationException("Symlinks not supported");
1406    }
1407    final Path nonRelLink = fixRelativePart(link);
1408    new FSLinkResolver<Void>() {
1409      @Override
1410      public Void next(final AbstractFileSystem fs, final Path p) 
1411        throws IOException, UnresolvedLinkException {
1412        fs.createSymlink(target, p, createParent);
1413        return null;
1414      }
1415    }.resolve(this, nonRelLink);
1416  }
1417  
1418  /**
1419   * List the statuses of the files/directories in the given path if the path is
1420   * a directory.
1421   * 
1422   * @param f is the path
1423   *
1424   * @return an iterator that traverses statuses of the files/directories 
1425   *         in the given path
1426   *
1427   * @throws AccessControlException If access is denied
1428   * @throws FileNotFoundException If <code>f</code> does not exist
1429   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1430   *           not supported
1431   * @throws IOException If an I/O error occurred
1432   * 
1433   * Exceptions applicable to file systems accessed over RPC:
1434   * @throws RpcClientException If an exception occurred in the RPC client
1435   * @throws RpcServerException If an exception occurred in the RPC server
1436   * @throws UnexpectedServerException If server implementation throws 
1437   *           undeclared exception to RPC server
1438   */
1439  public RemoteIterator<FileStatus> listStatus(final Path f) throws
1440      AccessControlException, FileNotFoundException,
1441      UnsupportedFileSystemException, IOException {
1442    final Path absF = fixRelativePart(f);
1443    return new FSLinkResolver<RemoteIterator<FileStatus>>() {
1444      @Override
1445      public RemoteIterator<FileStatus> next(
1446          final AbstractFileSystem fs, final Path p) 
1447        throws IOException, UnresolvedLinkException {
1448        return fs.listStatusIterator(p);
1449      }
1450    }.resolve(this, absF);
1451  }
1452
1453  /**
1454   * @return an iterator over the corrupt files under the given path
1455   * (may contain duplicates if a file has more than one corrupt block)
1456   * @throws IOException
1457   */
1458  public RemoteIterator<Path> listCorruptFileBlocks(Path path)
1459    throws IOException {
1460    final Path absF = fixRelativePart(path);
1461    return new FSLinkResolver<RemoteIterator<Path>>() {
1462      @Override
1463      public RemoteIterator<Path> next(final AbstractFileSystem fs,
1464                                       final Path p) 
1465        throws IOException, UnresolvedLinkException {
1466        return fs.listCorruptFileBlocks(p);
1467      }
1468    }.resolve(this, absF);
1469  }
1470  
1471  /**
1472   * List the statuses of the files/directories in the given path if the path is
1473   * a directory. 
1474   * Return the file's status and block locations If the path is a file.
1475   * 
1476   * If a returned status is a file, it contains the file's block locations.
1477   * 
1478   * @param f is the path
1479   *
1480   * @return an iterator that traverses statuses of the files/directories 
1481   *         in the given path
1482   * If any IO exception (for example the input directory gets deleted while
1483   * listing is being executed), next() or hasNext() of the returned iterator
1484   * may throw a RuntimeException with the io exception as the cause.
1485   *
1486   * @throws AccessControlException If access is denied
1487   * @throws FileNotFoundException If <code>f</code> does not exist
1488   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1489   *           not supported
1490   * @throws IOException If an I/O error occurred
1491   * 
1492   * Exceptions applicable to file systems accessed over RPC:
1493   * @throws RpcClientException If an exception occurred in the RPC client
1494   * @throws RpcServerException If an exception occurred in the RPC server
1495   * @throws UnexpectedServerException If server implementation throws 
1496   *           undeclared exception to RPC server
1497   */
1498  public RemoteIterator<LocatedFileStatus> listLocatedStatus(
1499      final Path f) throws
1500      AccessControlException, FileNotFoundException,
1501      UnsupportedFileSystemException, IOException {
1502    final Path absF = fixRelativePart(f);
1503    return new FSLinkResolver<RemoteIterator<LocatedFileStatus>>() {
1504      @Override
1505      public RemoteIterator<LocatedFileStatus> next(
1506          final AbstractFileSystem fs, final Path p) 
1507        throws IOException, UnresolvedLinkException {
1508        return fs.listLocatedStatus(p);
1509      }
1510    }.resolve(this, absF);
1511  }
1512
1513  /**
1514   * Mark a path to be deleted on JVM shutdown.
1515   * 
1516   * @param f the existing path to delete.
1517   *
1518   * @return  true if deleteOnExit is successful, otherwise false.
1519   *
1520   * @throws AccessControlException If access is denied
1521   * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1522   *           not supported
1523   * @throws IOException If an I/O error occurred
1524   * 
1525   * Exceptions applicable to file systems accessed over RPC:
1526   * @throws RpcClientException If an exception occurred in the RPC client
1527   * @throws RpcServerException If an exception occurred in the RPC server
1528   * @throws UnexpectedServerException If server implementation throws 
1529   *           undeclared exception to RPC server
1530   */
1531  public boolean deleteOnExit(Path f) throws AccessControlException,
1532      IOException {
1533    if (!this.util().exists(f)) {
1534      return false;
1535    }
1536    synchronized (DELETE_ON_EXIT) {
1537      if (DELETE_ON_EXIT.isEmpty()) {
1538        ShutdownHookManager.get().addShutdownHook(FINALIZER, SHUTDOWN_HOOK_PRIORITY);
1539      }
1540      
1541      Set<Path> set = DELETE_ON_EXIT.get(this);
1542      if (set == null) {
1543        set = new TreeSet<Path>();
1544        DELETE_ON_EXIT.put(this, set);
1545      }
1546      set.add(f);
1547    }
1548    return true;
1549  }
1550  
1551  private final Util util;
1552  public Util util() {
1553    return util;
1554  }
1555  
1556  
1557  /**
1558   * Utility/library methods built over the basic FileContext methods.
1559   * Since this are library functions, the oprtation are not atomic
1560   * and some of them may partially complete if other threads are making
1561   * changes to the same part of the name space.
1562   */
1563  public class Util {
1564    /**
1565     * Does the file exist?
1566     * Note: Avoid using this method if you already have FileStatus in hand.
1567     * Instead reuse the FileStatus 
1568     * @param f the  file or dir to be checked
1569     *
1570     * @throws AccessControlException If access is denied
1571     * @throws IOException If an I/O error occurred
1572     * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1573     *           not supported
1574     * 
1575     * Exceptions applicable to file systems accessed over RPC:
1576     * @throws RpcClientException If an exception occurred in the RPC client
1577     * @throws RpcServerException If an exception occurred in the RPC server
1578     * @throws UnexpectedServerException If server implementation throws 
1579     *           undeclared exception to RPC server
1580     */
1581    public boolean exists(final Path f) throws AccessControlException,
1582      UnsupportedFileSystemException, IOException {
1583      try {
1584        FileStatus fs = FileContext.this.getFileStatus(f);
1585        assert fs != null;
1586        return true;
1587      } catch (FileNotFoundException e) {
1588        return false;
1589      }
1590    }
1591    
1592    /**
1593     * Return the {@link ContentSummary} of path f.
1594     * @param f path
1595     *
1596     * @return the {@link ContentSummary} of path f.
1597     *
1598     * @throws AccessControlException If access is denied
1599     * @throws FileNotFoundException If <code>f</code> does not exist
1600     * @throws UnsupportedFileSystemException If file system for 
1601     *         <code>f</code> is not supported
1602     * @throws IOException If an I/O error occurred
1603     * 
1604     * Exceptions applicable to file systems accessed over RPC:
1605     * @throws RpcClientException If an exception occurred in the RPC client
1606     * @throws RpcServerException If an exception occurred in the RPC server
1607     * @throws UnexpectedServerException If server implementation throws 
1608     *           undeclared exception to RPC server
1609     */
1610    public ContentSummary getContentSummary(Path f)
1611        throws AccessControlException, FileNotFoundException,
1612        UnsupportedFileSystemException, IOException {
1613      FileStatus status = FileContext.this.getFileStatus(f);
1614      if (status.isFile()) {
1615        return new ContentSummary(status.getLen(), 1, 0);
1616      }
1617      long[] summary = {0, 0, 1};
1618      RemoteIterator<FileStatus> statusIterator = 
1619        FileContext.this.listStatus(f);
1620      while(statusIterator.hasNext()) {
1621        FileStatus s = statusIterator.next();
1622        ContentSummary c = s.isDirectory() ? getContentSummary(s.getPath()) :
1623                                       new ContentSummary(s.getLen(), 1, 0);
1624        summary[0] += c.getLength();
1625        summary[1] += c.getFileCount();
1626        summary[2] += c.getDirectoryCount();
1627      }
1628      return new ContentSummary(summary[0], summary[1], summary[2]);
1629    }
1630    
1631    /**
1632     * See {@link #listStatus(Path[], PathFilter)}
1633     */
1634    public FileStatus[] listStatus(Path[] files) throws AccessControlException,
1635        FileNotFoundException, IOException {
1636      return listStatus(files, DEFAULT_FILTER);
1637    }
1638     
1639    /**
1640     * Filter files/directories in the given path using the user-supplied path
1641     * filter.
1642     * 
1643     * @param f is the path name
1644     * @param filter is the user-supplied path filter
1645     *
1646     * @return an array of FileStatus objects for the files under the given path
1647     *         after applying the filter
1648     *
1649     * @throws AccessControlException If access is denied
1650     * @throws FileNotFoundException If <code>f</code> does not exist
1651     * @throws UnsupportedFileSystemException If file system for 
1652     *         <code>pathPattern</code> is not supported
1653     * @throws IOException If an I/O error occurred
1654     * 
1655     * Exceptions applicable to file systems accessed over RPC:
1656     * @throws RpcClientException If an exception occurred in the RPC client
1657     * @throws RpcServerException If an exception occurred in the RPC server
1658     * @throws UnexpectedServerException If server implementation throws 
1659     *           undeclared exception to RPC server
1660     */
1661    public FileStatus[] listStatus(Path f, PathFilter filter)
1662        throws AccessControlException, FileNotFoundException,
1663        UnsupportedFileSystemException, IOException {
1664      ArrayList<FileStatus> results = new ArrayList<FileStatus>();
1665      listStatus(results, f, filter);
1666      return results.toArray(new FileStatus[results.size()]);
1667    }
1668    
1669    /**
1670     * Filter files/directories in the given list of paths using user-supplied
1671     * path filter.
1672     * 
1673     * @param files is a list of paths
1674     * @param filter is the filter
1675     *
1676     * @return a list of statuses for the files under the given paths after
1677     *         applying the filter
1678     *
1679     * @throws AccessControlException If access is denied
1680     * @throws FileNotFoundException If a file in <code>files</code> does not 
1681     *           exist
1682     * @throws IOException If an I/O error occurred
1683     * 
1684     * Exceptions applicable to file systems accessed over RPC:
1685     * @throws RpcClientException If an exception occurred in the RPC client
1686     * @throws RpcServerException If an exception occurred in the RPC server
1687     * @throws UnexpectedServerException If server implementation throws 
1688     *           undeclared exception to RPC server
1689     */
1690    public FileStatus[] listStatus(Path[] files, PathFilter filter)
1691        throws AccessControlException, FileNotFoundException, IOException {
1692      ArrayList<FileStatus> results = new ArrayList<FileStatus>();
1693      for (int i = 0; i < files.length; i++) {
1694        listStatus(results, files[i], filter);
1695      }
1696      return results.toArray(new FileStatus[results.size()]);
1697    }
1698  
1699    /*
1700     * Filter files/directories in the given path using the user-supplied path
1701     * filter. Results are added to the given array <code>results</code>.
1702     */
1703    private void listStatus(ArrayList<FileStatus> results, Path f,
1704        PathFilter filter) throws AccessControlException,
1705        FileNotFoundException, IOException {
1706      FileStatus[] listing = listStatus(f);
1707      if (listing != null) {
1708        for (int i = 0; i < listing.length; i++) {
1709          if (filter.accept(listing[i].getPath())) {
1710            results.add(listing[i]);
1711          }
1712        }
1713      }
1714    }
1715
1716    /**
1717     * List the statuses of the files/directories in the given path 
1718     * if the path is a directory.
1719     * 
1720     * @param f is the path
1721     *
1722     * @return an array that contains statuses of the files/directories 
1723     *         in the given path
1724     *
1725     * @throws AccessControlException If access is denied
1726     * @throws FileNotFoundException If <code>f</code> does not exist
1727     * @throws UnsupportedFileSystemException If file system for <code>f</code> is
1728     *           not supported
1729     * @throws IOException If an I/O error occurred
1730     * 
1731     * Exceptions applicable to file systems accessed over RPC:
1732     * @throws RpcClientException If an exception occurred in the RPC client
1733     * @throws RpcServerException If an exception occurred in the RPC server
1734     * @throws UnexpectedServerException If server implementation throws 
1735     *           undeclared exception to RPC server
1736     */
1737    public FileStatus[] listStatus(final Path f) throws AccessControlException,
1738        FileNotFoundException, UnsupportedFileSystemException,
1739        IOException {
1740      final Path absF = fixRelativePart(f);
1741      return new FSLinkResolver<FileStatus[]>() {
1742        @Override
1743        public FileStatus[] next(final AbstractFileSystem fs, final Path p) 
1744          throws IOException, UnresolvedLinkException {
1745          return fs.listStatus(p);
1746        }
1747      }.resolve(FileContext.this, absF);
1748    }
1749
1750    /**
1751     * List the statuses and block locations of the files in the given path.
1752     * 
1753     * If the path is a directory, 
1754     *   if recursive is false, returns files in the directory;
1755     *   if recursive is true, return files in the subtree rooted at the path.
1756     *   The subtree is traversed in the depth-first order.
1757     * If the path is a file, return the file's status and block locations.
1758     * Files across symbolic links are also returned.
1759     * 
1760     * @param f is the path
1761     * @param recursive if the subdirectories need to be traversed recursively
1762     *
1763     * @return an iterator that traverses statuses of the files
1764     * If any IO exception (for example a sub-directory gets deleted while
1765     * listing is being executed), next() or hasNext() of the returned iterator
1766     * may throw a RuntimeException with the IO exception as the cause.
1767     *
1768     * @throws AccessControlException If access is denied
1769     * @throws FileNotFoundException If <code>f</code> does not exist
1770     * @throws UnsupportedFileSystemException If file system for <code>f</code>
1771     *         is not supported
1772     * @throws IOException If an I/O error occurred
1773     * 
1774     * Exceptions applicable to file systems accessed over RPC:
1775     * @throws RpcClientException If an exception occurred in the RPC client
1776     * @throws RpcServerException If an exception occurred in the RPC server
1777     * @throws UnexpectedServerException If server implementation throws 
1778     *           undeclared exception to RPC server
1779     */
1780    public RemoteIterator<LocatedFileStatus> listFiles(
1781        final Path f, final boolean recursive) throws AccessControlException,
1782        FileNotFoundException, UnsupportedFileSystemException, 
1783        IOException {
1784      return new RemoteIterator<LocatedFileStatus>() {
1785        private Stack<RemoteIterator<LocatedFileStatus>> itors = 
1786          new Stack<RemoteIterator<LocatedFileStatus>>();
1787        RemoteIterator<LocatedFileStatus> curItor = listLocatedStatus(f);
1788        LocatedFileStatus curFile;
1789
1790        /**
1791         * Returns <tt>true</tt> if the iterator has more files.
1792         *
1793         * @return <tt>true</tt> if the iterator has more files.
1794         * @throws AccessControlException if not allowed to access next
1795         *                                file's status or locations
1796         * @throws FileNotFoundException if next file does not exist any more
1797         * @throws UnsupportedFileSystemException if next file's 
1798         *                                        fs is unsupported
1799         * @throws IOException for all other IO errors
1800         *                     for example, NameNode is not avaialbe or
1801         *                     NameNode throws IOException due to an error
1802         *                     while getting the status or block locations
1803         */
1804        @Override
1805        public boolean hasNext() throws IOException {
1806          while (curFile == null) {
1807            if (curItor.hasNext()) {
1808              handleFileStat(curItor.next());
1809            } else if (!itors.empty()) {
1810              curItor = itors.pop();
1811            } else {
1812              return false;
1813            }
1814          }
1815          return true;
1816        }
1817
1818        /**
1819         * Process the input stat.
1820         * If it is a file, return the file stat.
1821         * If it is a directory, traverse the directory if recursive is true;
1822         * ignore it if recursive is false.
1823         * If it is a symlink, resolve the symlink first and then process it
1824         * depending on if it is a file or directory.
1825         * @param stat input status
1826         * @throws AccessControlException if access is denied
1827         * @throws FileNotFoundException if file is not found
1828         * @throws UnsupportedFileSystemException if fs is not supported
1829         * @throws IOException for all other IO errors
1830         */
1831        private void handleFileStat(LocatedFileStatus stat)
1832        throws IOException {
1833          if (stat.isFile()) { // file
1834            curFile = stat;
1835          } else if (stat.isSymlink()) { // symbolic link
1836            // resolve symbolic link
1837            FileStatus symstat = FileContext.this.getFileStatus(
1838                stat.getSymlink());
1839            if (symstat.isFile() || (recursive && symstat.isDirectory())) {
1840              itors.push(curItor);
1841              curItor = listLocatedStatus(stat.getPath());
1842            }
1843          } else if (recursive) { // directory
1844            itors.push(curItor);
1845            curItor = listLocatedStatus(stat.getPath());
1846          }
1847        }
1848
1849        /**
1850         * Returns the next file's status with its block locations
1851         *
1852         * @throws AccessControlException if not allowed to access next
1853         *                                file's status or locations
1854         * @throws FileNotFoundException if next file does not exist any more
1855         * @throws UnsupportedFileSystemException if next file's 
1856         *                                        fs is unsupported
1857         * @throws IOException for all other IO errors
1858         *                     for example, NameNode is not avaialbe or
1859         *                     NameNode throws IOException due to an error
1860         *                     while getting the status or block locations
1861         */
1862        @Override
1863        public LocatedFileStatus next() throws IOException {
1864          if (hasNext()) {
1865            LocatedFileStatus result = curFile;
1866            curFile = null;
1867            return result;
1868          } 
1869          throw new java.util.NoSuchElementException("No more entry in " + f);
1870        }
1871      };
1872    }
1873
1874    /**
1875     * <p>Return all the files that match filePattern and are not checksum
1876     * files. Results are sorted by their names.
1877     * 
1878     * <p>
1879     * A filename pattern is composed of <i>regular</i> characters and
1880     * <i>special pattern matching</i> characters, which are:
1881     *
1882     * <dl>
1883     *  <dd>
1884     *   <dl>
1885     *    <p>
1886     *    <dt> <tt> ? </tt>
1887     *    <dd> Matches any single character.
1888     *
1889     *    <p>
1890     *    <dt> <tt> * </tt>
1891     *    <dd> Matches zero or more characters.
1892     *
1893     *    <p>
1894     *    <dt> <tt> [<i>abc</i>] </tt>
1895     *    <dd> Matches a single character from character set
1896     *     <tt>{<i>a,b,c</i>}</tt>.
1897     *
1898     *    <p>
1899     *    <dt> <tt> [<i>a</i>-<i>b</i>] </tt>
1900     *    <dd> Matches a single character from the character range
1901     *     <tt>{<i>a...b</i>}</tt>. Note: character <tt><i>a</i></tt> must be
1902     *     lexicographically less than or equal to character <tt><i>b</i></tt>.
1903     *
1904     *    <p>
1905     *    <dt> <tt> [^<i>a</i>] </tt>
1906     *    <dd> Matches a single char that is not from character set or range
1907     *     <tt>{<i>a</i>}</tt>.  Note that the <tt>^</tt> character must occur
1908     *     immediately to the right of the opening bracket.
1909     *
1910     *    <p>
1911     *    <dt> <tt> \<i>c</i> </tt>
1912     *    <dd> Removes (escapes) any special meaning of character <i>c</i>.
1913     *
1914     *    <p>
1915     *    <dt> <tt> {ab,cd} </tt>
1916     *    <dd> Matches a string from the string set <tt>{<i>ab, cd</i>} </tt>
1917     *    
1918     *    <p>
1919     *    <dt> <tt> {ab,c{de,fh}} </tt>
1920     *    <dd> Matches a string from string set <tt>{<i>ab, cde, cfh</i>}</tt>
1921     *
1922     *   </dl>
1923     *  </dd>
1924     * </dl>
1925     *
1926     * @param pathPattern a regular expression specifying a pth pattern
1927     *
1928     * @return an array of paths that match the path pattern
1929     *
1930     * @throws AccessControlException If access is denied
1931     * @throws UnsupportedFileSystemException If file system for 
1932     *         <code>pathPattern</code> is not supported
1933     * @throws IOException If an I/O error occurred
1934     * 
1935     * Exceptions applicable to file systems accessed over RPC:
1936     * @throws RpcClientException If an exception occurred in the RPC client
1937     * @throws RpcServerException If an exception occurred in the RPC server
1938     * @throws UnexpectedServerException If server implementation throws 
1939     *           undeclared exception to RPC server
1940     */
1941    public FileStatus[] globStatus(Path pathPattern)
1942        throws AccessControlException, UnsupportedFileSystemException,
1943        IOException {
1944      return new Globber(FileContext.this, pathPattern, DEFAULT_FILTER).glob();
1945    }
1946    
1947    /**
1948     * Return an array of FileStatus objects whose path names match pathPattern
1949     * and is accepted by the user-supplied path filter. Results are sorted by
1950     * their path names.
1951     * Return null if pathPattern has no glob and the path does not exist.
1952     * Return an empty array if pathPattern has a glob and no path matches it. 
1953     * 
1954     * @param pathPattern regular expression specifying the path pattern
1955     * @param filter user-supplied path filter
1956     *
1957     * @return an array of FileStatus objects
1958     *
1959     * @throws AccessControlException If access is denied
1960     * @throws UnsupportedFileSystemException If file system for 
1961     *         <code>pathPattern</code> is not supported
1962     * @throws IOException If an I/O error occurred
1963     * 
1964     * Exceptions applicable to file systems accessed over RPC:
1965     * @throws RpcClientException If an exception occurred in the RPC client
1966     * @throws RpcServerException If an exception occurred in the RPC server
1967     * @throws UnexpectedServerException If server implementation throws 
1968     *           undeclared exception to RPC server
1969     */
1970    public FileStatus[] globStatus(final Path pathPattern,
1971        final PathFilter filter) throws AccessControlException,
1972        UnsupportedFileSystemException, IOException {
1973      return new Globber(FileContext.this, pathPattern, filter).glob();
1974    }
1975
1976    /**
1977     * Copy file from src to dest. See
1978     * {@link #copy(Path, Path, boolean, boolean)}
1979     */
1980    public boolean copy(final Path src, final Path dst)
1981        throws AccessControlException, FileAlreadyExistsException,
1982        FileNotFoundException, ParentNotDirectoryException,
1983        UnsupportedFileSystemException, IOException {
1984      return copy(src, dst, false, false);
1985    }
1986    
1987    /**
1988     * Copy from src to dst, optionally deleting src and overwriting dst.
1989     * @param src
1990     * @param dst
1991     * @param deleteSource - delete src if true
1992     * @param overwrite  overwrite dst if true; throw IOException if dst exists
1993     *         and overwrite is false.
1994     *
1995     * @return true if copy is successful
1996     *
1997     * @throws AccessControlException If access is denied
1998     * @throws FileAlreadyExistsException If <code>dst</code> already exists
1999     * @throws FileNotFoundException If <code>src</code> does not exist
2000     * @throws ParentNotDirectoryException If parent of <code>dst</code> is not
2001     *           a directory
2002     * @throws UnsupportedFileSystemException If file system for 
2003     *         <code>src</code> or <code>dst</code> is not supported
2004     * @throws IOException If an I/O error occurred
2005     * 
2006     * Exceptions applicable to file systems accessed over RPC:
2007     * @throws RpcClientException If an exception occurred in the RPC client
2008     * @throws RpcServerException If an exception occurred in the RPC server
2009     * @throws UnexpectedServerException If server implementation throws 
2010     *           undeclared exception to RPC server
2011     * 
2012     * RuntimeExceptions:
2013     * @throws InvalidPathException If path <code>dst</code> is invalid
2014     */
2015    public boolean copy(final Path src, final Path dst, boolean deleteSource,
2016        boolean overwrite) throws AccessControlException,
2017        FileAlreadyExistsException, FileNotFoundException,
2018        ParentNotDirectoryException, UnsupportedFileSystemException, 
2019        IOException {
2020      src.checkNotSchemeWithRelative();
2021      dst.checkNotSchemeWithRelative();
2022      Path qSrc = makeQualified(src);
2023      Path qDst = makeQualified(dst);
2024      checkDest(qSrc.getName(), qDst, overwrite);
2025      FileStatus fs = FileContext.this.getFileStatus(qSrc);
2026      if (fs.isDirectory()) {
2027        checkDependencies(qSrc, qDst);
2028        mkdir(qDst, FsPermission.getDirDefault(), true);
2029        FileStatus[] contents = listStatus(qSrc);
2030        for (FileStatus content : contents) {
2031          copy(makeQualified(content.getPath()), makeQualified(new Path(qDst,
2032              content.getPath().getName())), deleteSource, overwrite);
2033        }
2034      } else {
2035        InputStream in=null;
2036        OutputStream out = null;
2037        try {
2038          in = open(qSrc);
2039          EnumSet<CreateFlag> createFlag = overwrite ? EnumSet.of(
2040              CreateFlag.CREATE, CreateFlag.OVERWRITE) : 
2041                EnumSet.of(CreateFlag.CREATE);
2042          out = create(qDst, createFlag);
2043          IOUtils.copyBytes(in, out, conf, true);
2044        } finally {
2045          IOUtils.closeStream(out);
2046          IOUtils.closeStream(in);
2047        }
2048      }
2049      if (deleteSource) {
2050        return delete(qSrc, true);
2051      } else {
2052        return true;
2053      }
2054    }
2055  }
2056
2057  /**
2058   * Check if copying srcName to dst would overwrite an existing 
2059   * file or directory.
2060   * @param srcName File or directory to be copied.
2061   * @param dst Destination to copy srcName to.
2062   * @param overwrite Whether it's ok to overwrite an existing file. 
2063   * @throws AccessControlException If access is denied.
2064   * @throws IOException If dst is an existing directory, or dst is an 
2065   * existing file and the overwrite option is not passed.
2066   */
2067  private void checkDest(String srcName, Path dst, boolean overwrite)
2068      throws AccessControlException, IOException {
2069    try {
2070      FileStatus dstFs = getFileStatus(dst);
2071      if (dstFs.isDirectory()) {
2072        if (null == srcName) {
2073          throw new IOException("Target " + dst + " is a directory");
2074        }
2075        // Recurse to check if dst/srcName exists.
2076        checkDest(null, new Path(dst, srcName), overwrite);
2077      } else if (!overwrite) {
2078        throw new IOException("Target " + new Path(dst, srcName)
2079            + " already exists");
2080      }
2081    } catch (FileNotFoundException e) {
2082      // dst does not exist - OK to copy.
2083    }
2084  }
2085   
2086  //
2087  // If the destination is a subdirectory of the source, then
2088  // generate exception
2089  //
2090  private static void checkDependencies(Path qualSrc, Path qualDst)
2091    throws IOException {
2092    if (isSameFS(qualSrc, qualDst)) {
2093      String srcq = qualSrc.toString() + Path.SEPARATOR;
2094      String dstq = qualDst.toString() + Path.SEPARATOR;
2095      if (dstq.startsWith(srcq)) {
2096        if (srcq.length() == dstq.length()) {
2097          throw new IOException("Cannot copy " + qualSrc + " to itself.");
2098        } else {
2099          throw new IOException("Cannot copy " + qualSrc +
2100                             " to its subdirectory " + qualDst);
2101        }
2102      }
2103    }
2104  }
2105  
2106  /**
2107   * Are qualSrc and qualDst of the same file system?
2108   * @param qualPath1 - fully qualified path
2109   * @param qualPath2 - fully qualified path
2110   * @return
2111   */
2112  private static boolean isSameFS(Path qualPath1, Path qualPath2) {
2113    URI srcUri = qualPath1.toUri();
2114    URI dstUri = qualPath2.toUri();
2115    return (srcUri.getScheme().equals(dstUri.getScheme()) && 
2116        !(srcUri.getAuthority() != null && dstUri.getAuthority() != null && srcUri
2117        .getAuthority().equals(dstUri.getAuthority())));
2118  }
2119
2120  /**
2121   * Deletes all the paths in deleteOnExit on JVM shutdown.
2122   */
2123  static class FileContextFinalizer implements Runnable {
2124    @Override
2125    public synchronized void run() {
2126      processDeleteOnExit();
2127    }
2128  }
2129
2130  /**
2131   * Resolves all symbolic links in the specified path.
2132   * Returns the new path object.
2133   */
2134  protected Path resolve(final Path f) throws FileNotFoundException,
2135      UnresolvedLinkException, AccessControlException, IOException {
2136    return new FSLinkResolver<Path>() {
2137      @Override
2138      public Path next(final AbstractFileSystem fs, final Path p) 
2139        throws IOException, UnresolvedLinkException {
2140        return fs.resolvePath(p);
2141      }
2142    }.resolve(this, f);
2143  }
2144
2145  /**
2146   * Resolves all symbolic links in the specified path leading up 
2147   * to, but not including the final path component.
2148   * @param f path to resolve
2149   * @return the new path object.
2150   */
2151  protected Path resolveIntermediate(final Path f) throws IOException {
2152    return new FSLinkResolver<FileStatus>() {
2153      @Override
2154      public FileStatus next(final AbstractFileSystem fs, final Path p) 
2155        throws IOException, UnresolvedLinkException {
2156        return fs.getFileLinkStatus(p);
2157      }
2158    }.resolve(this, f).getPath();
2159  }
2160
2161  /**
2162   * Returns the list of AbstractFileSystems accessed in the path. The list may
2163   * contain more than one AbstractFileSystems objects in case of symlinks.
2164   * 
2165   * @param f
2166   *          Path which needs to be resolved
2167   * @return List of AbstractFileSystems accessed in the path
2168   * @throws IOException
2169   */
2170  Set<AbstractFileSystem> resolveAbstractFileSystems(final Path f)
2171      throws IOException {
2172    final Path absF = fixRelativePart(f);
2173    final HashSet<AbstractFileSystem> result 
2174      = new HashSet<AbstractFileSystem>();
2175    new FSLinkResolver<Void>() {
2176      @Override
2177      public Void next(final AbstractFileSystem fs, final Path p)
2178          throws IOException, UnresolvedLinkException {
2179        result.add(fs);
2180        fs.getFileStatus(p);
2181        return null;
2182      }
2183    }.resolve(this, absF);
2184    return result;
2185  }
2186
2187  /**
2188   * Get the statistics for a particular file system
2189   * 
2190   * @param uri
2191   *          the uri to lookup the statistics. Only scheme and authority part
2192   *          of the uri are used as the key to store and lookup.
2193   * @return a statistics object
2194   */
2195  public static Statistics getStatistics(URI uri) {
2196    return AbstractFileSystem.getStatistics(uri);
2197  }
2198
2199  /**
2200   * Clears all the statistics stored in AbstractFileSystem, for all the file
2201   * systems.
2202   */
2203  public static void clearStatistics() {
2204    AbstractFileSystem.clearStatistics();
2205  }
2206
2207  /**
2208   * Prints the statistics to standard output. File System is identified by the
2209   * scheme and authority.
2210   */
2211  public static void printStatistics() {
2212    AbstractFileSystem.printStatistics();
2213  }
2214
2215  /**
2216   * @return Map of uri and statistics for each filesystem instantiated. The uri
2217   *         consists of scheme and authority for the filesystem.
2218   */
2219  public static Map<URI, Statistics> getAllStatistics() {
2220    return AbstractFileSystem.getAllStatistics();
2221  }
2222  
2223  /**
2224   * Get delegation tokens for the file systems accessed for a given
2225   * path.
2226   * @param p Path for which delegations tokens are requested.
2227   * @param renewer the account name that is allowed to renew the token.
2228   * @return List of delegation tokens.
2229   * @throws IOException
2230   */
2231  @InterfaceAudience.LimitedPrivate( { "HDFS", "MapReduce" })
2232  public List<Token<?>> getDelegationTokens(
2233      Path p, String renewer) throws IOException {
2234    Set<AbstractFileSystem> afsSet = resolveAbstractFileSystems(p);
2235    List<Token<?>> tokenList = 
2236        new ArrayList<Token<?>>();
2237    for (AbstractFileSystem afs : afsSet) {
2238      List<Token<?>> afsTokens = afs.getDelegationTokens(renewer);
2239      tokenList.addAll(afsTokens);
2240    }
2241    return tokenList;
2242  }
2243
2244  /**
2245   * Modifies ACL entries of files and directories.  This method can add new ACL
2246   * entries or modify the permissions on existing ACL entries.  All existing
2247   * ACL entries that are not specified in this call are retained without
2248   * changes.  (Modifications are merged into the current ACL.)
2249   *
2250   * @param path Path to modify
2251   * @param aclSpec List<AclEntry> describing modifications
2252   * @throws IOException if an ACL could not be modified
2253   */
2254  public void modifyAclEntries(final Path path, final List<AclEntry> aclSpec)
2255      throws IOException {
2256    Path absF = fixRelativePart(path);
2257    new FSLinkResolver<Void>() {
2258      @Override
2259      public Void next(final AbstractFileSystem fs, final Path p)
2260          throws IOException {
2261        fs.modifyAclEntries(p, aclSpec);
2262        return null;
2263      }
2264    }.resolve(this, absF);
2265  }
2266
2267  /**
2268   * Removes ACL entries from files and directories.  Other ACL entries are
2269   * retained.
2270   *
2271   * @param path Path to modify
2272   * @param aclSpec List<AclEntry> describing entries to remove
2273   * @throws IOException if an ACL could not be modified
2274   */
2275  public void removeAclEntries(final Path path, final List<AclEntry> aclSpec)
2276      throws IOException {
2277    Path absF = fixRelativePart(path);
2278    new FSLinkResolver<Void>() {
2279      @Override
2280      public Void next(final AbstractFileSystem fs, final Path p)
2281          throws IOException {
2282        fs.removeAclEntries(p, aclSpec);
2283        return null;
2284      }
2285    }.resolve(this, absF);
2286  }
2287
2288  /**
2289   * Removes all default ACL entries from files and directories.
2290   *
2291   * @param path Path to modify
2292   * @throws IOException if an ACL could not be modified
2293   */
2294  public void removeDefaultAcl(Path path)
2295      throws IOException {
2296    Path absF = fixRelativePart(path);
2297    new FSLinkResolver<Void>() {
2298      @Override
2299      public Void next(final AbstractFileSystem fs, final Path p)
2300          throws IOException {
2301        fs.removeDefaultAcl(p);
2302        return null;
2303      }
2304    }.resolve(this, absF);
2305  }
2306
2307  /**
2308   * Removes all but the base ACL entries of files and directories.  The entries
2309   * for user, group, and others are retained for compatibility with permission
2310   * bits.
2311   *
2312   * @param path Path to modify
2313   * @throws IOException if an ACL could not be removed
2314   */
2315  public void removeAcl(Path path) throws IOException {
2316    Path absF = fixRelativePart(path);
2317    new FSLinkResolver<Void>() {
2318      @Override
2319      public Void next(final AbstractFileSystem fs, final Path p)
2320          throws IOException {
2321        fs.removeAcl(p);
2322        return null;
2323      }
2324    }.resolve(this, absF);
2325  }
2326
2327  /**
2328   * Fully replaces ACL of files and directories, discarding all existing
2329   * entries.
2330   *
2331   * @param path Path to modify
2332   * @param aclSpec List<AclEntry> describing modifications, must include entries
2333   *   for user, group, and others for compatibility with permission bits.
2334   * @throws IOException if an ACL could not be modified
2335   */
2336  public void setAcl(Path path, final List<AclEntry> aclSpec)
2337      throws IOException {
2338    Path absF = fixRelativePart(path);
2339    new FSLinkResolver<Void>() {
2340      @Override
2341      public Void next(final AbstractFileSystem fs, final Path p)
2342          throws IOException {
2343        fs.setAcl(p, aclSpec);
2344        return null;
2345      }
2346    }.resolve(this, absF);
2347  }
2348
2349  /**
2350   * Gets the ACLs of files and directories.
2351   *
2352   * @param path Path to get
2353   * @return RemoteIterator<AclStatus> which returns each AclStatus
2354   * @throws IOException if an ACL could not be read
2355   */
2356  public AclStatus getAclStatus(Path path) throws IOException {
2357    Path absF = fixRelativePart(path);
2358    return new FSLinkResolver<AclStatus>() {
2359      @Override
2360      public AclStatus next(final AbstractFileSystem fs, final Path p)
2361          throws IOException {
2362        return fs.getAclStatus(p);
2363      }
2364    }.resolve(this, absF);
2365  }
2366
2367  /**
2368   * Set an xattr of a file or directory.
2369   * The name must be prefixed with the namespace followed by ".". For example,
2370   * "user.attr".
2371   * <p/>
2372   * Refer to the HDFS extended attributes user documentation for details.
2373   *
2374   * @param path Path to modify
2375   * @param name xattr name.
2376   * @param value xattr value.
2377   * @throws IOException
2378   */
2379  public void setXAttr(Path path, String name, byte[] value)
2380      throws IOException {
2381    setXAttr(path, name, value, EnumSet.of(XAttrSetFlag.CREATE,
2382        XAttrSetFlag.REPLACE));
2383  }
2384
2385  /**
2386   * Set an xattr of a file or directory.
2387   * The name must be prefixed with the namespace followed by ".". For example,
2388   * "user.attr".
2389   * <p/>
2390   * Refer to the HDFS extended attributes user documentation for details.
2391   *
2392   * @param path Path to modify
2393   * @param name xattr name.
2394   * @param value xattr value.
2395   * @param flag xattr set flag
2396   * @throws IOException
2397   */
2398  public void setXAttr(Path path, final String name, final byte[] value,
2399      final EnumSet<XAttrSetFlag> flag) throws IOException {
2400    final Path absF = fixRelativePart(path);
2401    new FSLinkResolver<Void>() {
2402      @Override
2403      public Void next(final AbstractFileSystem fs, final Path p)
2404          throws IOException {
2405        fs.setXAttr(p, name, value, flag);
2406        return null;
2407      }
2408    }.resolve(this, absF);
2409  }
2410
2411  /**
2412   * Get an xattr for a file or directory.
2413   * The name must be prefixed with the namespace followed by ".". For example,
2414   * "user.attr".
2415   * <p/>
2416   * Refer to the HDFS extended attributes user documentation for details.
2417   *
2418   * @param path Path to get extended attribute
2419   * @param name xattr name.
2420   * @return byte[] xattr value.
2421   * @throws IOException
2422   */
2423  public byte[] getXAttr(Path path, final String name) throws IOException {
2424    final Path absF = fixRelativePart(path);
2425    return new FSLinkResolver<byte[]>() {
2426      @Override
2427      public byte[] next(final AbstractFileSystem fs, final Path p)
2428          throws IOException {
2429        return fs.getXAttr(p, name);
2430      }
2431    }.resolve(this, absF);
2432  }
2433
2434  /**
2435   * Get all of the xattrs for a file or directory.
2436   * Only those xattrs for which the logged-in user has permissions to view
2437   * are returned.
2438   * <p/>
2439   * Refer to the HDFS extended attributes user documentation for details.
2440   *
2441   * @param path Path to get extended attributes
2442   * @return Map<String, byte[]> describing the XAttrs of the file or directory
2443   * @throws IOException
2444   */
2445  public Map<String, byte[]> getXAttrs(Path path) throws IOException {
2446    final Path absF = fixRelativePart(path);
2447    return new FSLinkResolver<Map<String, byte[]>>() {
2448      @Override
2449      public Map<String, byte[]> next(final AbstractFileSystem fs, final Path p)
2450          throws IOException {
2451        return fs.getXAttrs(p);
2452      }
2453    }.resolve(this, absF);
2454  }
2455
2456  /**
2457   * Get all of the xattrs for a file or directory.
2458   * Only those xattrs for which the logged-in user has permissions to view
2459   * are returned.
2460   * <p/>
2461   * Refer to the HDFS extended attributes user documentation for details.
2462   *
2463   * @param path Path to get extended attributes
2464   * @param names XAttr names.
2465   * @return Map<String, byte[]> describing the XAttrs of the file or directory
2466   * @throws IOException
2467   */
2468  public Map<String, byte[]> getXAttrs(Path path, final List<String> names)
2469      throws IOException {
2470    final Path absF = fixRelativePart(path);
2471    return new FSLinkResolver<Map<String, byte[]>>() {
2472      @Override
2473      public Map<String, byte[]> next(final AbstractFileSystem fs, final Path p)
2474          throws IOException {
2475        return fs.getXAttrs(p, names);
2476      }
2477    }.resolve(this, absF);
2478  }
2479
2480  /**
2481   * Remove an xattr of a file or directory.
2482   * The name must be prefixed with the namespace followed by ".". For example,
2483   * "user.attr".
2484   * <p/>
2485   * Refer to the HDFS extended attributes user documentation for details.
2486   *
2487   * @param path Path to remove extended attribute
2488   * @param name xattr name
2489   * @throws IOException
2490   */
2491  public void removeXAttr(Path path, final String name) throws IOException {
2492    final Path absF = fixRelativePart(path);
2493    new FSLinkResolver<Void>() {
2494      @Override
2495      public Void next(final AbstractFileSystem fs, final Path p)
2496          throws IOException {
2497        fs.removeXAttr(p, name);
2498        return null;
2499      }
2500    }.resolve(this, absF);
2501  }
2502
2503  /**
2504   * Get all of the xattr names for a file or directory.
2505   * Only those xattr names which the logged-in user has permissions to view
2506   * are returned.
2507   * <p/>
2508   * Refer to the HDFS extended attributes user documentation for details.
2509   *
2510   * @param path Path to get extended attributes
2511   * @return List<String> of the XAttr names of the file or directory
2512   * @throws IOException
2513   */
2514  public List<String> listXAttrs(Path path) throws IOException {
2515    final Path absF = fixRelativePart(path);
2516    return new FSLinkResolver<List<String>>() {
2517      @Override
2518      public List<String> next(final AbstractFileSystem fs, final Path p)
2519          throws IOException {
2520        return fs.listXAttrs(p);
2521      }
2522    }.resolve(this, absF);
2523  }
2524
2525  Tracer getTracer() {
2526    return tracer;
2527  }
2528}