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    package org.apache.hadoop.fs;
019    
020    import java.io.IOException;
021    
022    import org.apache.hadoop.classification.InterfaceAudience;
023    import org.apache.hadoop.classification.InterfaceStability;
024    import org.apache.hadoop.conf.Configuration;
025    import org.apache.hadoop.conf.Configured;
026    
027    /** 
028     * Provides a trash facility which supports pluggable Trash policies. 
029     *
030     * See the implementation of the configured TrashPolicy for more
031     * details.
032     */
033    @InterfaceAudience.Public
034    @InterfaceStability.Stable
035    public class Trash extends Configured {
036      private TrashPolicy trashPolicy; // configured trash policy instance
037    
038      /** 
039       * Construct a trash can accessor.
040       * @param conf a Configuration
041       */
042      public Trash(Configuration conf) throws IOException {
043        this(FileSystem.get(conf), conf);
044      }
045    
046      /**
047       * Construct a trash can accessor for the FileSystem provided.
048       * @param fs the FileSystem
049       * @param conf a Configuration
050       */
051      public Trash(FileSystem fs, Configuration conf) throws IOException {
052        super(conf);
053        trashPolicy = TrashPolicy.getInstance(conf, fs, fs.getHomeDirectory());
054      }
055    
056      /**
057       * In case of the symlinks or mount points, one has to move the appropriate
058       * trashbin in the actual volume of the path p being deleted.
059       *
060       * Hence we get the file system of the fully-qualified resolved-path and
061       * then move the path p to the trashbin in that volume,
062       * @param fs - the filesystem of path p
063       * @param p - the  path being deleted - to be moved to trasg
064       * @param conf - configuration
065       * @return false if the item is already in the trash or trash is disabled
066       * @throws IOException on error
067       */
068      public static boolean moveToAppropriateTrash(FileSystem fs, Path p,
069          Configuration conf) throws IOException {
070        Path fullyResolvedPath = fs.resolvePath(p);
071        FileSystem fullyResolvedFs =
072            FileSystem.get(fullyResolvedPath.toUri(), conf);
073        // If the trash interval is configured server side then clobber this
074        // configuration so that we always respect the server configuration.
075        try {
076          long trashInterval = fullyResolvedFs.getServerDefaults(
077              fullyResolvedPath).getTrashInterval();
078          if (0 != trashInterval) {
079            Configuration confCopy = new Configuration(conf);
080            confCopy.setLong(CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY,
081                trashInterval);
082            conf = confCopy;
083          }
084        } catch (Exception e) {
085          // If we can not determine that trash is enabled server side then
086          // bail rather than potentially deleting a file when trash is enabled.
087          throw new IOException("Failed to get server trash configuration", e);
088        }
089        Trash trash = new Trash(fullyResolvedFs, conf);
090        boolean success = trash.moveToTrash(fullyResolvedPath);
091        if (success) {
092          System.out.println("Moved: '" + p + "' to trash at: " +
093              trash.getCurrentTrashDir() );
094        }
095        return success;
096      }
097      
098      /**
099       * Returns whether the trash is enabled for this filesystem
100       */
101      public boolean isEnabled() {
102        return trashPolicy.isEnabled();
103      }
104    
105      /** Move a file or directory to the current trash directory.
106       * @return false if the item is already in the trash or trash is disabled
107       */ 
108      public boolean moveToTrash(Path path) throws IOException {
109        return trashPolicy.moveToTrash(path);
110      }
111    
112      /** Create a trash checkpoint. */
113      public void checkpoint() throws IOException {
114        trashPolicy.createCheckpoint();
115      }
116    
117      /** Delete old checkpoint(s). */
118      public void expunge() throws IOException {
119        trashPolicy.deleteCheckpoint();
120      }
121    
122      /** get the current working directory */
123      Path getCurrentTrashDir() {
124        return trashPolicy.getCurrentTrashDir();
125      }
126    
127      /** get the configured trash policy */
128      TrashPolicy getTrashPolicy() {
129        return trashPolicy;
130      }
131    
132      /** Return a {@link Runnable} that periodically empties the trash of all
133       * users, intended to be run by the superuser.
134       */
135      public Runnable getEmptier() throws IOException {
136        return trashPolicy.getEmptier();
137      }
138    }