[Arakhnę-Dev] [265] * Bug fix: recursive deletion of directories. |
[ Thread Index |
Date Index
| More arakhne.org/dev Archives
]
Revision: 265
Author: galland
Date: 2011-08-21 23:16:53 +0200 (Sun, 21 Aug 2011)
Log Message:
-----------
* Bug fix: recursive deletion of directories.
Modified Paths:
--------------
trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/FileSystem.java
Modified: trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/FileSystem.java
===================================================================
--- trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/FileSystem.java 2011-08-21 14:45:08 UTC (rev 264)
+++ trunk/arakhneVmutils/java/src/main/java/org/arakhne/vmutil/FileSystem.java 2011-08-21 21:16:53 UTC (rev 265)
@@ -41,6 +41,7 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
@@ -59,10 +60,10 @@
static {
URLHandlerUtil.installArakhneHandlers();
-
+
String validChars = "[^\\\\/:*?\"<>|]"; //$NON-NLS-1$
String bslashChar = "\\\\"; //$NON-NLS-1$
-
+
StringBuffer pattern = new StringBuffer();
pattern.append("^"); //$NON-NLS-1$
pattern.append("(([a-zA-Z]:"); //$NON-NLS-1$
@@ -82,15 +83,15 @@
//"^([A-Za-z]:)?([^\\\\/:*?\"<>|]*\\\\)*[^\\\\/:*?\"<>|]*$"; //$NON-NLS-1$
WINDOW_NATIVE_FILENAME_PATTERN = pattern.toString();
}
-
+
/** Regular expression pattern which corresponds to Windows native filename.
*/
private static final String WINDOW_NATIVE_FILENAME_PATTERN;
-
+
/** Character used to specify a file extension.
*/
public static final char EXTENSION_SEPARATOR_CHAR = '.';
-
+
/** String which is representing the current directory in a relative path.
*/
public static final String CURRENT_DIRECTORY = "."; //$NON-NLS-1$
@@ -110,13 +111,15 @@
/** String used to specify a file extension.
*/
public static final String EXTENSION_SEPARATOR = "."; //$NON-NLS-1$
-
+
/** Prefix used to join in a Jar URL the jar filename and the inside-jar filename.
*/
public static final String JAR_URL_FILE_ROOT = "!/"; //$NON-NLS-1$
+
+ private static final Random RANDOM = new Random();
private static final DeleteOnExitHook deleteOnExitHook = new DeleteOnExitHook();
-
+
/** Decode the given string.
*
* @param s
@@ -136,7 +139,7 @@
public static boolean isJarURL(URL url) {
return URISchemeType.JAR.isURL(url);
}
-
+
/** Replies the jar part of the jar-scheme URL.
*
* @param url
@@ -238,7 +241,7 @@
}
return new URL(URISchemeType.JAR.name(), "", buf.toString()); //$NON-NLS-1$
}
-
+
/** Replies if the current operating system uses case-sensitive filename.
*
* @return <code>true</code> if the filenames on the current file system are case sensitive,
@@ -262,7 +265,7 @@
return false;
}
}
-
+
/** Replies the character used to separate the basename and the file extension.
*
* @return the character used to separate the basename and the file extension.
@@ -306,7 +309,7 @@
*/
public static URL dirname(URL filename) {
if (filename==null) return null;
-
+
URL prefix = null;
String path;
if (isJarURL(filename)) {
@@ -315,9 +318,9 @@
}
else
path = filename.getPath();
-
+
if ("".equals(path)) return null; //$NON-NLS-1$
-
+
int idx = path.lastIndexOf(URL_PATH_SEPARATOR_CHAR);
if (idx==path.length()-1)
idx = path.lastIndexOf(URL_PATH_SEPARATOR_CHAR, path.length()-2);
@@ -331,7 +334,7 @@
else {
path = path.substring(0, idx+1);
}
-
+
try {
if (prefix!=null) {
return toJarURL(prefix, path);
@@ -362,7 +365,7 @@
}
return null;
}
-
+
/** Replies the basename of the specified file with the extension.
* <p>
* Caution: This function does not support URL format.
@@ -532,7 +535,7 @@
}
else
basename = filename.substring(idx+1, end+1);
-
+
idx = basename.indexOf(getFileExtensionCharacter());
if (idx<0) return basename;
return basename.substring(0,idx);
@@ -576,7 +579,7 @@
}
else
basename = largeBasename.substring(idx+1, end+1);
-
+
idx = basename.indexOf(getFileExtensionCharacter());
if (idx<0) return basename;
return basename.substring(0,idx);
@@ -688,8 +691,8 @@
if (!empty) {
assert(elt!=null);
if (!elt.startsWith(File.separator)
- && buf.length()>=0
- && buf.charAt(buf.length()-1)!=File.separatorChar) {
+ && buf.length()>=0
+ && buf.charAt(buf.length()-1)!=File.separatorChar) {
buf.append(File.separatorChar);
}
buf.append(elt);
@@ -733,8 +736,8 @@
if (!empty) {
assert(elt!=null);
if (!elt.startsWith(File.separator)
- && (buf.length()==0
- || buf.charAt(buf.length()-1)!=URL_PATH_SEPARATOR_CHAR)) {
+ && (buf.length()==0
+ || buf.charAt(buf.length()-1)!=URL_PATH_SEPARATOR_CHAR)) {
buf.append(URL_PATH_SEPARATOR_CHAR);
}
buf.append(elt);
@@ -1064,7 +1067,7 @@
candidates.add(file);
File f;
File[] children;
- while (candidates.isEmpty()) {
+ while (!candidates.isEmpty()) {
f = candidates.getFirst();
if (f.isDirectory()) {
children = f.listFiles();
@@ -1088,7 +1091,7 @@
}
}
}
-
+
/** Delete the given directory and all its subdirectories when the JVM is exiting.
* If the given <var>file</var> is a directory, its
* content and the <var>file</var> itself are recursivelly removed.
@@ -1178,7 +1181,7 @@
if (outChannel!=null) outChannel.close();
}
}
-
+
/** Copy the first file into the second file.
* <p>
* The content of the second file will be lost.
@@ -1299,7 +1302,7 @@
}
return null;
}
-
+
/** Replies the user configuration directory for the specified software.
* <p>
* On Unix operating systems, the user directory for a
@@ -1350,7 +1353,7 @@
}
return null;
}
-
+
/** Replies the user configuration directory for the specified software.
* <p>
* On Unix operating systems, the system directory for a
@@ -1430,7 +1433,7 @@
public static File convertUrlToFile(URL url) {
return convertURLToFile(url);
}
-
+
/** Convert an URL which represents a local file into a File.
*
* @param url is the URL to convert.
@@ -1489,7 +1492,7 @@
}
throw new IllegalArgumentException("not a file URL: "+url); //$NON-NLS-1$
}
-
+
/** Convert a string to an URL according to several rules.
* <p>
* The rules are (the first succeeded is replied):
@@ -1579,7 +1582,7 @@
public static URL convertStringToUrl(String urlDescription, boolean allowResourceSearch, boolean repliesFileURL) {
return convertStringToURL(urlDescription, allowResourceSearch, repliesFileURL, true);
}
-
+
/** Convert a string to an URL according to several rules.
* <p>
* The rules are (the first succeeded is replied):
@@ -1670,16 +1673,16 @@
// ignore error
}
}
-
+
if (url==null) {
if (allowResourceSearch) {
url = Resources.getResource(urlDescription);
}
-
+
if (url==null && URISchemeType.RESOURCE.isScheme(urlDescription)) {
return null;
}
-
+
if (url==null && repliesFileURL) {
String urlPart = URISchemeType.removeAnyScheme(urlDescription);
// Try to parse a malformed JAR url:
@@ -1698,7 +1701,7 @@
}
}
}
-
+
// Standard local file
if (url==null) {
try {
@@ -1712,7 +1715,7 @@
}
}
}
-
+
return url;
}
@@ -1773,7 +1776,7 @@
}
return filename;
}
-
+
/** Replies if the given URL is using a protocol which could be map to files.
*
* @param url
@@ -1788,7 +1791,7 @@
}
return false;
}
-
+
/** Replies if the given URL scheme is using a protocol which could be map to files.
*
* @param scheme
@@ -2004,15 +2007,15 @@
}
break;
case FILE:
- {
- File f = new File(filename.getFile());
- if (!f.isAbsolute()) {
- if (current!=null) {
- return join(current, f);
- }
+ {
+ File f = new File(filename.getFile());
+ if (!f.isAbsolute()) {
+ if (current!=null) {
+ return join(current, f);
}
}
- break;
+ }
+ break;
default:
// do not change the URL
}
@@ -2111,27 +2114,27 @@
switch(URISchemeType.getSchemeType(url)) {
case JAR:
- {
- int index = path.indexOf(JAR_URL_FILE_ROOT);
- assert(index>0);
- prefix = path.substring(0,index+1);
- path = path.substring(index+1);
- parentStr = URL_PATH_SEPARATOR;
- }
- break;
+ {
+ int index = path.indexOf(JAR_URL_FILE_ROOT);
+ assert(index>0);
+ prefix = path.substring(0,index+1);
+ path = path.substring(index+1);
+ parentStr = URL_PATH_SEPARATOR;
+ }
+ break;
case FILE:
- {
- prefix = null;
- parentStr = ".."+URL_PATH_SEPARATOR; //$NON-NLS-1$
- }
- break;
+ {
+ prefix = null;
+ parentStr = ".."+URL_PATH_SEPARATOR; //$NON-NLS-1$
+ }
+ break;
default:
- {
- prefix = null;
- parentStr = URL_PATH_SEPARATOR;
- }
+ {
+ prefix = null;
+ parentStr = URL_PATH_SEPARATOR;
}
-
+ }
+
if (path==null || "".equals(path)) path = parentStr; //$NON-NLS-1$
int index = path.lastIndexOf(URL_PATH_SEPARATOR_CHAR);
if (index==-1) path = parentStr;
@@ -2141,12 +2144,12 @@
else path = path.substring(0, index+1);
}
else path = path.substring(0, index+1);
-
+
if (prefix!=null) path = prefix + path;
-
+
return new URL(url.getProtocol(), url.getHost(), url.getPort(), path);
}
-
+
/** Test if the given filename is a local filename and extract
* the path component.
*
@@ -2164,7 +2167,7 @@
fn = filename;
return fn;
}
-
+
/** Replies if the given string contains a Windows® native long filename.
* <p>
* Long filenames (LFN), spelled "long file names" by Microsoft Corporation,
@@ -2195,7 +2198,7 @@
Matcher matcher = pattern.matcher(fn);
return matcher.matches();
}
-
+
/** Normalize the given string contains a Windows® native long filename
* and replies a Java-standard version.
* <p>
@@ -2230,7 +2233,7 @@
}
return null;
}
-
+
/** Replies an URL for the given file and translate it into a
* resource URL if the given file is inside the classpath.
*
@@ -2253,7 +2256,7 @@
return null;
}
}
-
+
/** Replies an URL for the given url and translate it into a
* resource URL if the given file is inside the classpath.
*
@@ -2268,7 +2271,7 @@
String sp;
Iterator<URL> classpath = ClasspathUtil.getClasspath();
URL path;
-
+
while (classpath.hasNext()) {
path = classpath.next();
sp = path.toExternalForm().replaceAll("/$", ""); //$NON-NLS-1$//$NON-NLS-2$
@@ -2283,7 +2286,7 @@
}
}
}
-
+
return url;
}
@@ -2298,21 +2301,21 @@
public static File makeRelative(File filenameToMakeRelative, File rootPath) throws IOException {
if (filenameToMakeRelative==null || rootPath==null)
throw new IllegalArgumentException();
-
+
if (!filenameToMakeRelative.isAbsolute()) return filenameToMakeRelative;
if (!rootPath.isAbsolute()) return filenameToMakeRelative;
File root = rootPath.getCanonicalFile();
File dir = filenameToMakeRelative.getParentFile().getCanonicalFile();
-
+
String[] parts1 = split(dir);
String[] parts2 = split(root);
-
+
String relPath = makeRelative(parts1, parts2, filenameToMakeRelative.getName());
-
+
return new File(CURRENT_DIRECTORY, relPath);
}
-
+
/**
* Make the given filename relative to the given root path.
*
@@ -2325,16 +2328,16 @@
public static File makeRelative(File filenameToMakeRelative, URL rootPath) throws IOException {
if (filenameToMakeRelative==null || rootPath==null)
throw new IllegalArgumentException();
-
+
if (!filenameToMakeRelative.isAbsolute()) return filenameToMakeRelative;
File dir = filenameToMakeRelative.getParentFile().getCanonicalFile();
-
+
String[] parts1 = split(dir);
String[] parts2 = split(rootPath);
-
+
String relPath = makeRelative(parts1, parts2, filenameToMakeRelative.getName());
-
+
return new File(CURRENT_DIRECTORY, relPath);
}
@@ -2350,27 +2353,27 @@
public static File makeRelative(URL filenameToMakeRelative, URL rootPath) throws IOException {
if (filenameToMakeRelative==null || rootPath==null)
throw new IllegalArgumentException();
-
+
String basename = largeBasename(filenameToMakeRelative);
URL dir = dirname(filenameToMakeRelative);
-
+
String[] parts1 = split(dir);
String[] parts2 = split(rootPath);
-
+
String relPath = makeRelative(parts1, parts2, basename);
-
+
return new File(CURRENT_DIRECTORY, relPath);
}
private static String makeRelative(String[] parts1, String[] parts2, String basename) {
int firstDiff = -1;
-
+
for(int i=0; firstDiff<0 && i<parts1.length && i<parts2.length; i++) {
if (!parts1[i].equals(parts2[i])) {
firstDiff = i;
}
}
-
+
StringBuffer result = new StringBuffer();
if (firstDiff<0) {
firstDiff = Math.min(parts1.length, parts2.length);
@@ -2388,15 +2391,15 @@
if (result.length()>0) result.append(File.separator);
result.append(basename);
-
+
return result.toString();
}
-
+
/**
- * <p>
- * A canonical pathname is both absolute and unique. This method maps
- * the pathname to its unique form. This typically involves removing redundant names
- * such as <tt>"."</tt> and <tt>".."</tt> from the pathname.
+ * <p>
+ * A canonical pathname is both absolute and unique. This method maps
+ * the pathname to its unique form. This typically involves removing redundant names
+ * such as <tt>"."</tt> and <tt>".."</tt> from the pathname.
*
* @param url is the URL to make canonical
* @return the canonical form of the given URL.
@@ -2405,7 +2408,7 @@
public static URL makeCanonicalURL(URL url) {
if (url!=null) {
String[] pathComponents = url.getPath().split(Pattern.quote(URL_PATH_SEPARATOR));
-
+
List<String> canonicalPath = new LinkedList<String>();
for(String component : pathComponents) {
if (!CURRENT_DIRECTORY.equals(component)) {
@@ -2422,7 +2425,7 @@
}
}
}
-
+
StringBuffer newPathBuffer = new StringBuffer();
boolean isFirst = true;
for(String component : canonicalPath) {
@@ -2434,7 +2437,7 @@
}
newPathBuffer.append(component);
}
-
+
try {
URI uri = new URI(
url.getProtocol(),
@@ -2480,18 +2483,18 @@
ZipOutputStream zos = null;
try {
zos = new ZipOutputStream(output);
-
+
if (input==null) return;
LinkedList<File> candidates = new LinkedList<File>();
candidates.add(input);
-
+
byte[] buffer = new byte[2048];
int len;
File file;
-
+
File rootDirectory = (input.isDirectory()) ? input : input.getParentFile();
-
+
while (!candidates.isEmpty()) {
file = candidates.removeFirst();
assert(file!=null);
@@ -2521,7 +2524,7 @@
if (zos!=null) zos.close();
}
}
-
+
/**
* Unzip the given stream and write out the file in the output.
* If the input file is a directory, the content of the directory is zipped.
@@ -2539,7 +2542,7 @@
ZipInputStream zis = null;
try {
zis = new ZipInputStream(input);
-
+
}
finally {
if (zis!=null) zis.close();
@@ -2570,7 +2573,126 @@
unzipFile(new FileInputStream(input), output);
}
- /** Hook to recursively delete files on JVM exit.
+ /** Create an empty directory in the default temporary-file directory, using
+ * the given prefix and suffix to generate its name. Invoking this method
+ * is equivalent to invoking <code>{@link #createTempDirectory(java.lang.String,
+ * java.lang.String, java.io.File)
+ * createTempDirectory(prefix, suffix, null)}</code>.
+ *
+ * @param prefix is the prefix string to be used in generating the file's
+ * name; must be at least three characters long
+ *
+ * @param suffix is the suffix string to be used in generating the file's
+ * name; may be <code>null</code>, in which case the
+ * suffix <code>".tmp"</code> will be used
+ * @return An abstract pathname denoting a newly-created empty file
+ * @throws IllegalArgumentException
+ * If the <code>prefix</code> argument contains fewer than three
+ * characters
+ * @throws IOException If a file could not be created
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method does not allow a file to be created
+ * @since 6.2
+ */
+ public static File createTempDirectory(String prefix, String suffix) throws IOException {
+ return createTempDirectory(prefix, suffix, null);
+ }
+
+ /** Creates a new empty directory in the specified directory, using the
+ * given prefix and suffix strings to generate its name. If this method
+ * returns successfully then it is guaranteed that:
+ * <ol>
+ * <li> The directory denoted by the returned abstract pathname did not exist
+ * before this method was invoked, and
+ * <li> Neither this method nor any of its variants will return the same
+ * abstract pathname again in the current invocation of the virtual
+ * machine.
+ * </ol>
+ * <p>
+ * This method provides only part of a temporary-file facility. To arrange
+ * for a file created by this method to be deleted automatically, use the
+ * <code>{@link #deleteOnExit}</code> method.
+ *
+ * <p> The <code>prefix</code> argument must be at least three characters
+ * long. It is recommended that the prefix be a short, meaningful string
+ * such as <code>"hjb"</code> or <code>"mail"</code>. The
+ * <code>suffix</code> argument may be <code>null</code>, in which case the
+ * suffix <code>".tmp"</code> will be used.
+ *
+ * <p> To create the new directory, the prefix and the suffix may first be
+ * adjusted to fit the limitations of the underlying platform. If the
+ * prefix is too long then it will be truncated, but its first three
+ * characters will always be preserved. If the suffix is too long then it
+ * too will be truncated, but if it begins with a period character
+ * (<code>'.'</code>) then the period and the first three characters
+ * following it will always be preserved. Once these adjustments have been
+ * made the name of the new file will be generated by concatenating the
+ * prefix, five or more internally-generated characters, and the suffix.
+ *
+ * <p> If the <code>directory</code> argument is <code>null</code> then the
+ * system-dependent default temporary-file directory will be used. The
+ * default temporary-file directory is specified by the system property
+ * <code>java.io.tmpdir</code>. On UNIX systems the default value of this
+ * property is typically <code>"/tmp"</code> or <code>"/var/tmp"</code>; on
+ * Microsoft Windows systems it is typically <code>"C:\\WINNT\\TEMP"</code>. A different
+ * value may be given to this system property when the Java virtual machine
+ * is invoked, but programmatic changes to this property are not guaranteed
+ * to have any effect upon the temporary directory used by this method.
+ *
+ * @param prefix is the prefix string to be used in generating the file's
+ * name; must be at least three characters long
+ *
+ * @param suffix is the suffix string to be used in generating the file's
+ * name; may be <code>null</code>, in which case the
+ * suffix <code>".tmp"</code> will be used
+ * @param directory is the directory in which the file is to be created, or
+ * <code>null</code> if the default temporary-file
+ * directory is to be used
+ * @return An abstract pathname denoting a newly-created empty file
+ * @throws IllegalArgumentException
+ * If the <code>prefix</code> argument contains fewer than three
+ * characters
+ * @throws IOException If a file could not be created
+ * @throws SecurityException
+ * If a security manager exists and its <code>{@link
+ * java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
+ * method does not allow a file to be created
+ * @since 6.2
+ */
+ public static File createTempDirectory(String prefix, String suffix, File directory) throws IOException {
+ if (prefix == null) throw new NullPointerException();
+ if (prefix.length() < 3)
+ throw new IllegalArgumentException("Prefix string too short"); //$NON-NLS-1$
+ String s = (suffix == null) ? ".tmp" : suffix; //$NON-NLS-1$
+ File targetDirectory;
+ if (directory == null) {
+ targetDirectory = new File(System.getProperty("java.io.tmpdir")); //$NON-NLS-1$
+ }
+ else {
+ targetDirectory = directory;
+ }
+ File f;
+ do {
+ long n = RANDOM.nextLong();
+ if (n == Long.MIN_VALUE) {
+ n = 0; // corner case
+ }
+ else {
+ n = Math.abs(n);
+ }
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(prefix);
+ buffer.append(Long.toString(n));
+ buffer.append(s);
+ f = new File(targetDirectory, buffer.toString());
+ }
+ while (!f.mkdirs());
+ return f;
+ }
+
+ /** Hook to recursively delete files on JVM exit.
*
* @author $Author: galland$
* @version $FullVersion$
@@ -2585,7 +2707,7 @@
public DeleteOnExitHook() {
setName("DeleteOnExitHook"); //$NON-NLS-1$
}
-
+
/**
* {@inheritDoc}
*/
@@ -2606,7 +2728,7 @@
}
}
}
-
+
/** Add a file to delete.
*
* @param file
@@ -2621,7 +2743,7 @@
this.filesToDelete.add(file);
}
}
-
+
/** Remove a file to delete.
*
* @param file
@@ -2637,8 +2759,8 @@
}
}
}
-
+
}
-
+
}