/**
* 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.fusesource.hawtjournal.util;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
*/
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() {
}
/**
* 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
*/
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
*/
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 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()))) {
throw new IOException("Failed to move " + src + " to " + targetDirectory);
}
}
public static void copyFile(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 {
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int len = in.read(buffer);
while (len >= 0) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
in.close();
out.close();
}
static {
MAX_DIR_NAME_LENGTH = Integer.valueOf(System.getProperty("MaximumDirNameLength", "200")).intValue();
MAX_FILE_NAME_LENGTH = Integer.valueOf(System.getProperty("MaximumFileNameLength", "64")).intValue();
}
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 + "'");
}
}
}
public interface IOStrategy {
void sync(FileDescriptor fdo) throws IOException;
}
static final IOStrategy IO_STRATEGY = createIOStrategy();
private static IOStrategy createIOStrategy() {
// On OS X, the fsync system call does not fully flush the hardware buffers..
// to do that you have to do an fcntl call, and the only way to do that is to
// do some JNI.
String os = System.getProperty("os.name");
// if( "Mac OS X".equals(os) ) {
//
// // We will gracefully fall back to default JDK file sync behavior
// // if the JNA library is not in the path, and we can't set the
// // FileDescriptor.fd field accessible.
// try {
// final Field field = FileDescriptor.class.getDeclaredField("fd");
// field.setAccessible(true);
// // Try to dynamically load the JNA impl of the CLibrary interface..
// final CLibrary lib = getCLibrary();
// return new IOStrategy() {
// static final int F_FULLFSYNC = 51;
// public void sync(FileDescriptor fd) throws IOException {
// try {
// int id = field.getInt(fd);
// lib.fcntl(id, F_FULLFSYNC);
// } catch (Exception e) {
// throw IOExceptionSupport.create(e);
// }
// }
// };
// } catch (Throwable ignore) {
// // Perhaps we should issue a warning here so folks know that
// // the disk syncs are not going to be of very good quality.
// }
// }
return new IOStrategy() {
public void sync(FileDescriptor fd) throws IOException {
fd.sync();
}
};
}
static public void sync(FileDescriptor fd) throws IOException {
IO_STRATEGY.sync(fd);
}
}