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     */
018    
019    package org.apache.hadoop.fs;
020    
021    import java.io.File;
022    import java.io.IOException;
023    import java.net.URI;
024    import java.util.Random;
025    
026    import org.apache.hadoop.classification.InterfaceAudience;
027    import org.apache.hadoop.classification.InterfaceStability;
028    import org.apache.hadoop.conf.Configuration;
029    
030    /****************************************************************
031     * Implement the FileSystem API for the checksumed local filesystem.
032     *
033     *****************************************************************/
034    @InterfaceAudience.Public
035    @InterfaceStability.Stable
036    public class LocalFileSystem extends ChecksumFileSystem {
037      static final URI NAME = URI.create("file:///");
038      static private Random rand = new Random();
039      
040      public LocalFileSystem() {
041        this(new RawLocalFileSystem());
042      }
043      
044      @Override
045      public void initialize(URI name, Configuration conf) throws IOException {
046        if (fs.getConf() == null) {
047          fs.initialize(name, conf);
048        }
049        String scheme = name.getScheme();
050        if (!scheme.equals(fs.getUri().getScheme())) {
051          swapScheme = scheme;
052        }
053      }
054    
055      /**
056       * Return the protocol scheme for the FileSystem.
057       * <p/>
058       *
059       * @return <code>file</code>
060       */
061      @Override
062      public String getScheme() {
063        return "file";
064      }
065    
066      public FileSystem getRaw() {
067        return getRawFileSystem();
068      }
069        
070      public LocalFileSystem(FileSystem rawLocalFileSystem) {
071        super(rawLocalFileSystem);
072      }
073        
074      /** Convert a path to a File. */
075      public File pathToFile(Path path) {
076        return ((RawLocalFileSystem)fs).pathToFile(path);
077      }
078    
079      @Override
080      public void copyFromLocalFile(boolean delSrc, Path src, Path dst)
081        throws IOException {
082        FileUtil.copy(this, src, this, dst, delSrc, getConf());
083      }
084    
085      @Override
086      public void copyToLocalFile(boolean delSrc, Path src, Path dst)
087        throws IOException {
088        FileUtil.copy(this, src, this, dst, delSrc, getConf());
089      }
090    
091      /**
092       * Moves files to a bad file directory on the same device, so that their
093       * storage will not be reused.
094       */
095      @Override
096      public boolean reportChecksumFailure(Path p, FSDataInputStream in,
097                                           long inPos,
098                                           FSDataInputStream sums, long sumsPos) {
099        try {
100          // canonicalize f
101          File f = ((RawLocalFileSystem)fs).pathToFile(p).getCanonicalFile();
102          
103          // find highest writable parent dir of f on the same device
104          String device = new DF(f, getConf()).getMount();
105          File parent = f.getParentFile();
106          File dir = null;
107          while (parent != null && FileUtil.canWrite(parent) &&
108              parent.toString().startsWith(device)) {
109            dir = parent;
110            parent = parent.getParentFile();
111          }
112    
113          if (dir==null) {
114            throw new IOException(
115                                  "not able to find the highest writable parent dir");
116          }
117            
118          // move the file there
119          File badDir = new File(dir, "bad_files");
120          if (!badDir.mkdirs()) {
121            if (!badDir.isDirectory()) {
122              throw new IOException("Mkdirs failed to create " + badDir.toString());
123            }
124          }
125          String suffix = "." + rand.nextInt();
126          File badFile = new File(badDir, f.getName()+suffix);
127          LOG.warn("Moving bad file " + f + " to " + badFile);
128          in.close();                               // close it first
129          boolean b = f.renameTo(badFile);                      // rename it
130          if (!b) {
131            LOG.warn("Ignoring failure of renameTo");
132          }
133          // move checksum file too
134          File checkFile = ((RawLocalFileSystem)fs).pathToFile(getChecksumFile(p));
135          // close the stream before rename to release the file handle
136          sums.close();
137          b = checkFile.renameTo(new File(badDir, checkFile.getName()+suffix));
138          if (!b) {
139              LOG.warn("Ignoring failure of renameTo");
140            }
141        } catch (IOException e) {
142          LOG.warn("Error moving bad file " + p + ": " + e);
143        }
144        return false;
145      }
146    
147      @Override
148      public boolean supportsSymlinks() {
149        return true;
150      }
151    
152      @Override
153      public void createSymlink(Path target, Path link, boolean createParent)
154          throws IOException {
155        fs.createSymlink(target, link, createParent);
156      }
157    
158      @Override
159      public FileStatus getFileLinkStatus(final Path f) throws IOException {
160        return fs.getFileLinkStatus(f);
161      }
162    
163      @Override
164      public Path getLinkTarget(Path f) throws IOException {
165        return fs.getLinkTarget(f);
166      }
167    }