/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.fs; import java.io.FileNotFoundException; import java.io.IOException; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem.GlobFilter; /** * main logic of delete a file */ public class DeleteUtils { public static final Log LOG = LogFactory.getLog(DeleteUtils.class); /* delete a file */ static public void delete(Configuration conf, Path src, FileSystem srcFs, boolean recursive, boolean skipTrash, boolean ignoreNonEmpty, boolean onlyDeleteFile) throws IOException { FileStatus fs = null; try { fs = srcFs.getFileStatus(src); } catch (FileNotFoundException fnfe) { // Have to re-throw so that console output is as expected throw new FileNotFoundException("cannot remove " + src + ": No such file or directory."); } if (fs.isDir() && !recursive) { // We may safely delete empty directories if // the recursive option is not specified FileStatus children[] = srcFs.listStatus(src); if (onlyDeleteFile || (children != null && children.length != 0)) { if (ignoreNonEmpty) { return; } else { throw new IOException("Cannot remove directory \"" + src + "\"," + " use -rmr instead"); } } else if (children == null) { throw new IOException(src + " no longer exists"); } } if(!skipTrash) { try { Trash trashTmp = new Trash(srcFs, conf); if (trashTmp.moveToTrash(src)) { System.err.println("Moved to trash: " + src); return; } } catch (IOException e) { Exception cause = (Exception) e.getCause(); String msg = ""; if(cause != null) { msg = cause.getLocalizedMessage(); } System.err.println("Problem with Trash." + msg +". Consider using -skipTrash option"); throw e; } } if (srcFs.delete(src, recursive, true)) { System.err.println("Deleted " + src); } else { throw new IOException("Delete failed " + src); } } private static final String DEFAULT_TMP_PATH = "{/tmp,/namespace/*/tmp}"; public static boolean isTempPath(Configuration conf, String file) { // TODO: implement a version that accepts a list of path patterns, instead // of prefixes. The current implementation is temporary and // inefficient. Several string copying and object creations can be avoided. String tempPathPattern = getTempPathPattern(conf); return isTempPathUseDefaultOnFailure(tempPathPattern, file); } static String getTempPathPattern(Configuration conf) { return conf.get("fs.trash.tmp.path.pattern", DEFAULT_TMP_PATH); } public static boolean isTempPathUseDefaultOnFailure(String pathPattern, String path) { try { return isTempPath(pathPattern, path); } catch (IOException ioe) { LOG.warn("Configured tmp directory " + pathPattern + " is not valid, use default value instead."); try { return isTempPath(DEFAULT_TMP_PATH, path); } catch (IOException ioe2) { LOG.warn("Default temp path still causes exception", ioe2); return false; } } } public static boolean isTempPath(String pathPattern, String path) throws IOException { List<String> listPatterns = GlobExpander.expand(pathPattern); if (listPatterns == null || listPatterns.isEmpty()) { return false; } String filename = new Path(path).toUri().getPath(); String[] components = filename.split(Path.SEPARATOR); for (String pattern : listPatterns) { Path p = new Path(pattern); if (!p.isAbsolute()) { throw new IOException("Temp path setting has relative path " + p + ", which is not allowed."); } else { if (ifMatchPathPattern(p, components)) { return true; } } } return false; } public static boolean ifMatchPathPattern(Path pattern, String[] pathComponents) throws IOException { String[] patternComponents = pattern.toUri().getPath().split(Path.SEPARATOR); if (pathComponents.length < patternComponents.length) { return false; } for (int i = 0; i < patternComponents.length; i++) { GlobFilter fp = new GlobFilter(patternComponents[i], null); if (!fp.hasPattern()) { if (!patternComponents[i].equals(pathComponents[i])) { return false; } } else { if (!fp.accept(pathComponents[i])) { return false; } } } return true; } }