blob: fb0784c9501369b45d12659d20396ed91b57b65a [file] [log] [blame]
/**
* 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.activemq.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* Collection of File and Folder utility methods.
*/
public final class IOHelper {
protected static final int MAX_DIR_NAME_LENGTH;
protected static final int MAX_FILE_NAME_LENGTH;
private static final int DEFAULT_BUFFER_SIZE = 4096;
private IOHelper() {
}
public static String getDefaultDataDirectory() {
return getDefaultDirectoryPrefix() + "activemq-data";
}
public static String getDefaultStoreDirectory() {
return getDefaultDirectoryPrefix() + "amqstore";
}
/**
* Allows a system property to be used to overload the default data
* directory which can be useful for forcing the test cases to use a target/
* prefix
*/
public static String getDefaultDirectoryPrefix() {
try {
return System.getProperty("org.apache.activemq.default.directory.prefix", "");
} catch (Exception e) {
return "";
}
}
/**
* Converts any string into a string that is safe to use as a file name. The
* result will only include ascii characters and numbers, and the "-","_",
* and "." characters.
*
* @param name
* @return safe name of the directory
*/
public static String toFileSystemDirectorySafeName(String name) {
return toFileSystemSafeName(name, true, MAX_DIR_NAME_LENGTH);
}
public static String toFileSystemSafeName(String name) {
return toFileSystemSafeName(name, false, MAX_FILE_NAME_LENGTH);
}
/**
* Converts any string into a string that is safe to use as a file name. The
* result will only include ascii characters and numbers, and the "-","_",
* and "." characters.
*
* @param name
* @param dirSeparators
* @param maxFileLength
* @return file system safe name
*/
public static String toFileSystemSafeName(String name, boolean dirSeparators, int maxFileLength) {
int size = name.length();
StringBuffer rc = new StringBuffer(size * 2);
for (int i = 0; i < size; i++) {
char c = name.charAt(i);
boolean valid = c >= 'a' && c <= 'z';
valid = valid || (c >= 'A' && c <= 'Z');
valid = valid || (c >= '0' && c <= '9');
valid = valid || (c == '_') || (c == '-') || (c == '.') || (c == '#') || (dirSeparators && ((c == '/') || (c == '\\')));
if (valid) {
rc.append(c);
} else {
// Encode the character using hex notation
rc.append('#');
rc.append(HexSupport.toHexFromInt(c, true));
}
}
String result = rc.toString();
if (result.length() > maxFileLength) {
result = result.substring(result.length() - maxFileLength, result.length());
}
return result;
}
public static boolean delete(File top) {
boolean result = true;
Stack<File> files = new Stack<File>();
// Add file to the stack to be processed...
files.push(top);
// Process all files until none remain...
while (!files.isEmpty()) {
File file = files.pop();
if (file.isDirectory()) {
File list[] = file.listFiles();
if (list == null || list.length == 0) {
// The current directory contains no entries...
// delete directory and continue...
result &= file.delete();
} else {
// Add back the directory since it is not empty....
// and when we process it again it will be empty and can be
// deleted safely...
files.push(file);
for (File dirFile : list) {
if (dirFile.isDirectory()) {
// Place the directory on the stack...
files.push(dirFile);
} else {
// This is a simple file, delete it...
result &= dirFile.delete();
}
}
}
} else {
// This is a simple file, delete it...
result &= file.delete();
}
}
return result;
}
public static boolean deleteFile(File fileToDelete) {
if (fileToDelete == null || !fileToDelete.exists()) {
return true;
}
boolean result = deleteChildren(fileToDelete);
result &= fileToDelete.delete();
return result;
}
public static boolean deleteChildren(File parent) {
if (parent == null || !parent.exists()) {
return false;
}
boolean result = true;
if (parent.isDirectory()) {
File[] files = parent.listFiles();
if (files == null) {
result = false;
} else {
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (file.getName().equals(".") || file.getName().equals("..")) {
continue;
}
if (file.isDirectory()) {
result &= deleteFile(file);
} else {
result &= file.delete();
}
}
}
}
return result;
}
public static void moveFile(File src, File targetDirectory) throws IOException {
if (!src.renameTo(new File(targetDirectory, src.getName()))) {
// If rename fails we must do a true deep copy instead.
Path sourcePath = src.toPath();
Path targetDirPath = targetDirectory.toPath();
try {
Files.move(sourcePath, targetDirPath.resolve(sourcePath.getFileName()), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
throw new IOException("Failed to move " + src + " to " + targetDirectory + " - " + ex.getMessage());
}
}
}
public static void moveFiles(File srcDirectory, File targetDirectory, FilenameFilter filter) throws IOException {
if (!srcDirectory.isDirectory()) {
throw new IOException("source is not a directory");
}
if (targetDirectory.exists() && !targetDirectory.isDirectory()) {
throw new IOException("target exists and is not a directory");
} else {
mkdirs(targetDirectory);
}
List<File> filesToMove = new ArrayList<File>();
getFiles(srcDirectory, filesToMove, filter);
for (File file : filesToMove) {
if (!file.isDirectory()) {
moveFile(file, targetDirectory);
}
}
}
public static void copyFile(File src, File dest) throws IOException {
copyFile(src, dest, null);
}
public static void copyFile(File src, File dest, FilenameFilter filter) throws IOException {
if (src.getCanonicalPath().equals(dest.getCanonicalPath()) == false) {
if (src.isDirectory()) {
mkdirs(dest);
List<File> list = getFiles(src, filter);
for (File f : list) {
if (f.isFile()) {
File target = new File(getCopyParent(src, dest, f), f.getName());
copySingleFile(f, target);
}
}
} else if (dest.isDirectory()) {
mkdirs(dest);
File target = new File(dest, src.getName());
copySingleFile(src, target);
} else {
copySingleFile(src, dest);
}
}
}
static File getCopyParent(File from, File to, File src) {
File result = null;
File parent = src.getParentFile();
String fromPath = from.getAbsolutePath();
if (parent.getAbsolutePath().equals(fromPath)) {
// one level down
result = to;
} else {
String parentPath = parent.getAbsolutePath();
String path = parentPath.substring(fromPath.length());
result = new File(to.getAbsolutePath() + File.separator + path);
}
return result;
}
static List<File> getFiles(File dir, FilenameFilter filter) {
List<File> result = new ArrayList<File>();
getFiles(dir, result, filter);
return result;
}
static void getFiles(File dir, List<File> list, FilenameFilter filter) {
if (!list.contains(dir)) {
list.add(dir);
String[] fileNames = dir.list(filter);
for (int i = 0; i < fileNames.length; i++) {
File f = new File(dir, fileNames[i]);
if (f.isFile()) {
list.add(f);
} else {
getFiles(dir, list, filter);
}
}
}
}
public static void copySingleFile(File src, File dest) throws IOException {
FileInputStream fileSrc = new FileInputStream(src);
FileOutputStream fileDest = new FileOutputStream(dest);
copyInputStream(fileSrc, fileDest);
}
public static void copyInputStream(InputStream in, OutputStream out) throws IOException {
try {
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int len = in.read(buffer);
while (len >= 0) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
} finally {
in.close();
out.close();
}
}
static {
MAX_DIR_NAME_LENGTH = Integer.getInteger("MaximumDirNameLength", 200);
MAX_FILE_NAME_LENGTH = Integer.getInteger("MaximumFileNameLength", 64);
}
public static int getMaxDirNameLength() {
return MAX_DIR_NAME_LENGTH;
}
public static int getMaxFileNameLength() {
return MAX_FILE_NAME_LENGTH;
}
public static void mkdirs(File dir) throws IOException {
if (dir.exists()) {
if (!dir.isDirectory()) {
throw new IOException("Failed to create directory '" + dir +
"', regular file already existed with that name");
}
} else {
if (!dir.mkdirs()) {
throw new IOException("Failed to create directory '" + dir + "'");
}
}
}
}