001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.fs;
019
020import java.io.IOException;
021
022import org.apache.commons.logging.LogFactory;
023import org.apache.hadoop.classification.InterfaceAudience;
024import org.apache.hadoop.classification.InterfaceStability;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.conf.Configured;
027
028/** 
029 * Provides a trash facility which supports pluggable Trash policies. 
030 *
031 * See the implementation of the configured TrashPolicy for more
032 * details.
033 */
034@InterfaceAudience.Public
035@InterfaceStability.Stable
036public class Trash extends Configured {
037  private static final org.apache.commons.logging.Log LOG =
038      LogFactory.getLog(Trash.class);
039
040  private TrashPolicy trashPolicy; // configured trash policy instance
041
042  /** 
043   * Construct a trash can accessor.
044   * @param conf a Configuration
045   */
046  public Trash(Configuration conf) throws IOException {
047    this(FileSystem.get(conf), conf);
048  }
049
050  /**
051   * Construct a trash can accessor for the FileSystem provided.
052   * @param fs the FileSystem
053   * @param conf a Configuration
054   */
055  public Trash(FileSystem fs, Configuration conf) throws IOException {
056    super(conf);
057    trashPolicy = TrashPolicy.getInstance(conf, fs, fs.getHomeDirectory());
058  }
059
060  /**
061   * In case of the symlinks or mount points, one has to move the appropriate
062   * trashbin in the actual volume of the path p being deleted.
063   *
064   * Hence we get the file system of the fully-qualified resolved-path and
065   * then move the path p to the trashbin in that volume,
066   * @param fs - the filesystem of path p
067   * @param p - the  path being deleted - to be moved to trasg
068   * @param conf - configuration
069   * @return false if the item is already in the trash or trash is disabled
070   * @throws IOException on error
071   */
072  public static boolean moveToAppropriateTrash(FileSystem fs, Path p,
073      Configuration conf) throws IOException {
074    Path fullyResolvedPath = fs.resolvePath(p);
075    FileSystem fullyResolvedFs =
076        FileSystem.get(fullyResolvedPath.toUri(), conf);
077    // If the trash interval is configured server side then clobber this
078    // configuration so that we always respect the server configuration.
079    try {
080      long trashInterval = fullyResolvedFs.getServerDefaults(
081          fullyResolvedPath).getTrashInterval();
082      if (0 != trashInterval) {
083        Configuration confCopy = new Configuration(conf);
084        confCopy.setLong(CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_KEY,
085            trashInterval);
086        conf = confCopy;
087      }
088    } catch (Exception e) {
089      // If we can not determine that trash is enabled server side then
090      // bail rather than potentially deleting a file when trash is enabled.
091      LOG.warn("Failed to get server trash configuration", e);
092      throw new IOException("Failed to get server trash configuration", e);
093    }
094    Trash trash = new Trash(fullyResolvedFs, conf);
095    boolean success = trash.moveToTrash(fullyResolvedPath);
096    if (success) {
097      System.out.println("Moved: '" + p + "' to trash at: " +
098          trash.getCurrentTrashDir() );
099    }
100    return success;
101  }
102  
103  /**
104   * Returns whether the trash is enabled for this filesystem
105   */
106  public boolean isEnabled() {
107    return trashPolicy.isEnabled();
108  }
109
110  /** Move a file or directory to the current trash directory.
111   * @return false if the item is already in the trash or trash is disabled
112   */ 
113  public boolean moveToTrash(Path path) throws IOException {
114    return trashPolicy.moveToTrash(path);
115  }
116
117  /** Create a trash checkpoint. */
118  public void checkpoint() throws IOException {
119    trashPolicy.createCheckpoint();
120  }
121
122  /** Delete old checkpoint(s). */
123  public void expunge() throws IOException {
124    trashPolicy.deleteCheckpoint();
125  }
126
127  /** get the current working directory */
128  public Path getCurrentTrashDir() {
129    return trashPolicy.getCurrentTrashDir();
130  }
131
132  /** get the configured trash policy */
133  TrashPolicy getTrashPolicy() {
134    return trashPolicy;
135  }
136
137  /** Return a {@link Runnable} that periodically empties the trash of all
138   * users, intended to be run by the superuser.
139   */
140  public Runnable getEmptier() throws IOException {
141    return trashPolicy.getEmptier();
142  }
143}