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

网格计算

开发平台:

Java

  1. /**
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  *     http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing, software
  13.  * distributed under the License is distributed on an "AS IS" BASIS,
  14.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15.  * See the License for the specific language governing permissions and
  16.  * limitations under the License.
  17.  */
  18. package org.apache.hadoop.fs;
  19. import java.io.File;
  20. import java.io.FileNotFoundException;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import java.net.URI;
  24. import java.text.DecimalFormat;
  25. import java.text.NumberFormat;
  26. import java.text.SimpleDateFormat;
  27. import java.util.*;
  28. import java.util.zip.GZIPInputStream;
  29. import org.apache.hadoop.conf.Configuration;
  30. import org.apache.hadoop.conf.Configured;
  31. import org.apache.hadoop.fs.shell.CommandFormat;
  32. import org.apache.hadoop.fs.shell.Count;
  33. import org.apache.hadoop.io.DataInputBuffer;
  34. import org.apache.hadoop.io.DataOutputBuffer;
  35. import org.apache.hadoop.io.IOUtils;
  36. import org.apache.hadoop.io.SequenceFile;
  37. import org.apache.hadoop.io.Writable;
  38. import org.apache.hadoop.io.WritableComparable;
  39. import org.apache.hadoop.ipc.RPC;
  40. import org.apache.hadoop.ipc.RemoteException;
  41. import org.apache.hadoop.util.ReflectionUtils;
  42. import org.apache.hadoop.util.Tool;
  43. import org.apache.hadoop.util.ToolRunner;
  44. import org.apache.hadoop.util.StringUtils;
  45. /** Provide command line access to a FileSystem. */
  46. public class FsShell extends Configured implements Tool {
  47.   protected FileSystem fs;
  48.   private Trash trash;
  49.   public static final SimpleDateFormat dateForm = 
  50.     new SimpleDateFormat("yyyy-MM-dd HH:mm");
  51.   protected static final SimpleDateFormat modifFmt =
  52.     new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  53.   static final int BORDER = 2;
  54.   static {
  55.     modifFmt.setTimeZone(TimeZone.getTimeZone("UTC"));
  56.   }
  57.   static final String SETREP_SHORT_USAGE="-setrep [-R] [-w] <rep> <path/file>";
  58.   static final String GET_SHORT_USAGE = "-get [-ignoreCrc] [-crc] <src> <localdst>";
  59.   static final String COPYTOLOCAL_SHORT_USAGE = GET_SHORT_USAGE.replace(
  60.       "-get", "-copyToLocal");
  61.   static final String TAIL_USAGE="-tail [-f] <file>";
  62.   /**
  63.    */
  64.   public FsShell() {
  65.     this(null);
  66.   }
  67.   public FsShell(Configuration conf) {
  68.     super(conf);
  69.     fs = null;
  70.     trash = null;
  71.   }
  72.   
  73.   protected void init() throws IOException {
  74.     getConf().setQuietMode(true);
  75.     if (this.fs == null) {
  76.      this.fs = FileSystem.get(getConf());
  77.     }
  78.     if (this.trash == null) {
  79.       this.trash = new Trash(getConf());
  80.     }
  81.   }
  82.   
  83.   /**
  84.    * Copies from stdin to the indicated file.
  85.    */
  86.   private void copyFromStdin(Path dst, FileSystem dstFs) throws IOException {
  87.     if (dstFs.isDirectory(dst)) {
  88.       throw new IOException("When source is stdin, destination must be a file.");
  89.     }
  90.     if (dstFs.exists(dst)) {
  91.       throw new IOException("Target " + dst.toString() + " already exists.");
  92.     }
  93.     FSDataOutputStream out = dstFs.create(dst); 
  94.     try {
  95.       IOUtils.copyBytes(System.in, out, getConf(), false);
  96.     } 
  97.     finally {
  98.       out.close();
  99.     }
  100.   }
  101.   /** 
  102.    * Print from src to stdout.
  103.    */
  104.   private void printToStdout(InputStream in) throws IOException {
  105.     try {
  106.       IOUtils.copyBytes(in, System.out, getConf(), false);
  107.     } finally {
  108.       in.close();
  109.     }
  110.   }
  111.   
  112.   /**
  113.    * Add local files to the indicated FileSystem name. src is kept.
  114.    */
  115.   void copyFromLocal(Path[] srcs, String dstf) throws IOException {
  116.     Path dstPath = new Path(dstf);
  117.     FileSystem dstFs = dstPath.getFileSystem(getConf());
  118.     if (srcs.length == 1 && srcs[0].toString().equals("-"))
  119.       copyFromStdin(dstPath, dstFs);
  120.     else
  121.       dstFs.copyFromLocalFile(false, false, srcs, dstPath);
  122.   }
  123.   
  124.   /**
  125.    * Add local files to the indicated FileSystem name. src is removed.
  126.    */
  127.   void moveFromLocal(Path[] srcs, String dstf) throws IOException {
  128.     Path dstPath = new Path(dstf);
  129.     FileSystem dstFs = dstPath.getFileSystem(getConf());
  130.     dstFs.moveFromLocalFile(srcs, dstPath);
  131.   }
  132.   /**
  133.    * Add a local file to the indicated FileSystem name. src is removed.
  134.    */
  135.   void moveFromLocal(Path src, String dstf) throws IOException {
  136.     moveFromLocal((new Path[]{src}), dstf);
  137.   }
  138.   /**
  139.    * Obtain the indicated files that match the file pattern <i>srcf</i>
  140.    * and copy them to the local name. srcf is kept.
  141.    * When copying multiple files, the destination must be a directory. 
  142.    * Otherwise, IOException is thrown.
  143.    * @param argv: arguments
  144.    * @param pos: Ignore everything before argv[pos]  
  145.    * @exception: IOException  
  146.    * @see org.apache.hadoop.fs.FileSystem.globStatus 
  147.    */
  148.   void copyToLocal(String[]argv, int pos) throws IOException {
  149.     CommandFormat cf = new CommandFormat("copyToLocal", 2,2,"crc","ignoreCrc");
  150.     
  151.     String srcstr = null;
  152.     String dststr = null;
  153.     try {
  154.       List<String> parameters = cf.parse(argv, pos);
  155.       srcstr = parameters.get(0);
  156.       dststr = parameters.get(1);
  157.     }
  158.     catch(IllegalArgumentException iae) {
  159.       System.err.println("Usage: java FsShell " + GET_SHORT_USAGE);
  160.       throw iae;
  161.     }
  162.     boolean copyCrc = cf.getOpt("crc");
  163.     final boolean verifyChecksum = !cf.getOpt("ignoreCrc");
  164.     if (dststr.equals("-")) {
  165.       if (copyCrc) {
  166.         System.err.println("-crc option is not valid when destination is stdout.");
  167.       }
  168.       cat(srcstr, verifyChecksum);
  169.     } else {
  170.       File dst = new File(dststr);      
  171.       Path srcpath = new Path(srcstr);
  172.       FileSystem srcFS = getSrcFileSystem(srcpath, verifyChecksum);
  173.       if (copyCrc && !(srcFS instanceof ChecksumFileSystem)) {
  174.         System.err.println("-crc option is not valid when source file system " +
  175.             "does not have crc files. Automatically turn the option off.");
  176.         copyCrc = false;
  177.       }
  178.       FileStatus[] srcs = srcFS.globStatus(srcpath);
  179.       boolean dstIsDir = dst.isDirectory(); 
  180.       if (srcs.length > 1 && !dstIsDir) {
  181.         throw new IOException("When copying multiple files, "
  182.                               + "destination should be a directory.");
  183.       }
  184.       for (FileStatus status : srcs) {
  185.         Path p = status.getPath();
  186.         File f = dstIsDir? new File(dst, p.getName()): dst;
  187.         copyToLocal(srcFS, p, f, copyCrc);
  188.       }
  189.     }
  190.   }
  191.   /**
  192.    * Return the {@link FileSystem} specified by src and the conf.
  193.    * It the {@link FileSystem} supports checksum, set verifyChecksum.
  194.    */
  195.   private FileSystem getSrcFileSystem(Path src, boolean verifyChecksum
  196.       ) throws IOException { 
  197.     FileSystem srcFs = src.getFileSystem(getConf());
  198.     srcFs.setVerifyChecksum(verifyChecksum);
  199.     return srcFs;
  200.   }
  201.   /**
  202.    * The prefix for the tmp file used in copyToLocal.
  203.    * It must be at least three characters long, required by
  204.    * {@link java.io.File#createTempFile(String, String, File)}.
  205.    */
  206.   static final String COPYTOLOCAL_PREFIX = "_copyToLocal_";
  207.   /**
  208.    * Copy a source file from a given file system to local destination.
  209.    * @param srcFS source file system
  210.    * @param src source path
  211.    * @param dst destination
  212.    * @param copyCrc copy CRC files?
  213.    * @exception IOException If some IO failed
  214.    */
  215.   private void copyToLocal(final FileSystem srcFS, final Path src,
  216.                            final File dst, final boolean copyCrc)
  217.     throws IOException {
  218.     /* Keep the structure similar to ChecksumFileSystem.copyToLocal(). 
  219.      * Ideal these two should just invoke FileUtil.copy() and not repeat
  220.      * recursion here. Of course, copy() should support two more options :
  221.      * copyCrc and useTmpFile (may be useTmpFile need not be an option).
  222.      */
  223.     
  224.     if (!srcFS.getFileStatus(src).isDir()) {
  225.       if (dst.exists()) {
  226.         // match the error message in FileUtil.checkDest():
  227.         throw new IOException("Target " + dst + " already exists");
  228.       }
  229.       
  230.       // use absolute name so that tmp file is always created under dest dir
  231.       File tmp = FileUtil.createLocalTempFile(dst.getAbsoluteFile(),
  232.                                               COPYTOLOCAL_PREFIX, true);
  233.       if (!FileUtil.copy(srcFS, src, tmp, false, srcFS.getConf())) {
  234.         throw new IOException("Failed to copy " + src + " to " + dst); 
  235.       }
  236.       
  237.       if (!tmp.renameTo(dst)) {
  238.         throw new IOException("Failed to rename tmp file " + tmp + 
  239.                               " to local destination "" + dst + "".");
  240.       }
  241.       if (copyCrc) {
  242.         if (!(srcFS instanceof ChecksumFileSystem)) {
  243.           throw new IOException("Source file system does not have crc files");
  244.         }
  245.         
  246.         ChecksumFileSystem csfs = (ChecksumFileSystem) srcFS;
  247.         File dstcs = FileSystem.getLocal(srcFS.getConf())
  248.           .pathToFile(csfs.getChecksumFile(new Path(dst.getCanonicalPath())));
  249.         copyToLocal(csfs.getRawFileSystem(), csfs.getChecksumFile(src),
  250.                     dstcs, false);
  251.       } 
  252.     } else {
  253.       // once FileUtil.copy() supports tmp file, we don't need to mkdirs().
  254.       dst.mkdirs();
  255.       for(FileStatus path : srcFS.listStatus(src)) {
  256.         copyToLocal(srcFS, path.getPath(), 
  257.                     new File(dst, path.getPath().getName()), copyCrc);
  258.       }
  259.     }
  260.   }
  261.   /**
  262.    * Get all the files in the directories that match the source file 
  263.    * pattern and merge and sort them to only one file on local fs 
  264.    * srcf is kept.
  265.    * @param srcf: a file pattern specifying source files
  266.    * @param dstf: a destination local file/directory 
  267.    * @exception: IOException  
  268.    * @see org.apache.hadoop.fs.FileSystem.globStatus 
  269.    */
  270.   void copyMergeToLocal(String srcf, Path dst) throws IOException {
  271.     copyMergeToLocal(srcf, dst, false);
  272.   }    
  273.     
  274.   /**
  275.    * Get all the files in the directories that match the source file pattern
  276.    * and merge and sort them to only one file on local fs 
  277.    * srcf is kept.
  278.    * 
  279.    * Also adds a string between the files (useful for adding n
  280.    * to a text file)
  281.    * @param srcf: a file pattern specifying source files
  282.    * @param dstf: a destination local file/directory
  283.    * @param endline: if an end of line character is added to a text file 
  284.    * @exception: IOException  
  285.    * @see org.apache.hadoop.fs.FileSystem.globStatus 
  286.    */
  287.   void copyMergeToLocal(String srcf, Path dst, boolean endline) throws IOException {
  288.     Path srcPath = new Path(srcf);
  289.     FileSystem srcFs = srcPath.getFileSystem(getConf());
  290.     Path [] srcs = FileUtil.stat2Paths(srcFs.globStatus(srcPath), 
  291.                                        srcPath);
  292.     for(int i=0; i<srcs.length; i++) {
  293.       if (endline) {
  294.         FileUtil.copyMerge(srcFs, srcs[i], 
  295.                            FileSystem.getLocal(getConf()), dst, false, getConf(), "n");
  296.       } else {
  297.         FileUtil.copyMerge(srcFs, srcs[i], 
  298.                            FileSystem.getLocal(getConf()), dst, false, getConf(), null);
  299.       }
  300.     }
  301.   }      
  302.   /**
  303.    * Obtain the indicated file and copy to the local name.
  304.    * srcf is removed.
  305.    */
  306.   void moveToLocal(String srcf, Path dst) throws IOException {
  307.     System.err.println("Option '-moveToLocal' is not implemented yet.");
  308.   }
  309.   /**
  310.    * Fetch all files that match the file pattern <i>srcf</i> and display
  311.    * their content on stdout. 
  312.    * @param srcf: a file pattern specifying source files
  313.    * @exception: IOException
  314.    * @see org.apache.hadoop.fs.FileSystem.globStatus 
  315.    */
  316.   void cat(String src, boolean verifyChecksum) throws IOException {
  317.     //cat behavior in Linux
  318.     //  [~/1207]$ ls ?.txt
  319.     //  x.txt  z.txt
  320.     //  [~/1207]$ cat x.txt y.txt z.txt
  321.     //  xxx
  322.     //  cat: y.txt: No such file or directory
  323.     //  zzz
  324.     Path srcPattern = new Path(src);
  325.     new DelayedExceptionThrowing() {
  326.       @Override
  327.       void process(Path p, FileSystem srcFs) throws IOException {
  328.         if (srcFs.getFileStatus(p).isDir()) {
  329.           throw new IOException("Source must be a file.");
  330.         }
  331.         printToStdout(srcFs.open(p));
  332.       }
  333.     }.globAndProcess(srcPattern, getSrcFileSystem(srcPattern, verifyChecksum));
  334.   }
  335.   private class TextRecordInputStream extends InputStream {
  336.     SequenceFile.Reader r;
  337.     WritableComparable key;
  338.     Writable val;
  339.     DataInputBuffer inbuf;
  340.     DataOutputBuffer outbuf;
  341.     public TextRecordInputStream(FileStatus f) throws IOException {
  342.       r = new SequenceFile.Reader(fs, f.getPath(), getConf());
  343.       key = ReflectionUtils.newInstance(r.getKeyClass().asSubclass(WritableComparable.class),
  344.                                         getConf());
  345.       val = ReflectionUtils.newInstance(r.getValueClass().asSubclass(Writable.class),
  346.                                         getConf());
  347.       inbuf = new DataInputBuffer();
  348.       outbuf = new DataOutputBuffer();
  349.     }
  350.     public int read() throws IOException {
  351.       int ret;
  352.       if (null == inbuf || -1 == (ret = inbuf.read())) {
  353.         if (!r.next(key, val)) {
  354.           return -1;
  355.         }
  356.         byte[] tmp = key.toString().getBytes();
  357.         outbuf.write(tmp, 0, tmp.length);
  358.         outbuf.write('t');
  359.         tmp = val.toString().getBytes();
  360.         outbuf.write(tmp, 0, tmp.length);
  361.         outbuf.write('n');
  362.         inbuf.reset(outbuf.getData(), outbuf.getLength());
  363.         outbuf.reset();
  364.         ret = inbuf.read();
  365.       }
  366.       return ret;
  367.     }
  368.   }
  369.   private InputStream forMagic(Path p, FileSystem srcFs) throws IOException {
  370.     FSDataInputStream i = srcFs.open(p);
  371.     switch(i.readShort()) {
  372.       case 0x1f8b: // RFC 1952
  373.         i.seek(0);
  374.         return new GZIPInputStream(i);
  375.       case 0x5345: // 'S' 'E'
  376.         if (i.readByte() == 'Q') {
  377.           i.close();
  378.           return new TextRecordInputStream(srcFs.getFileStatus(p));
  379.         }
  380.         break;
  381.     }
  382.     i.seek(0);
  383.     return i;
  384.   }
  385.   void text(String srcf) throws IOException {
  386.     Path srcPattern = new Path(srcf);
  387.     new DelayedExceptionThrowing() {
  388.       @Override
  389.       void process(Path p, FileSystem srcFs) throws IOException {
  390.         if (srcFs.isDirectory(p)) {
  391.           throw new IOException("Source must be a file.");
  392.         }
  393.         printToStdout(forMagic(p, srcFs));
  394.       }
  395.     }.globAndProcess(srcPattern, srcPattern.getFileSystem(getConf()));
  396.   }
  397.   /**
  398.    * Parse the incoming command string
  399.    * @param cmd
  400.    * @param pos ignore anything before this pos in cmd
  401.    * @throws IOException 
  402.    */
  403.   private void setReplication(String[] cmd, int pos) throws IOException {
  404.     CommandFormat c = new CommandFormat("setrep", 2, 2, "R", "w");
  405.     String dst = null;
  406.     short rep = 0;
  407.     try {
  408.       List<String> parameters = c.parse(cmd, pos);
  409.       rep = Short.parseShort(parameters.get(0));
  410.       dst = parameters.get(1);
  411.     } catch (NumberFormatException nfe) {
  412.       System.err.println("Illegal replication, a positive integer expected");
  413.       throw nfe;
  414.     }
  415.     catch(IllegalArgumentException iae) {
  416.       System.err.println("Usage: java FsShell " + SETREP_SHORT_USAGE);
  417.       throw iae;
  418.     }
  419.     if (rep < 1) {
  420.       System.err.println("Cannot set replication to: " + rep);
  421.       throw new IllegalArgumentException("replication must be >= 1");
  422.     }
  423.     List<Path> waitList = c.getOpt("w")? new ArrayList<Path>(): null;
  424.     setReplication(rep, dst, c.getOpt("R"), waitList);
  425.     if (waitList != null) {
  426.       waitForReplication(waitList, rep);
  427.     }
  428.   }
  429.     
  430.   /**
  431.    * Wait for all files in waitList to have replication number equal to rep.
  432.    * @param waitList The files are waited for.
  433.    * @param rep The new replication number.
  434.    * @throws IOException IOException
  435.    */
  436.   void waitForReplication(List<Path> waitList, int rep) throws IOException {
  437.     for(Path f : waitList) {
  438.       System.out.print("Waiting for " + f + " ...");
  439.       System.out.flush();
  440.       boolean printWarning = false;
  441.       FileStatus status = fs.getFileStatus(f);
  442.       long len = status.getLen();
  443.       for(boolean done = false; !done; ) {
  444.         BlockLocation[] locations = fs.getFileBlockLocations(status, 0, len);
  445.         int i = 0;
  446.         for(; i < locations.length && 
  447.           locations[i].getHosts().length == rep; i++)
  448.           if (!printWarning && locations[i].getHosts().length > rep) {
  449.             System.out.println("nWARNING: the waiting time may be long for "
  450.                 + "DECREASING the number of replication.");
  451.             printWarning = true;
  452.           }
  453.         done = i == locations.length;
  454.         if (!done) {
  455.           System.out.print(".");
  456.           System.out.flush();
  457.           try {Thread.sleep(10000);} catch (InterruptedException e) {}
  458.         }
  459.       }
  460.       System.out.println(" done");
  461.     }
  462.   }
  463.   /**
  464.    * Set the replication for files that match file pattern <i>srcf</i>
  465.    * if it's a directory and recursive is true,
  466.    * set replication for all the subdirs and those files too.
  467.    * @param newRep new replication factor
  468.    * @param srcf a file pattern specifying source files
  469.    * @param recursive if need to set replication factor for files in subdirs
  470.    * @throws IOException  
  471.    * @see org.apache.hadoop.fs.FileSystem#globStatus(Path)
  472.    */
  473.   void setReplication(short newRep, String srcf, boolean recursive,
  474.                       List<Path> waitingList)
  475.     throws IOException {
  476.     Path srcPath = new Path(srcf);
  477.     FileSystem srcFs = srcPath.getFileSystem(getConf());
  478.     Path[] srcs = FileUtil.stat2Paths(srcFs.globStatus(srcPath),
  479.                                       srcPath);
  480.     for(int i=0; i<srcs.length; i++) {
  481.       setReplication(newRep, srcFs, srcs[i], recursive, waitingList);
  482.     }
  483.   }
  484.   private void setReplication(short newRep, FileSystem srcFs, 
  485.                               Path src, boolean recursive,
  486.                               List<Path> waitingList)
  487.     throws IOException {
  488.     if (!srcFs.getFileStatus(src).isDir()) {
  489.       setFileReplication(src, srcFs, newRep, waitingList);
  490.       return;
  491.     }
  492.     FileStatus items[] = srcFs.listStatus(src);
  493.     if (items == null) {
  494.       throw new IOException("Could not get listing for " + src);
  495.     } else {
  496.       for (int i = 0; i < items.length; i++) {
  497.         if (!items[i].isDir()) {
  498.           setFileReplication(items[i].getPath(), srcFs, newRep, waitingList);
  499.         } else if (recursive) {
  500.           setReplication(newRep, srcFs, items[i].getPath(), recursive, 
  501.                          waitingList);
  502.         }
  503.       }
  504.     }
  505.   }
  506.     
  507.   /**
  508.    * Actually set the replication for this file
  509.    * If it fails either throw IOException or print an error msg
  510.    * @param file: a file/directory
  511.    * @param newRep: new replication factor
  512.    * @throws IOException
  513.    */
  514.   private void setFileReplication(Path file, FileSystem srcFs, short newRep, List<Path> waitList)
  515.     throws IOException {
  516.     if (srcFs.setReplication(file, newRep)) {
  517.       if (waitList != null) {
  518.         waitList.add(file);
  519.       }
  520.       System.out.println("Replication " + newRep + " set: " + file);
  521.     } else {
  522.       System.err.println("Could not set replication for: " + file);
  523.     }
  524.   }
  525.     
  526.     
  527.   /**
  528.    * Get a listing of all files in that match the file pattern <i>srcf</i>.
  529.    * @param srcf a file pattern specifying source files
  530.    * @param recursive if need to list files in subdirs
  531.    * @throws IOException  
  532.    * @see org.apache.hadoop.fs.FileSystem#globStatus(Path)
  533.    */
  534.   private int ls(String srcf, boolean recursive) throws IOException {
  535.     Path srcPath = new Path(srcf);
  536.     FileSystem srcFs = srcPath.getFileSystem(this.getConf());
  537.     FileStatus[] srcs = srcFs.globStatus(srcPath);
  538.     if (srcs==null || srcs.length==0) {
  539.       throw new FileNotFoundException("Cannot access " + srcf + 
  540.           ": No such file or directory.");
  541.     }
  542.  
  543.     boolean printHeader = (srcs.length == 1) ? true: false;
  544.     int numOfErrors = 0;
  545.     for(int i=0; i<srcs.length; i++) {
  546.       numOfErrors += ls(srcs[i], srcFs, recursive, printHeader);
  547.     }
  548.     return numOfErrors == 0 ? 0 : -1;
  549.   }
  550.   /* list all files under the directory <i>src</i>
  551.    * ideally we should provide "-l" option, that lists like "ls -l".
  552.    */
  553.   private int ls(FileStatus src, FileSystem srcFs, boolean recursive,
  554.       boolean printHeader) throws IOException {
  555.     final String cmd = recursive? "lsr": "ls";
  556.     final FileStatus[] items = shellListStatus(cmd, srcFs, src);
  557.     if (items == null) {
  558.       return 1;
  559.     } else {
  560.       int numOfErrors = 0;
  561.       if (!recursive && printHeader) {
  562.         if (items.length != 0) {
  563.           System.out.println("Found " + items.length + " items");
  564.         }
  565.       }
  566.       
  567.       int maxReplication = 3, maxLen = 10, maxOwner = 0,maxGroup = 0;
  568.       for(int i = 0; i < items.length; i++) {
  569.         FileStatus stat = items[i];
  570.         int replication = String.valueOf(stat.getReplication()).length();
  571.         int len = String.valueOf(stat.getLen()).length();
  572.         int owner = String.valueOf(stat.getOwner()).length();
  573.         int group = String.valueOf(stat.getGroup()).length();
  574.         
  575.         if (replication > maxReplication) maxReplication = replication;
  576.         if (len > maxLen) maxLen = len;
  577.         if (owner > maxOwner)  maxOwner = owner;
  578.         if (group > maxGroup)  maxGroup = group;
  579.       }
  580.       
  581.       for (int i = 0; i < items.length; i++) {
  582.         FileStatus stat = items[i];
  583.         Path cur = stat.getPath();
  584.         String mdate = dateForm.format(new Date(stat.getModificationTime()));
  585.         
  586.         System.out.print((stat.isDir() ? "d" : "-") + 
  587.           stat.getPermission() + " ");
  588.         System.out.printf("%"+ maxReplication + 
  589.           "s ", (!stat.isDir() ? stat.getReplication() : "-"));
  590.         if (maxOwner > 0)
  591.           System.out.printf("%-"+ maxOwner + "s ", stat.getOwner());
  592.         if (maxGroup > 0)
  593.           System.out.printf("%-"+ maxGroup + "s ", stat.getGroup());
  594.         System.out.printf("%"+ maxLen + "d ", stat.getLen());
  595.         System.out.print(mdate + " ");
  596.         System.out.println(cur.toUri().getPath());
  597.         if (recursive && stat.isDir()) {
  598.           numOfErrors += ls(stat,srcFs, recursive, printHeader);
  599.         }
  600.       }
  601.       return numOfErrors;
  602.     }
  603.   }
  604.   /**
  605.    * Show the size of all files that match the file pattern <i>src</i>
  606.    * @param src a file pattern specifying source files
  607.    * @throws IOException  
  608.    * @see org.apache.hadoop.fs.FileSystem#globStatus(Path)
  609.    */
  610.   void du(String src) throws IOException {
  611.     Path srcPath = new Path(src);
  612.     FileSystem srcFs = srcPath.getFileSystem(getConf());
  613.     Path[] pathItems = FileUtil.stat2Paths(srcFs.globStatus(srcPath), 
  614.                                            srcPath);
  615.     FileStatus items[] = srcFs.listStatus(pathItems);
  616.     if ((items == null) || ((items.length == 0) && 
  617.         (!srcFs.exists(srcPath)))){
  618.       throw new FileNotFoundException("Cannot access " + src
  619.             + ": No such file or directory.");
  620.     } else {
  621.       System.out.println("Found " + items.length + " items");
  622.       int maxLength = 10;
  623.       
  624.       long length[] = new long[items.length];
  625.       for (int i = 0; i < items.length; i++) {
  626.         length[i] = items[i].isDir() ?
  627.           srcFs.getContentSummary(items[i].getPath()).getLength() :
  628.           items[i].getLen();
  629.         int len = String.valueOf(length[i]).length();
  630.         if (len > maxLength) maxLength = len;
  631.       }
  632.       for(int i = 0; i < items.length; i++) {
  633.         System.out.printf("%-"+ (maxLength + BORDER) +"d", length[i]);
  634.         System.out.println(items[i].getPath());
  635.       }
  636.     }
  637.   }
  638.     
  639.   /**
  640.    * Show the summary disk usage of each dir/file 
  641.    * that matches the file pattern <i>src</i>
  642.    * @param src a file pattern specifying source files
  643.    * @throws IOException  
  644.    * @see org.apache.hadoop.fs.FileSystem#globStatus(Path)
  645.    */
  646.   void dus(String src) throws IOException {
  647.     Path srcPath = new Path(src);
  648.     FileSystem srcFs = srcPath.getFileSystem(getConf());
  649.     FileStatus status[] = srcFs.globStatus(new Path(src));
  650.     if (status==null || status.length==0) {
  651.       throw new FileNotFoundException("Cannot access " + src + 
  652.           ": No such file or directory.");
  653.     }
  654.     for(int i=0; i<status.length; i++) {
  655.       long totalSize = srcFs.getContentSummary(status[i].getPath()).getLength();
  656.       String pathStr = status[i].getPath().toString();
  657.       System.out.println(("".equals(pathStr)?".":pathStr) + "t" + totalSize);
  658.     }
  659.   }
  660.   /**
  661.    * Create the given dir
  662.    */
  663.   void mkdir(String src) throws IOException {
  664.     Path f = new Path(src);
  665.     FileSystem srcFs = f.getFileSystem(getConf());
  666.     FileStatus fstatus = null;
  667.     try {
  668.       fstatus = srcFs.getFileStatus(f);
  669.       if (fstatus.isDir()) {
  670.         throw new IOException("cannot create directory " 
  671.             + src + ": File exists");
  672.       }
  673.       else {
  674.         throw new IOException(src + " exists but " +
  675.             "is not a directory");
  676.       }
  677.     } catch(FileNotFoundException e) {
  678.         if (!srcFs.mkdirs(f)) {
  679.           throw new IOException("failed to create " + src);
  680.         }
  681.     }
  682.   }
  683.   /**
  684.    * (Re)create zero-length file at the specified path.
  685.    * This will be replaced by a more UNIX-like touch when files may be
  686.    * modified.
  687.    */
  688.   void touchz(String src) throws IOException {
  689.     Path f = new Path(src);
  690.     FileSystem srcFs = f.getFileSystem(getConf());
  691.     FileStatus st;
  692.     if (srcFs.exists(f)) {
  693.       st = srcFs.getFileStatus(f);
  694.       if (st.isDir()) {
  695.         // TODO: handle this
  696.         throw new IOException(src + " is a directory");
  697.       } else if (st.getLen() != 0)
  698.         throw new IOException(src + " must be a zero-length file");
  699.     }
  700.     FSDataOutputStream out = srcFs.create(f);
  701.     out.close();
  702.   }
  703.   /**
  704.    * Check file types.
  705.    */
  706.   int test(String argv[], int i) throws IOException {
  707.     if (!argv[i].startsWith("-") || argv[i].length() > 2)
  708.       throw new IOException("Not a flag: " + argv[i]);
  709.     char flag = argv[i].toCharArray()[1];
  710.     Path f = new Path(argv[++i]);
  711.     FileSystem srcFs = f.getFileSystem(getConf());
  712.     switch(flag) {
  713.       case 'e':
  714.         return srcFs.exists(f) ? 0 : 1;
  715.       case 'z':
  716.         return srcFs.getFileStatus(f).getLen() == 0 ? 0 : 1;
  717.       case 'd':
  718.         return srcFs.getFileStatus(f).isDir() ? 0 : 1;
  719.       default:
  720.         throw new IOException("Unknown flag: " + flag);
  721.     }
  722.   }
  723.   /**
  724.    * Print statistics about path in specified format.
  725.    * Format sequences:
  726.    *   %b: Size of file in blocks
  727.    *   %n: Filename
  728.    *   %o: Block size
  729.    *   %r: replication
  730.    *   %y: UTC date as &quot;yyyy-MM-dd HH:mm:ss&quot;
  731.    *   %Y: Milliseconds since January 1, 1970 UTC
  732.    */
  733.   void stat(char[] fmt, String src) throws IOException {
  734.     Path srcPath = new Path(src);
  735.     FileSystem srcFs = srcPath.getFileSystem(getConf());
  736.     FileStatus glob[] = srcFs.globStatus(srcPath);
  737.     if (null == glob)
  738.       throw new IOException("cannot stat `" + src + "': No such file or directory");
  739.     for (FileStatus f : glob) {
  740.       StringBuilder buf = new StringBuilder();
  741.       for (int i = 0; i < fmt.length; ++i) {
  742.         if (fmt[i] != '%') {
  743.           buf.append(fmt[i]);
  744.         } else {
  745.           if (i + 1 == fmt.length) break;
  746.           switch(fmt[++i]) {
  747.             case 'b':
  748.               buf.append(f.getLen());
  749.               break;
  750.             case 'F':
  751.               buf.append(f.isDir() ? "directory" : "regular file");
  752.               break;
  753.             case 'n':
  754.               buf.append(f.getPath().getName());
  755.               break;
  756.             case 'o':
  757.               buf.append(f.getBlockSize());
  758.               break;
  759.             case 'r':
  760.               buf.append(f.getReplication());
  761.               break;
  762.             case 'y':
  763.               buf.append(modifFmt.format(new Date(f.getModificationTime())));
  764.               break;
  765.             case 'Y':
  766.               buf.append(f.getModificationTime());
  767.               break;
  768.             default:
  769.               buf.append(fmt[i]);
  770.               break;
  771.           }
  772.         }
  773.       }
  774.       System.out.println(buf.toString());
  775.     }
  776.   }
  777.   /**
  778.    * Move files that match the file pattern <i>srcf</i>
  779.    * to a destination file.
  780.    * When moving mutiple files, the destination must be a directory. 
  781.    * Otherwise, IOException is thrown.
  782.    * @param srcf a file pattern specifying source files
  783.    * @param dstf a destination local file/directory 
  784.    * @throws IOException  
  785.    * @see org.apache.hadoop.fs.FileSystem#globStatus(Path)
  786.    */
  787.   void rename(String srcf, String dstf) throws IOException {
  788.     Path srcPath = new Path(srcf);
  789.     Path dstPath = new Path(dstf);
  790.     FileSystem srcFs = srcPath.getFileSystem(getConf());
  791.     FileSystem dstFs = dstPath.getFileSystem(getConf());
  792.     URI srcURI = srcFs.getUri();
  793.     URI dstURI = dstFs.getUri();
  794.     if (srcURI.compareTo(dstURI) != 0) {
  795.       throw new IOException("src and destination filesystems do not match.");
  796.     }
  797.     Path[] srcs = FileUtil.stat2Paths(srcFs.globStatus(srcPath), srcPath);
  798.     Path dst = new Path(dstf);
  799.     if (srcs.length > 1 && !srcFs.isDirectory(dst)) {
  800.       throw new IOException("When moving multiple files, " 
  801.                             + "destination should be a directory.");
  802.     }
  803.     for(int i=0; i<srcs.length; i++) {
  804.       if (!srcFs.rename(srcs[i], dst)) {
  805.         FileStatus srcFstatus = null;
  806.         FileStatus dstFstatus = null;
  807.         try {
  808.           srcFstatus = srcFs.getFileStatus(srcs[i]);
  809.         } catch(FileNotFoundException e) {
  810.           throw new FileNotFoundException(srcs[i] + 
  811.           ": No such file or directory");
  812.         }
  813.         try {
  814.           dstFstatus = dstFs.getFileStatus(dst);
  815.         } catch(IOException e) {
  816.         }
  817.         if((srcFstatus!= null) && (dstFstatus!= null)) {
  818.           if (srcFstatus.isDir()  && !dstFstatus.isDir()) {
  819.             throw new IOException("cannot overwrite non directory "
  820.                 + dst + " with directory " + srcs[i]);
  821.           }
  822.         }
  823.         throw new IOException("Failed to rename " + srcs[i] + " to " + dst);
  824.       }
  825.     }
  826.   }
  827.   /**
  828.    * Move/rename file(s) to a destination file. Multiple source
  829.    * files can be specified. The destination is the last element of
  830.    * the argvp[] array.
  831.    * If multiple source files are specified, then the destination 
  832.    * must be a directory. Otherwise, IOException is thrown.
  833.    * @exception: IOException  
  834.    */
  835.   private int rename(String argv[], Configuration conf) throws IOException {
  836.     int i = 0;
  837.     int exitCode = 0;
  838.     String cmd = argv[i++];  
  839.     String dest = argv[argv.length-1];
  840.     //
  841.     // If the user has specified multiple source files, then
  842.     // the destination has to be a directory
  843.     //
  844.     if (argv.length > 3) {
  845.       Path dst = new Path(dest);
  846.       FileSystem dstFs = dst.getFileSystem(getConf());
  847.       if (!dstFs.isDirectory(dst)) {
  848.         throw new IOException("When moving multiple files, " 
  849.                               + "destination " + dest + " should be a directory.");
  850.       }
  851.     }
  852.     //
  853.     // for each source file, issue the rename
  854.     //
  855.     for (; i < argv.length - 1; i++) {
  856.       try {
  857.         //
  858.         // issue the rename to the fs
  859.         //
  860.         rename(argv[i], dest);
  861.       } catch (RemoteException e) {
  862.         //
  863.         // This is a error returned by hadoop server. Print
  864.         // out the first line of the error mesage.
  865.         //
  866.         exitCode = -1;
  867.         try {
  868.           String[] content;
  869.           content = e.getLocalizedMessage().split("n");
  870.           System.err.println(cmd.substring(1) + ": " + content[0]);
  871.         } catch (Exception ex) {
  872.           System.err.println(cmd.substring(1) + ": " +
  873.                              ex.getLocalizedMessage());
  874.         }
  875.       } catch (IOException e) {
  876.         //
  877.         // IO exception encountered locally.
  878.         //
  879.         exitCode = -1;
  880.         System.err.println(cmd.substring(1) + ": " +
  881.                            e.getLocalizedMessage());
  882.       }
  883.     }
  884.     return exitCode;
  885.   }
  886.   /**
  887.    * Copy files that match the file pattern <i>srcf</i>
  888.    * to a destination file.
  889.    * When copying mutiple files, the destination must be a directory. 
  890.    * Otherwise, IOException is thrown.
  891.    * @param srcf a file pattern specifying source files
  892.    * @param dstf a destination local file/directory 
  893.    * @throws IOException  
  894.    * @see org.apache.hadoop.fs.FileSystem#globStatus(Path)
  895.    */
  896.   void copy(String srcf, String dstf, Configuration conf) throws IOException {
  897.     Path srcPath = new Path(srcf);
  898.     FileSystem srcFs = srcPath.getFileSystem(getConf());
  899.     Path dstPath = new Path(dstf);
  900.     FileSystem dstFs = dstPath.getFileSystem(getConf());
  901.     Path [] srcs = FileUtil.stat2Paths(srcFs.globStatus(srcPath), srcPath);
  902.     if (srcs.length > 1 && !dstFs.isDirectory(dstPath)) {
  903.       throw new IOException("When copying multiple files, " 
  904.                             + "destination should be a directory.");
  905.     }
  906.     for(int i=0; i<srcs.length; i++) {
  907.       FileUtil.copy(srcFs, srcs[i], dstFs, dstPath, false, conf);
  908.     }
  909.   }
  910.   /**
  911.    * Copy file(s) to a destination file. Multiple source
  912.    * files can be specified. The destination is the last element of
  913.    * the argvp[] array.
  914.    * If multiple source files are specified, then the destination 
  915.    * must be a directory. Otherwise, IOException is thrown.
  916.    * @exception: IOException  
  917.    */
  918.   private int copy(String argv[], Configuration conf) throws IOException {
  919.     int i = 0;
  920.     int exitCode = 0;
  921.     String cmd = argv[i++];  
  922.     String dest = argv[argv.length-1];
  923.     //
  924.     // If the user has specified multiple source files, then
  925.     // the destination has to be a directory
  926.     //
  927.     if (argv.length > 3) {
  928.       Path dst = new Path(dest);
  929.       if (!fs.isDirectory(dst)) {
  930.         throw new IOException("When copying multiple files, " 
  931.                               + "destination " + dest + " should be a directory.");
  932.       }
  933.     }
  934.     //
  935.     // for each source file, issue the copy
  936.     //
  937.     for (; i < argv.length - 1; i++) {
  938.       try {
  939.         //
  940.         // issue the copy to the fs
  941.         //
  942.         copy(argv[i], dest, conf);
  943.       } catch (RemoteException e) {
  944.         //
  945.         // This is a error returned by hadoop server. Print
  946.         // out the first line of the error mesage.
  947.         //
  948.         exitCode = -1;
  949.         try {
  950.           String[] content;
  951.           content = e.getLocalizedMessage().split("n");
  952.           System.err.println(cmd.substring(1) + ": " +
  953.                              content[0]);
  954.         } catch (Exception ex) {
  955.           System.err.println(cmd.substring(1) + ": " +
  956.                              ex.getLocalizedMessage());
  957.         }
  958.       } catch (IOException e) {
  959.         //
  960.         // IO exception encountered locally.
  961.         //
  962.         exitCode = -1;
  963.         System.err.println(cmd.substring(1) + ": " +
  964.                            e.getLocalizedMessage());
  965.       }
  966.     }
  967.     return exitCode;
  968.   }
  969.   /**
  970.    * Delete all files that match the file pattern <i>srcf</i>.
  971.    * @param srcf a file pattern specifying source files
  972.    * @param recursive if need to delete subdirs
  973.    * @throws IOException  
  974.    * @see org.apache.hadoop.fs.FileSystem#globStatus(Path)
  975.    */
  976.   void delete(String srcf, final boolean recursive) throws IOException {
  977.     //rm behavior in Linux
  978.     //  [~/1207]$ ls ?.txt
  979.     //  x.txt  z.txt
  980.     //  [~/1207]$ rm x.txt y.txt z.txt 
  981.     //  rm: cannot remove `y.txt': No such file or directory
  982.     Path srcPattern = new Path(srcf);
  983.     new DelayedExceptionThrowing() {
  984.       @Override
  985.       void process(Path p, FileSystem srcFs) throws IOException {
  986.         delete(p, srcFs, recursive);
  987.       }
  988.     }.globAndProcess(srcPattern, srcPattern.getFileSystem(getConf()));
  989.   }
  990.     
  991.   /* delete a file */
  992.   private void delete(Path src, FileSystem srcFs, boolean recursive) throws IOException {
  993.     if (srcFs.isDirectory(src) && !recursive) {
  994.       throw new IOException("Cannot remove directory "" + src +
  995.                             "", use -rmr instead");
  996.     }
  997.     Trash trashTmp = new Trash(srcFs, getConf());
  998.     if (trashTmp.moveToTrash(src)) {
  999.       System.out.println("Moved to trash: " + src);
  1000.       return;
  1001.     }
  1002.     if (srcFs.delete(src, true)) {
  1003.       System.out.println("Deleted " + src);
  1004.     } else {
  1005.       if (!srcFs.exists(src)) {
  1006.         throw new FileNotFoundException("cannot remove "
  1007.             + src + ": No such file or directory.");
  1008.         }
  1009.       throw new IOException("Delete failed " + src);
  1010.     }
  1011.   }
  1012.   private void expunge() throws IOException {
  1013.     trash.expunge();
  1014.     trash.checkpoint();
  1015.   }
  1016.   /**
  1017.    * Returns the Trash object associated with this shell.
  1018.    */
  1019.   public Path getCurrentTrashDir() {
  1020.     return trash.getCurrentTrashDir();
  1021.   }
  1022.   /**
  1023.    * Parse the incoming command string
  1024.    * @param cmd
  1025.    * @param pos ignore anything before this pos in cmd
  1026.    * @throws IOException 
  1027.    */
  1028.   private void tail(String[] cmd, int pos) throws IOException {
  1029.     CommandFormat c = new CommandFormat("tail", 1, 1, "f");
  1030.     String src = null;
  1031.     Path path = null;
  1032.     try {
  1033.       List<String> parameters = c.parse(cmd, pos);
  1034.       src = parameters.get(0);
  1035.     } catch(IllegalArgumentException iae) {
  1036.       System.err.println("Usage: java FsShell " + TAIL_USAGE);
  1037.       throw iae;
  1038.     }
  1039.     boolean foption = c.getOpt("f") ? true: false;
  1040.     path = new Path(src);
  1041.     FileSystem srcFs = path.getFileSystem(getConf());
  1042.     if (srcFs.isDirectory(path)) {
  1043.       throw new IOException("Source must be a file.");
  1044.     }
  1045.     long fileSize = srcFs.getFileStatus(path).getLen();
  1046.     long offset = (fileSize > 1024) ? fileSize - 1024: 0;
  1047.     while (true) {
  1048.       FSDataInputStream in = srcFs.open(path);
  1049.       in.seek(offset);
  1050.       IOUtils.copyBytes(in, System.out, 1024, false);
  1051.       offset = in.getPos();
  1052.       in.close();
  1053.       if (!foption) {
  1054.         break;
  1055.       }
  1056.       fileSize = srcFs.getFileStatus(path).getLen();
  1057.       offset = (fileSize > offset) ? offset: fileSize;
  1058.       try {
  1059.         Thread.sleep(5000);
  1060.       } catch (InterruptedException e) {
  1061.         break;
  1062.       }
  1063.     }
  1064.   }
  1065.   /**
  1066.    * This class runs a command on a given FileStatus. This can be used for
  1067.    * running various commands like chmod, chown etc.
  1068.    */
  1069.   static abstract class CmdHandler {
  1070.     
  1071.     protected int errorCode = 0;
  1072.     protected boolean okToContinue = true;
  1073.     protected String cmdName;
  1074.     
  1075.     int getErrorCode() { return errorCode; }
  1076.     boolean okToContinue() { return okToContinue; }
  1077.     String getName() { return cmdName; }
  1078.     
  1079.     protected CmdHandler(String cmdName, FileSystem fs) {
  1080.       this.cmdName = cmdName;
  1081.     }
  1082.     
  1083.     public abstract void run(FileStatus file, FileSystem fs) throws IOException;
  1084.   }
  1085.   
  1086.   /** helper returns listStatus() */
  1087.   private static FileStatus[] shellListStatus(String cmd, 
  1088.                                                    FileSystem srcFs,
  1089.                                                    FileStatus src) {
  1090.     if (!src.isDir()) {
  1091.       FileStatus[] files = { src };
  1092.       return files;
  1093.     }
  1094.     Path path = src.getPath();
  1095.     try {
  1096.       FileStatus[] files = srcFs.listStatus(path);
  1097.       if ( files == null ) {
  1098.         System.err.println(cmd + 
  1099.                            ": could not get listing for '" + path + "'");
  1100.       }
  1101.       return files;
  1102.     } catch (IOException e) {
  1103.       System.err.println(cmd + 
  1104.                          ": could not get get listing for '" + path + "' : " +
  1105.                          e.getMessage().split("n")[0]);
  1106.     }
  1107.     return null;
  1108.   }
  1109.   
  1110.   
  1111.   /**
  1112.    * Runs the command on a given file with the command handler. 
  1113.    * If recursive is set, command is run recursively.
  1114.    */                                       
  1115.   private static int runCmdHandler(CmdHandler handler, FileStatus stat, 
  1116.                                    FileSystem srcFs, 
  1117.                                    boolean recursive) throws IOException {
  1118.     int errors = 0;
  1119.     handler.run(stat, srcFs);
  1120.     if (recursive && stat.isDir() && handler.okToContinue()) {
  1121.       FileStatus[] files = shellListStatus(handler.getName(), srcFs, stat);
  1122.       if (files == null) {
  1123.         return 1;
  1124.       }
  1125.       for(FileStatus file : files ) {
  1126.         errors += runCmdHandler(handler, file, srcFs, recursive);
  1127.       }
  1128.     }
  1129.     return errors;
  1130.   }
  1131.   ///top level runCmdHandler
  1132.   int runCmdHandler(CmdHandler handler, String[] args,
  1133.                                    int startIndex, boolean recursive) 
  1134.                                    throws IOException {
  1135.     int errors = 0;
  1136.     
  1137.     for (int i=startIndex; i<args.length; i++) {
  1138.       Path srcPath = new Path(args[i]);
  1139.       FileSystem srcFs = srcPath.getFileSystem(getConf());
  1140.       Path[] paths = FileUtil.stat2Paths(srcFs.globStatus(srcPath), srcPath);
  1141.       for(Path path : paths) {
  1142.         try {
  1143.           FileStatus file = srcFs.getFileStatus(path);
  1144.           if (file == null) {
  1145.             System.err.println(handler.getName() + 
  1146.                                ": could not get status for '" + path + "'");
  1147.             errors++;
  1148.           } else {
  1149.             errors += runCmdHandler(handler, file, srcFs, recursive);
  1150.           }
  1151.         } catch (IOException e) {
  1152.           String msg = (e.getMessage() != null ? e.getLocalizedMessage() :
  1153.             (e.getCause().getMessage() != null ? 
  1154.                 e.getCause().getLocalizedMessage() : "null"));
  1155.           System.err.println(handler.getName() + ": could not get status for '"
  1156.                                         + path + "': " + msg.split("n")[0]);        
  1157.         }
  1158.       }
  1159.     }
  1160.     
  1161.     return (errors > 0 || handler.getErrorCode() != 0) ? 1 : 0;
  1162.   }
  1163.   
  1164.   /**
  1165.    * Return an abbreviated English-language desc of the byte length
  1166.    * @deprecated Consider using {@link org.apache.hadoop.util.StringUtils#byteDesc} instead.
  1167.    */
  1168.   @Deprecated
  1169.   public static String byteDesc(long len) {
  1170.     return StringUtils.byteDesc(len);
  1171.   }
  1172.   /**
  1173.    * @deprecated Consider using {@link org.apache.hadoop.util.StringUtils#limitDecimalTo2} instead.
  1174.    */
  1175.   @Deprecated
  1176.   public static synchronized String limitDecimalTo2(double d) {
  1177.     return StringUtils.limitDecimalTo2(d);
  1178.   }
  1179.   private void printHelp(String cmd) {
  1180.     String summary = "hadoop fs is the command to execute fs commands. " +
  1181.       "The full syntax is: nn" +
  1182.       "hadoop fs [-fs <local | file system URI>] [-conf <configuration file>]nt" +
  1183.       "[-D <property=value>] [-ls <path>] [-lsr <path>] [-du <path>]nt" + 
  1184.       "[-dus <path>] [-mv <src> <dst>] [-cp <src> <dst>] [-rm <src>]nt" + 
  1185.       "[-rmr <src>] [-put <localsrc> ... <dst>] [-copyFromLocal <localsrc> ... <dst>]nt" +
  1186.       "[-moveFromLocal <localsrc> ... <dst>] [" + 
  1187.       GET_SHORT_USAGE + "nt" +
  1188.       "[-getmerge <src> <localdst> [addnl]] [-cat <src>]nt" +
  1189.       "[" + COPYTOLOCAL_SHORT_USAGE + "] [-moveToLocal <src> <localdst>]nt" +
  1190.       "[-mkdir <path>] [-report] [" + SETREP_SHORT_USAGE + "]nt" +
  1191.       "[-touchz <path>] [-test -[ezd] <path>] [-stat [format] <path>]nt" +
  1192.       "[-tail [-f] <path>] [-text <path>]nt" +
  1193.       "[" + FsShellPermissions.CHMOD_USAGE + "]nt" +
  1194.       "[" + FsShellPermissions.CHOWN_USAGE + "]nt" +
  1195.       "[" + FsShellPermissions.CHGRP_USAGE + "]nt" +      
  1196.       "[" + Count.USAGE + "]nt" +      
  1197.       "[-help [cmd]]n";
  1198.     String conf ="-conf <configuration file>:  Specify an application configuration file.";
  1199.  
  1200.     String D = "-D <property=value>:  Use value for given property.";
  1201.   
  1202.     String fs = "-fs [local | <file system URI>]: tSpecify the file system to use.n" + 
  1203.       "ttIf not specified, the current configuration is used, n" +
  1204.       "tttaken from the following, in increasing precedence: n" + 
  1205.       "tttcore-default.xml inside the hadoop jar file n" +
  1206.       "tttcore-site.xml in $HADOOP_CONF_DIR n" +
  1207.       "tt'local' means use the local file system as your DFS. n" +
  1208.       "tt<file system URI> specifies a particular file system to n" +
  1209.       "ttcontact. This argument is optional but if used must appearn" +
  1210.       "ttappear first on the command line.  Exactly one additionaln" +
  1211.       "ttargument must be specified. n";
  1212.         
  1213.     String ls = "-ls <path>: tList the contents that match the specified file pattern. Ifn" + 
  1214.       "ttpath is not specified, the contents of /user/<currentUser>n" +
  1215.       "ttwill be listed. Directory entries are of the form n" +
  1216.       "tttdirName (full path) <dir> n" +
  1217.       "ttand file entries are of the form n" + 
  1218.       "tttfileName(full path) <r n> size n" +
  1219.       "ttwhere n is the number of replicas specified for the file n" + 
  1220.       "ttand size is the size of the file, in bytes.n";
  1221.     String lsr = "-lsr <path>: tRecursively list the contents that match the specifiedn" +
  1222.       "ttfile pattern.  Behaves very similarly to hadoop fs -ls,n" + 
  1223.       "ttexcept that the data is shown for all the entries in then" +
  1224.       "ttsubtree.n";
  1225.     String du = "-du <path>: tShow the amount of space, in bytes, used by the files that n" +
  1226.       "ttmatch the specified file pattern.  Equivalent to the unixn" + 
  1227.       "ttcommand "du -sb <path>/*" in case of a directory, n" +
  1228.       "ttand to "du -b <path>" in case of a file.n" +
  1229.       "ttThe output is in the form n" + 
  1230.       "tttname(full path) size (in bytes)n"; 
  1231.     String dus = "-dus <path>: tShow the amount of space, in bytes, used by the files that n" +
  1232.       "ttmatch the specified file pattern.  Equivalent to the unixn" + 
  1233.       "ttcommand "du -sb"  The output is in the form n" + 
  1234.       "tttname(full path) size (in bytes)n"; 
  1235.     
  1236.     String mv = "-mv <src> <dst>:   Move files that match the specified file pattern <src>n" +
  1237.       "ttto a destination <dst>.  When moving multiple files, the n" +
  1238.       "ttdestination must be a directory. n";
  1239.     String cp = "-cp <src> <dst>:   Copy files that match the file pattern <src> to a n" +
  1240.       "ttdestination.  When copying multiple files, the destinationn" +
  1241.       "ttmust be a directory. n";
  1242.     String rm = "-rm <src>: tDelete all files that match the specified file pattern.n" +
  1243.       "ttEquivlent to the Unix command "rm <src>"n";
  1244.     String rmr = "-rmr <src>: tRemove all directories which match the specified file n" +
  1245.       "ttpattern. Equivlent to the Unix command "rm -rf <src>"n";
  1246.     String put = "-put <localsrc> ... <dst>: tCopy files " + 
  1247.     "from the local file system nttinto fs. n";
  1248.     String copyFromLocal = "-copyFromLocal <localsrc> ... <dst>:" +
  1249.     " Identical to the -put command.n";
  1250.     String moveFromLocal = "-moveFromLocal <localsrc> ... <dst>:" +
  1251.     " Same as -put, except that the source isnttdeleted after it's copied.n"; 
  1252.     String get = GET_SHORT_USAGE
  1253.       + ":  Copy files that match the file pattern <src> n" +
  1254.       "ttto the local name.  <src> is kept.  When copying mutiple, n" +
  1255.       "ttfiles, the destination must be a directory. n";
  1256.     String getmerge = "-getmerge <src> <localdst>:  Get all the files in the directories that n" +
  1257.       "ttmatch the source file pattern and merge and sort them to onlyn" +
  1258.       "ttone file on local fs. <src> is kept.n";
  1259.     String cat = "-cat <src>: tFetch all files that match the file pattern <src> n" +
  1260.       "ttand display their content on stdout.n";
  1261.     /*
  1262.     String text = "-text <path>: Attempt to decode contents if the first few bytesn" +
  1263.       "ttmatch a magic number associated with a known formatn" +
  1264.       "tt(gzip, SequenceFile)n";
  1265.     */
  1266.     String copyToLocal = COPYTOLOCAL_SHORT_USAGE
  1267.                          + ":  Identical to the -get command.n";
  1268.     String moveToLocal = "-moveToLocal <src> <localdst>:  Not implemented yet n";
  1269.         
  1270.     String mkdir = "-mkdir <path>: tCreate a directory in specified location. n";
  1271.     String setrep = SETREP_SHORT_USAGE
  1272.       + ":  Set the replication level of a file. n"
  1273.       + "ttThe -R flag requests a recursive change of replication level n"
  1274.       + "ttfor an entire tree.n";
  1275.     String touchz = "-touchz <path>: Write a timestamp in yyyy-MM-dd HH:mm:ss formatn" +
  1276.       "ttin a file at <path>. An error is returned if the file exists with non-zero lengthn";
  1277.     String test = "-test -[ezd] <path>: If file { exists, has zero length, is a directoryn" +
  1278.       "ttthen return 0, else return 1.n";
  1279.     String stat = "-stat [format] <path>: Print statistics about the file/directory at <path>n" +
  1280.       "ttin the specified format. Format accepts filesize in blocks (%b), filename (%n),n" +
  1281.       "ttblock size (%o), replication (%r), modification date (%y, %Y)n";
  1282.     String tail = TAIL_USAGE
  1283.       + ":  Show the last 1KB of the file. n"
  1284.       + "ttThe -f option shows apended data as the file grows. n";
  1285.     String chmod = FsShellPermissions.CHMOD_USAGE + "n" +
  1286.       "ttChanges permissions of a file.n" +
  1287.       "ttThis works similar to shell's chmod with a few exceptions.nn" +
  1288.       "t-Rtmodifies the files recursively. This is the only optionn" +
  1289.       "ttcurrently supported.nn" +
  1290.       "tMODEtMode is same as mode used for chmod shell command.n" +
  1291.       "ttOnly letters recognized are 'rwxX'. E.g. a+r,g-w,+rwx,o=rnn" +
  1292.       "tOCTALMODE Mode specifed in 3 digits. Unlike shell command,n" +
  1293.       "ttthis requires all three digits.n" +
  1294.       "ttE.g. 754 is same as u=rwx,g=rx,o=rnn" +
  1295.       "ttIf none of 'augo' is specified, 'a' is assumed and unliken" +
  1296.       "ttshell command, no umask is applied.n";
  1297.     
  1298.     String chown = FsShellPermissions.CHOWN_USAGE + "n" +
  1299.       "ttChanges owner and group of a file.n" +
  1300.       "ttThis is similar to shell's chown with a few exceptions.nn" +
  1301.       "t-Rtmodifies the files recursively. This is the only optionn" +
  1302.       "ttcurrently supported.nn" +
  1303.       "ttIf only owner or group is specified then only owner orn" +
  1304.       "ttgroup is modified.nn" +
  1305.       "ttThe owner and group names may only cosists of digits, alphabet,n"+
  1306.       "ttand any of '-_.@/' i.e. [-_.@/a-zA-Z0-9]. The names are casen" +
  1307.       "ttsensitive.nn" +
  1308.       "ttWARNING: Avoid using '.' to separate user name and group thoughn" +
  1309.       "ttLinux allows it. If user names have dots in them and you aren" +
  1310.       "ttusing local file system, you might see surprising results sincen" +
  1311.       "ttshell command 'chown' is used for local files.n";
  1312.     
  1313.     String chgrp = FsShellPermissions.CHGRP_USAGE + "n" +
  1314.       "ttThis is equivalent to -chown ... :GROUP ...n";
  1315.     
  1316.     String help = "-help [cmd]: tDisplays help for given command or all commands if nonen" +
  1317.       "ttis specified.n";
  1318.     if ("fs".equals(cmd)) {
  1319.       System.out.println(fs);
  1320.     } else if ("conf".equals(cmd)) {
  1321.       System.out.println(conf);
  1322.     } else if ("D".equals(cmd)) {
  1323.       System.out.println(D);
  1324.     } else if ("ls".equals(cmd)) {
  1325.       System.out.println(ls);
  1326.     } else if ("lsr".equals(cmd)) {
  1327.       System.out.println(lsr);
  1328.     } else if ("du".equals(cmd)) {
  1329.       System.out.println(du);
  1330.     } else if ("dus".equals(cmd)) {
  1331.       System.out.println(dus);
  1332.     } else if ("rm".equals(cmd)) {
  1333.       System.out.println(rm);
  1334.     } else if ("rmr".equals(cmd)) {
  1335.       System.out.println(rmr);
  1336.     } else if ("mkdir".equals(cmd)) {
  1337.       System.out.println(mkdir);
  1338.     } else if ("mv".equals(cmd)) {
  1339.       System.out.println(mv);
  1340.     } else if ("cp".equals(cmd)) {
  1341.       System.out.println(cp);
  1342.     } else if ("put".equals(cmd)) {
  1343.       System.out.println(put);
  1344.     } else if ("copyFromLocal".equals(cmd)) {
  1345.       System.out.println(copyFromLocal);
  1346.     } else if ("moveFromLocal".equals(cmd)) {
  1347.       System.out.println(moveFromLocal);
  1348.     } else if ("get".equals(cmd)) {
  1349.       System.out.println(get);
  1350.     } else if ("getmerge".equals(cmd)) {
  1351.       System.out.println(getmerge);
  1352.     } else if ("copyToLocal".equals(cmd)) {
  1353.       System.out.println(copyToLocal);
  1354.     } else if ("moveToLocal".equals(cmd)) {
  1355.       System.out.println(moveToLocal);
  1356.     } else if ("cat".equals(cmd)) {
  1357.       System.out.println(cat);
  1358.     } else if ("get".equals(cmd)) {
  1359.       System.out.println(get);
  1360.     } else if ("setrep".equals(cmd)) {
  1361.       System.out.println(setrep);
  1362.     } else if ("touchz".equals(cmd)) {
  1363.       System.out.println(touchz);
  1364.     } else if ("test".equals(cmd)) {
  1365.       System.out.println(test);
  1366.     } else if ("stat".equals(cmd)) {
  1367.       System.out.println(stat);
  1368.     } else if ("tail".equals(cmd)) {
  1369.       System.out.println(tail);
  1370.     } else if ("chmod".equals(cmd)) {
  1371.       System.out.println(chmod);
  1372.     } else if ("chown".equals(cmd)) {
  1373.       System.out.println(chown);
  1374.     } else if ("chgrp".equals(cmd)) {
  1375.       System.out.println(chgrp);
  1376.     } else if (Count.matches(cmd)) {
  1377.       System.out.println(Count.DESCRIPTION);
  1378.     } else if ("help".equals(cmd)) {
  1379.       System.out.println(help);
  1380.     } else {
  1381.       System.out.println(summary);
  1382.       System.out.println(fs);
  1383.       System.out.println(ls);
  1384.       System.out.println(lsr);
  1385.       System.out.println(du);
  1386.       System.out.println(dus);
  1387.       System.out.println(mv);
  1388.       System.out.println(cp);
  1389.       System.out.println(rm);
  1390.       System.out.println(rmr);
  1391.       System.out.println(put);
  1392.       System.out.println(copyFromLocal);
  1393.       System.out.println(moveFromLocal);
  1394.       System.out.println(get);
  1395.       System.out.println(getmerge);
  1396.       System.out.println(cat);
  1397.       System.out.println(copyToLocal);
  1398.       System.out.println(moveToLocal);
  1399.       System.out.println(mkdir);
  1400.       System.out.println(setrep);
  1401.       System.out.println(chmod);
  1402.       System.out.println(chown);      
  1403.       System.out.println(chgrp);
  1404.       System.out.println(Count.DESCRIPTION);
  1405.       System.out.println(help);
  1406.     }        
  1407.                            
  1408.   }
  1409.   /**
  1410.    * Apply operation specified by 'cmd' on all parameters
  1411.    * starting from argv[startindex].
  1412.    */
  1413.   private int doall(String cmd, String argv[], int startindex) {
  1414.     int exitCode = 0;
  1415.     int i = startindex;
  1416.     //
  1417.     // for each source file, issue the command
  1418.     //
  1419.     for (; i < argv.length; i++) {
  1420.       try {
  1421.         //
  1422.         // issue the command to the fs
  1423.         //
  1424.         if ("-cat".equals(cmd)) {
  1425.           cat(argv[i], true);
  1426.         } else if ("-mkdir".equals(cmd)) {
  1427.           mkdir(argv[i]);
  1428.         } else if ("-rm".equals(cmd)) {
  1429.           delete(argv[i], false);
  1430.         } else if ("-rmr".equals(cmd)) {
  1431.           delete(argv[i], true);
  1432.         } else if ("-du".equals(cmd)) {
  1433.           du(argv[i]);
  1434.         } else if ("-dus".equals(cmd)) {
  1435.           dus(argv[i]);
  1436.         } else if (Count.matches(cmd)) {
  1437.           new Count(argv, i, getConf()).runAll();
  1438.         } else if ("-ls".equals(cmd)) {
  1439.           exitCode = ls(argv[i], false);
  1440.         } else if ("-lsr".equals(cmd)) {
  1441.           exitCode = ls(argv[i], true);
  1442.         } else if ("-touchz".equals(cmd)) {
  1443.           touchz(argv[i]);
  1444.         } else if ("-text".equals(cmd)) {
  1445.           text(argv[i]);
  1446.         }
  1447.       } catch (RemoteException e) {
  1448.         //
  1449.         // This is a error returned by hadoop server. Print
  1450.         // out the first line of the error message.
  1451.         //
  1452.         exitCode = -1;
  1453.         try {
  1454.           String[] content;
  1455.           content = e.getLocalizedMessage().split("n");
  1456.           System.err.println(cmd.substring(1) + ": " +
  1457.                              content[0]);
  1458.         } catch (Exception ex) {
  1459.           System.err.println(cmd.substring(1) + ": " +
  1460.                              ex.getLocalizedMessage());
  1461.         }
  1462.       } catch (IOException e) {
  1463.         //
  1464.         // IO exception encountered locally.
  1465.         //
  1466.         exitCode = -1;
  1467.         String content = e.getLocalizedMessage();
  1468.         if (content != null) {
  1469.           content = content.split("n")[0];
  1470.         }
  1471.         System.err.println(cmd.substring(1) + ": " +
  1472.                           content);
  1473.       }
  1474.     }
  1475.     return exitCode;
  1476.   }
  1477.   /**
  1478.    * Displays format of commands.
  1479.    * 
  1480.    */
  1481.   private static void printUsage(String cmd) {
  1482.     String prefix = "Usage: java " + FsShell.class.getSimpleName();
  1483.     if ("-fs".equals(cmd)) {
  1484.       System.err.println("Usage: java FsShell" + 
  1485.                          " [-fs <local | file system URI>]");
  1486.     } else if ("-conf".equals(cmd)) {
  1487.       System.err.println("Usage: java FsShell" + 
  1488.                          " [-conf <configuration file>]");
  1489.     } else if ("-D".equals(cmd)) {
  1490.       System.err.println("Usage: java FsShell" + 
  1491.                          " [-D <[property=value>]");
  1492.     } else if ("-ls".equals(cmd) || "-lsr".equals(cmd) ||
  1493.                "-du".equals(cmd) || "-dus".equals(cmd) ||
  1494.                "-rm".equals(cmd) || "-rmr".equals(cmd) ||
  1495.                "-touchz".equals(cmd) || "-mkdir".equals(cmd) ||
  1496.                "-text".equals(cmd)) {
  1497.       System.err.println("Usage: java FsShell" + 
  1498.                          " [" + cmd + " <path>]");
  1499.     } else if (Count.matches(cmd)) {
  1500.       System.err.println(prefix + " [" + Count.USAGE + "]");
  1501.     } else if ("-mv".equals(cmd) || "-cp".equals(cmd)) {
  1502.       System.err.println("Usage: java FsShell" + 
  1503.                          " [" + cmd + " <src> <dst>]");
  1504.     } else if ("-put".equals(cmd) || "-copyFromLocal".equals(cmd) ||
  1505.                "-moveFromLocal".equals(cmd)) {
  1506.       System.err.println("Usage: java FsShell" + 
  1507.                          " [" + cmd + " <localsrc> ... <dst>]");
  1508.     } else if ("-get".equals(cmd)) {
  1509.       System.err.println("Usage: java FsShell [" + GET_SHORT_USAGE + "]"); 
  1510.     } else if ("-copyToLocal".equals(cmd)) {
  1511.       System.err.println("Usage: java FsShell [" + COPYTOLOCAL_SHORT_USAGE+ "]"); 
  1512.     } else if ("-moveToLocal".equals(cmd)) {
  1513.       System.err.println("Usage: java FsShell" + 
  1514.                          " [" + cmd + " [-crc] <src> <localdst>]");
  1515.     } else if ("-cat".equals(cmd)) {
  1516.       System.err.println("Usage: java FsShell" + 
  1517.                          " [" + cmd + " <src>]");
  1518.     } else if ("-setrep".equals(cmd)) {
  1519.       System.err.println("Usage: java FsShell [" + SETREP_SHORT_USAGE + "]");
  1520.     } else if ("-test".equals(cmd)) {
  1521.       System.err.println("Usage: java FsShell" +
  1522.                          " [-test -[ezd] <path>]");
  1523.     } else if ("-stat".equals(cmd)) {
  1524.       System.err.println("Usage: java FsShell" +
  1525.                          " [-stat [format] <path>]");
  1526.     } else if ("-tail".equals(cmd)) {
  1527.       System.err.println("Usage: java FsShell [" + TAIL_USAGE + "]");
  1528.     } else {
  1529.       System.err.println("Usage: java FsShell");
  1530.       System.err.println("           [-ls <path>]");
  1531.       System.err.println("           [-lsr <path>]");
  1532.       System.err.println("           [-du <path>]");
  1533.       System.err.println("           [-dus <path>]");
  1534.       System.err.println("           [" + Count.USAGE + "]");
  1535.       System.err.println("           [-mv <src> <dst>]");
  1536.       System.err.println("           [-cp <src> <dst>]");
  1537.       System.err.println("           [-rm <path>]");
  1538.       System.err.println("           [-rmr <path>]");
  1539.       System.err.println("           [-expunge]");
  1540.       System.err.println("           [-put <localsrc> ... <dst>]");
  1541.       System.err.println("           [-copyFromLocal <localsrc> ... <dst>]");
  1542.       System.err.println("           [-moveFromLocal <localsrc> ... <dst>]");
  1543.       System.err.println("           [" + GET_SHORT_USAGE + "]");
  1544.       System.err.println("           [-getmerge <src> <localdst> [addnl]]");
  1545.       System.err.println("           [-cat <src>]");
  1546.       System.err.println("           [-text <src>]");
  1547.       System.err.println("           [" + COPYTOLOCAL_SHORT_USAGE + "]");
  1548.       System.err.println("           [-moveToLocal [-crc] <src> <localdst>]");
  1549.       System.err.println("           [-mkdir <path>]");
  1550.       System.err.println("           [" + SETREP_SHORT_USAGE + "]");
  1551.       System.err.println("           [-touchz <path>]");
  1552.       System.err.println("           [-test -[ezd] <path>]");
  1553.       System.err.println("           [-stat [format] <path>]");
  1554.       System.err.println("           [" + TAIL_USAGE + "]");
  1555.       System.err.println("           [" + FsShellPermissions.CHMOD_USAGE + "]");      
  1556.       System.err.println("           [" + FsShellPermissions.CHOWN_USAGE + "]");
  1557.       System.err.println("           [" + FsShellPermissions.CHGRP_USAGE + "]");
  1558.       System.err.println("           [-help [cmd]]");
  1559.       System.err.println();
  1560.       ToolRunner.printGenericCommandUsage(System.err);
  1561.     }
  1562.   }
  1563.   /**
  1564.    * run
  1565.    */
  1566.   public int run(String argv[]) throws Exception {
  1567.     if (argv.length < 1) {
  1568.       printUsage(""); 
  1569.       return -1;
  1570.     }
  1571.     int exitCode = -1;
  1572.     int i = 0;
  1573.     String cmd = argv[i++];
  1574.     //
  1575.     // verify that we have enough command line parameters
  1576.     //
  1577.     if ("-put".equals(cmd) || "-test".equals(cmd) ||
  1578.         "-copyFromLocal".equals(cmd) || "-moveFromLocal".equals(cmd)) {
  1579.       if (argv.length < 3) {
  1580.         printUsage(cmd);
  1581.         return exitCode;
  1582.       }
  1583.     } else if ("-get".equals(cmd) || 
  1584.                "-copyToLocal".equals(cmd) || "-moveToLocal".equals(cmd)) {
  1585.       if (argv.length < 3) {
  1586.         printUsage(cmd);
  1587.         return exitCode;
  1588.       }
  1589.     } else if ("-mv".equals(cmd) || "-cp".equals(cmd)) {
  1590.       if (argv.length < 3) {
  1591.         printUsage(cmd);
  1592.         return exitCode;
  1593.       }
  1594.     } else if ("-rm".equals(cmd) || "-rmr".equals(cmd) ||
  1595.                "-cat".equals(cmd) || "-mkdir".equals(cmd) ||
  1596.                "-touchz".equals(cmd) || "-stat".equals(cmd) ||
  1597.                "-text".equals(cmd)) {
  1598.       if (argv.length < 2) {
  1599.         printUsage(cmd);
  1600.         return exitCode;
  1601.       }
  1602.     }
  1603.     // initialize FsShell
  1604.     try {
  1605.       init();
  1606.     } catch (RPC.VersionMismatch v) { 
  1607.       System.err.println("Version Mismatch between client and server" +
  1608.                          "... command aborted.");
  1609.       return exitCode;
  1610.     } catch (IOException e) {
  1611.       System.err.println("Bad connection to FS. command aborted.");
  1612.       return exitCode;
  1613.     }
  1614.     exitCode = 0;
  1615.     try {
  1616.       if ("-put".equals(cmd) || "-copyFromLocal".equals(cmd)) {
  1617.         Path[] srcs = new Path[argv.length-2];
  1618.         for (int j=0 ; i < argv.length-1 ;) 
  1619.           srcs[j++] = new Path(argv[i++]);
  1620.         copyFromLocal(srcs, argv[i++]);
  1621.       } else if ("-moveFromLocal".equals(cmd)) {
  1622.         Path[] srcs = new Path[argv.length-2];
  1623.         for (int j=0 ; i < argv.length-1 ;) 
  1624.           srcs[j++] = new Path(argv[i++]);
  1625.         moveFromLocal(srcs, argv[i++]);
  1626.       } else if ("-get".equals(cmd) || "-copyToLocal".equals(cmd)) {
  1627.         copyToLocal(argv, i);
  1628.       } else if ("-getmerge".equals(cmd)) {
  1629.         if (argv.length>i+2)
  1630.           copyMergeToLocal(argv[i++], new Path(argv[i++]), Boolean.parseBoolean(argv[i++]));
  1631.         else
  1632.           copyMergeToLocal(argv[i++], new Path(argv[i++]));
  1633.       } else if ("-cat".equals(cmd)) {
  1634.         exitCode = doall(cmd, argv, i);
  1635.       } else if ("-text".equals(cmd)) {
  1636.         exitCode = doall(cmd, argv, i);
  1637.       } else if ("-moveToLocal".equals(cmd)) {
  1638.         moveToLocal(argv[i++], new Path(argv[i++]));
  1639.       } else if ("-setrep".equals(cmd)) {
  1640.         setReplication(argv, i);           
  1641.       } else if ("-chmod".equals(cmd) || 
  1642.                  "-chown".equals(cmd) ||
  1643.                  "-chgrp".equals(cmd)) {
  1644.         FsShellPermissions.changePermissions(fs, cmd, argv, i, this);
  1645.       } else if ("-ls".equals(cmd)) {
  1646.         if (i < argv.length) {
  1647.           exitCode = doall(cmd, argv, i);
  1648.         } else {
  1649.           exitCode = ls(Path.CUR_DIR, false);
  1650.         } 
  1651.       } else if ("-lsr".equals(cmd)) {
  1652.         if (i < argv.length) {
  1653.           exitCode = doall(cmd, argv, i);
  1654.         } else {
  1655.           exitCode = ls(Path.CUR_DIR, true);
  1656.         } 
  1657.       } else if ("-mv".equals(cmd)) {
  1658.         exitCode = rename(argv, getConf());
  1659.       } else if ("-cp".equals(cmd)) {
  1660.         exitCode = copy(argv, getConf());
  1661.       } else if ("-rm".equals(cmd)) {
  1662.         exitCode = doall(cmd, argv, i);
  1663.       } else if ("-rmr".equals(cmd)) {
  1664.         exitCode = doall(cmd, argv, i);
  1665.       } else if ("-expunge".equals(cmd)) {
  1666.         expunge();
  1667.       } else if ("-du".equals(cmd)) {
  1668.         if (i < argv.length) {
  1669.           exitCode = doall(cmd, argv, i);
  1670.         } else {
  1671.           du(".");
  1672.         }
  1673.       } else if ("-dus".equals(cmd)) {
  1674.         if (i < argv.length) {
  1675.           exitCode = doall(cmd, argv, i);
  1676.         } else {
  1677.           dus(".");
  1678.         }         
  1679.       } else if (Count.matches(cmd)) {
  1680.         exitCode = new Count(argv, i, getConf()).runAll();
  1681.       } else if ("-mkdir".equals(cmd)) {
  1682.         exitCode = doall(cmd, argv, i);
  1683.       } else if ("-touchz".equals(cmd)) {
  1684.         exitCode = doall(cmd, argv, i);
  1685.       } else if ("-test".equals(cmd)) {
  1686.         exitCode = test(argv, i);
  1687.       } else if ("-stat".equals(cmd)) {
  1688.         if (i + 1 < argv.length) {
  1689.           stat(argv[i++].toCharArray(), argv[i++]);
  1690.         } else {
  1691.           stat("%y".toCharArray(), argv[i]);
  1692.         }
  1693.       } else if ("-help".equals(cmd)) {
  1694.         if (i < argv.length) {
  1695.           printHelp(argv[i]);
  1696.         } else {
  1697.           printHelp("");
  1698.         }
  1699.       } else if ("-tail".equals(cmd)) {
  1700.         tail(argv, i);           
  1701.       } else {
  1702.         exitCode = -1;
  1703.         System.err.println(cmd.substring(1) + ": Unknown command");
  1704.         printUsage("");
  1705.       }
  1706.     } catch (IllegalArgumentException arge) {
  1707.       exitCode = -1;
  1708.       System.err.println(cmd.substring(1) + ": " + arge.getLocalizedMessage());
  1709.       printUsage(cmd);
  1710.     } catch (RemoteException e) {
  1711.       //
  1712.       // This is a error returned by hadoop server. Print
  1713.       // out the first line of the error mesage, ignore the stack trace.
  1714.       exitCode = -1;
  1715.       try {
  1716.         String[] content;
  1717.         content = e.getLocalizedMessage().split("n");
  1718.         System.err.println(cmd.substring(1) + ": " + 
  1719.                            content[0]);
  1720.       } catch (Exception ex) {
  1721.         System.err.println(cmd.substring(1) + ": " + 
  1722.                            ex.getLocalizedMessage());  
  1723.       }
  1724.     } catch (IOException e) {
  1725.       //
  1726.       // IO exception encountered locally.
  1727.       // 
  1728.       exitCode = -1;
  1729.       System.err.println(cmd.substring(1) + ": " + 
  1730.                          e.getLocalizedMessage());  
  1731.     } catch (Exception re) {
  1732.       exitCode = -1;
  1733.       System.err.println(cmd.substring(1) + ": " + re.getLocalizedMessage());  
  1734.     } finally {
  1735.     }
  1736.     return exitCode;
  1737.   }
  1738.   public void close() throws IOException {
  1739.     if (fs != null) {
  1740.       fs.close();
  1741.       fs = null;
  1742.     }
  1743.   }
  1744.   /**
  1745.    * main() has some simple utility methods
  1746.    */
  1747.   public static void main(String argv[]) throws Exception {
  1748.     FsShell shell = new FsShell();
  1749.     int res;
  1750.     try {
  1751.       res = ToolRunner.run(shell, argv);
  1752.     } finally {
  1753.       shell.close();
  1754.     }
  1755.     System.exit(res);
  1756.   }
  1757.   /**
  1758.    * Accumulate exceptions if there is any.  Throw them at last.
  1759.    */
  1760.   private abstract class DelayedExceptionThrowing {
  1761.     abstract void process(Path p, FileSystem srcFs) throws IOException;
  1762.     final void globAndProcess(Path srcPattern, FileSystem srcFs
  1763.         ) throws IOException {
  1764.       List<IOException> exceptions = new ArrayList<IOException>();
  1765.       for(Path p : FileUtil.stat2Paths(srcFs.globStatus(srcPattern), 
  1766.                                        srcPattern))
  1767.         try { process(p, srcFs); } 
  1768.         catch(IOException ioe) { exceptions.add(ioe); }
  1769.     
  1770.       if (!exceptions.isEmpty())
  1771.         if (exceptions.size() == 1)
  1772.           throw exceptions.get(0);
  1773.         else 
  1774.           throw new IOException("Multiple IOExceptions: " + exceptions);
  1775.     }
  1776.   }
  1777. }