--- /home/tromey/gnu/Nightly/classpath/classpath/java/io/File.java 2004-11-29 02:19:39.000000000 -0700
+++ java/io/File.java 2004-09-13 02:17:02.000000000 -0600
@@ -43,6 +43,8 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
+import gnu.classpath.Configuration;
+import gnu.gcj.runtime.FileDeleter;
/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
* "The Java Language Specification", ISBN 0-201-63451-1
@@ -61,6 +63,27 @@
public class File implements Serializable, Comparable
{
private static final long serialVersionUID = 301077366599181567L;
+
+ // QUERY arguments to access function.
+ private final static int READ = 0;
+ private final static int WRITE = 1;
+ private final static int EXISTS = 2;
+
+ // QUERY arguments to stat function.
+ private final static int DIRECTORY = 0;
+ private final static int ISFILE = 1;
+ private final static int ISHIDDEN = 2;
+
+ // QUERY arguments to attr function.
+ private final static int MODIFIED = 0;
+ private final static int LENGTH = 1;
+
+ private final native long attr (int query);
+ // On OSF1 V5.0, `stat' is a macro. It is easiest to use the name
+ // `_stat' instead. We do the same thing for `_access' just in
+ // case.
+ private final native boolean _access (int query);
+ private final native boolean _stat (int query);
/**
* This is the path separator string for the current host. This field
@@ -93,12 +116,34 @@
*/
public static final char pathSeparatorChar = pathSeparator.charAt(0);
+ static final String tmpdir = System.getProperty("java.io.tmpdir");
+ static int maxPathLen;
+ static boolean caseSensitive;
+
+ static
+ {
+ if (Configuration.INIT_LOAD_LIBRARY)
+ {
+ System.loadLibrary("javaio");
+ }
+
+ init_native();
+ }
+
+ // Native function called at class initialization. This should should
+ // set the maxPathLen and caseSensitive variables.
+ private static native void init_native();
+
/**
* This is the path to the file set when the object is created. It
* may be an absolute or relative path name.
*/
private String path;
+ // We keep a counter for use by createTempFile. We choose the first
+ // value randomly to try to avoid clashes with other VMs.
+ private static long counter = Double.doubleToLongBits (Math.random());
+
/**
* This method tests whether or not the current thread is allowed to
* to read the file pointed to by this object. This will be true if and
@@ -114,11 +159,8 @@
*/
public boolean canRead()
{
- // Test for existence. This also does the SecurityManager check
- if (!exists())
- return false;
-
- return VMFile.canRead(path);
+ checkRead();
+ return _access (READ);
}
/**
@@ -137,18 +179,11 @@
*/
public boolean canWrite()
{
- // First do a SecurityCheck before doing anything else.
checkWrite();
-
- // Test for existence. This is required by the spec
- if (! VMFile.exists(path))
- return false;
-
- if (VMFile.isDirectory(path))
- return VMFile.canWriteDirectory(this);
- else
- return VMFile.canWrite(path);
+ return _access (WRITE);
}
+
+ private native boolean performCreate() throws IOException;
/**
* This method creates a new file of zero length with the same name as
@@ -170,8 +205,14 @@
public boolean createNewFile() throws IOException
{
checkWrite();
- return VMFile.create(path);
+ return performCreate();
}
+
+ /*
+ * This native method handles the actual deleting of the file
+ */
+ private native boolean performDelete();
+
/**
* This method deletes the file represented by this object. If this file
* is a directory, it must be empty in order for the delete to succeed.
@@ -188,7 +229,7 @@
if (s != null)
s.checkDelete(path);
- return VMFile.delete(path);
+ return performDelete();
}
/**
@@ -213,7 +254,7 @@
File other = (File) obj;
- if (VMFile.IS_CASE_SENSITIVE)
+ if (caseSensitive)
return path.equals(other.path);
else
return path.equalsIgnoreCase(other.path);
@@ -230,7 +271,7 @@
public boolean exists()
{
checkRead();
- return VMFile.exists(path);
+ return _access (EXISTS);
}
/**
@@ -243,7 +284,7 @@
{
path = normalizePath (name);
}
-
+
// Remove duplicate and redundant separator characters.
private String normalizePath(String p)
{
@@ -474,22 +515,7 @@
*
* @exception IOException If an error occurs
*/
- public String getCanonicalPath() throws IOException
- {
- // On Windows, getAbsolutePath might end up calling us, so we
- // have to special case that call to avoid infinite recursion.
- if (separatorChar == '\\' && path.length() == 2 &&
- ((path.charAt(0) >= 'a' && path.charAt(0) <= 'z') ||
- (path.charAt(0) >= 'A' && path.charAt(0) <= 'Z')) &&
- path.charAt(1) == ':')
- {
- return VMFile.toCanonicalForm(path);
- }
- // Call getAbsolutePath first to make sure that we do the
- // current directory handling, because the native code
- // may have a different idea of the current directory.
- return VMFile.toCanonicalForm(getAbsolutePath());
- }
+ public native String getCanonicalPath() throws IOException;
/**
* This method returns a File object representing the
@@ -516,7 +542,30 @@
*/
public String getName()
{
- return VMFile.getName(path);
+ int nameSeqIndex = 0;
+
+ if (separatorChar == '\\' && path.length() > 1)
+ {
+ // On Windows, ignore the drive specifier or the leading '\\'
+ // of a UNC network path, if any (a.k.a. the "prefix").
+ if ((path.charAt (0) == '\\' && path.charAt (1) == '\\')
+ || (((path.charAt (0) >= 'a' && path.charAt (0) <= 'z')
+ || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z'))
+ && path.charAt (1) == ':'))
+ {
+ if (path.length() > 2)
+ nameSeqIndex = 2;
+ else
+ return "";
+ }
+ }
+
+ String nameSeq
+ = (nameSeqIndex > 0 ? path.substring (nameSeqIndex) : path);
+
+ int last = nameSeq.lastIndexOf (separatorChar);
+
+ return nameSeq.substring (last + 1);
}
/**
@@ -616,7 +665,7 @@
*/
public int hashCode()
{
- if (VMFile.IS_CASE_SENSITIVE)
+ if (caseSensitive)
return path.hashCode() ^ 1234321;
else
return path.toLowerCase().hashCode() ^ 1234321;
@@ -631,18 +680,7 @@
* @return true if this object represents an absolute
* file name, false otherwise.
*/
- public boolean isAbsolute()
- {
- if (separatorChar == '\\')
- return path.startsWith(dupSeparator) ||
- (path.length() > 2 &&
- ((path.charAt(0) >= 'a' && path.charAt(0) <= 'z') ||
- (path.charAt(0) >= 'A' && path.charAt(0) <= 'Z')) &&
- path.charAt(1) == ':' &&
- path.charAt(2) == '\\');
- else
- return path.startsWith(separator);
- }
+ public native boolean isAbsolute();
/**
* This method tests whether or not the file represented by this object
@@ -657,7 +695,7 @@
public boolean isDirectory()
{
checkRead();
- return VMFile.isDirectory(path);
+ return _stat (DIRECTORY);
}
/**
@@ -673,7 +711,7 @@
public boolean isFile()
{
checkRead();
- return VMFile.isFile(path);
+ return _stat (ISFILE);
}
/**
@@ -689,7 +727,8 @@
*/
public boolean isHidden()
{
- return VMFile.isHidden(path);
+ checkRead();
+ return _stat (ISHIDDEN);
}
/**
@@ -708,7 +747,7 @@
public long lastModified()
{
checkRead();
- return VMFile.lastModified(path);
+ return attr (MODIFIED);
}
/**
@@ -722,9 +761,17 @@
public long length()
{
checkRead();
- return VMFile.length(path);
+ return attr (LENGTH);
}
+ /*
+ * This native function actually produces the list of file in this
+ * directory
+ */
+ private final native Object[] performList (FilenameFilter filter,
+ FileFilter fileFilter,
+ Class result_type);
+
/**
* This method returns a array of String's representing the
* list of files is then directory represented by this object. If this
@@ -755,37 +802,7 @@
public String[] list(FilenameFilter filter)
{
checkRead();
-
- if (!exists() || !isDirectory())
- return null;
-
- // Get the list of files
- String files[] = VMFile.list(path);
-
- // Check if an error occured in listInternal().
- if (files == null)
- return null;
-
- if (filter == null)
- return files;
-
- // Apply the filter
- int count = 0;
- for (int i = 0; i < files.length; i++)
- {
- if (filter.accept(this, files[i]))
- ++count;
- else
- files[i] = null;
- }
-
- String[] retfiles = new String[count];
- count = 0;
- for (int i = 0; i < files.length; i++)
- if (files[i] != null)
- retfiles[count++] = files[i];
-
- return retfiles;
+ return (String[]) performList (filter, null, String.class);
}
/**
@@ -808,7 +825,8 @@
*/
public String[] list()
{
- return list(null);
+ checkRead();
+ return (String[]) performList (null, null, String.class);
}
/**
@@ -831,7 +849,8 @@
*/
public File[] listFiles()
{
- return listFiles((FilenameFilter) null);
+ checkRead();
+ return (File[]) performList (null, null, File.class);
}
/**
@@ -860,17 +879,8 @@
*/
public File[] listFiles(FilenameFilter filter)
{
- String[] filelist = list(filter);
-
- if (filelist == null)
- return null;
-
- File[] fobjlist = new File [filelist.length];
-
- for (int i = 0; i < filelist.length; i++)
- fobjlist [i] = new File(this, filelist [i]);
-
- return fobjlist;
+ checkRead();
+ return (File[]) performList (filter, null, File.class);
}
/**
@@ -899,29 +909,8 @@
*/
public File[] listFiles(FileFilter filter)
{
- File[] fobjlist = listFiles((FilenameFilter) null);
-
- if (fobjlist == null)
- return null;
-
- if (filter == null)
- return fobjlist;
-
- int count = 0;
- for (int i = 0; i < fobjlist.length; i++)
- if (filter.accept(fobjlist[i]) == true)
- ++count;
-
- File[] final_list = new File[count];
- count = 0;
- for (int i = 0; i < fobjlist.length; i++)
- if (filter.accept(fobjlist[i]) == true)
- {
- final_list[count] = fobjlist[i];
- ++count;
- }
-
- return final_list;
+ checkRead();
+ return (File[]) performList (null, filter, File.class);
}
/**
@@ -943,22 +932,16 @@
String abspath = getAbsolutePath();
if (isDirectory())
- abspath = abspath + separatorChar;
-
- if (separatorChar == '\\')
- abspath = separatorChar + abspath;
+ abspath = abspath + separator;
try
{
- return new URI("file", null, null, -1,
- abspath.replace(separatorChar, '/'),
- null, null);
+ return new URI("file", "", abspath.replace(separatorChar, '/'));
}
catch (URISyntaxException use)
{
// Can't happen.
- throw (InternalError) new InternalError("Unconvertible file: "
- + this).initCause(use);
+ throw new RuntimeException(use);
}
}
@@ -984,6 +967,10 @@
+ (isDirectory() ? "/" : ""));
}
+ /*
+ * This native method actually creates the directory
+ */
+ private final native boolean performMkdir();
/**
* This method creates a directory for the path represented by this object.
@@ -996,7 +983,23 @@
public boolean mkdir()
{
checkWrite();
- return VMFile.mkdir(path);
+ return performMkdir();
+ }
+
+ private static boolean mkdirs (File x)
+ {
+ if (x.isDirectory())
+ return true;
+ String p = x.getPath();
+ String parent = x.getParent();
+ if (parent != null)
+ {
+ x.path = parent;
+ if (! mkdirs (x))
+ return false;
+ x.path = p;
+ }
+ return x.mkdir();
}
/**
@@ -1010,21 +1013,15 @@
*/
public boolean mkdirs()
{
- String parent = getParent();
- if (parent == null)
- {
- return mkdir();
- }
-
- File f = new File(parent);
- if (!f.exists())
- {
- boolean rc = f.mkdirs();
- if (rc == false)
- return false;
- }
+ checkWrite();
+ if (isDirectory())
+ return false;
+ return mkdirs (new File (path));
+ }
- return mkdir();
+ private static synchronized String nextValue()
+ {
+ return Long.toString(counter++, Character.MAX_RADIX);
}
/**
@@ -1064,15 +1061,15 @@
// Grab the system temp directory if necessary
if (directory == null)
{
- String dirname = System.getProperty("java.io.tmpdir");
+ String dirname = tmpdir;
if (dirname == null)
throw new IOException("Cannot determine system temporary directory");
directory = new File(dirname);
- if (! VMFile.exists(directory.path))
+ if (!directory.exists())
throw new IOException("System temporary directory "
+ directory.getName() + " does not exist.");
- if (! VMFile.isDirectory(directory.path))
+ if (!directory.isDirectory())
throw new IOException("System temporary directory "
+ directory.getName()
+ " is not really a directory.");
@@ -1086,44 +1083,45 @@
if (suffix == null)
suffix = ".tmp";
- // Now identify a file name and make sure it doesn't exist.
- File file;
- if (!VMFile.IS_DOS_8_3)
- {
- do
- {
- String filename = prefix + System.currentTimeMillis() + suffix;
- file = new File(directory, filename);
- }
- while (VMFile.exists(file.path));
- }
- else
+ // Truncation rules.
+ // `6' is the number of characters we generate.
+ if (prefix.length() + 6 + suffix.length() > maxPathLen)
{
- // make sure prefix is not longer than 7 characters
- if (prefix.length() >= 8)
- throw new IllegalArgumentException("Prefix too long: " + prefix + "(valid length 3..7)");
-
- long mask = 0x000000ffffFFFFL >> (prefix.length() * 4);
- do
- {
- int n = (int) (System.currentTimeMillis() & mask);
- String filename = prefix + java.lang.Integer.toHexString(n) + suffix;
- file = new File(directory, filename);
- }
- while (VMFile.exists(file.path));
+ int suf_len = 0;
+ if (suffix.charAt(0) == '.')
+ suf_len = 4;
+ suffix = suffix.substring(0, suf_len);
+ if (prefix.length() + 6 + suf_len > maxPathLen)
+ prefix = prefix.substring(0, maxPathLen - 6 - suf_len);
}
- // Verify that we are allowed to create this file
- SecurityManager sm = System.getSecurityManager();
- if (sm != null)
- sm.checkWrite(file.getAbsolutePath());
+ File f;
+
+ // How many times should we try? We choose 100.
+ for (int i = 0; i < 100; ++i)
+ {
+ // This is ugly.
+ String t = "ZZZZZZ" + nextValue();
+ String l = prefix + t.substring(t.length() - 6) + suffix;
+ try
+ {
+ f = new File(directory, l);
+ if (f.createNewFile())
+ return f;
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
- // Now create the file and return our file object
- // XXX - FIXME race condition.
- VMFile.create(file.getAbsolutePath());
- return file;
+ throw new IOException ("cannot create temporary file");
}
+ /*
+ * This native method sets the permissions to make the file read only.
+ */
+ private native boolean performSetReadOnly();
+
/**
* This method sets the file represented by this object to be read only.
* A read only file or directory cannot be modified. Please note that
@@ -1142,14 +1140,11 @@
{
// Do a security check before trying to do anything else.
checkWrite();
-
- // Test for existence.
- if (! VMFile.exists(path))
- return false;
-
- return VMFile.setReadOnly(path);
+ return performSetReadOnly();
}
+ private static native File[] performListRoots();
+
/**
* This method returns an array of filesystem roots. Some operating systems
* have volume oriented filesystem. This method provides a mechanism for
@@ -1163,7 +1158,38 @@
*/
public static File[] listRoots()
{
- return VMFile.listRoots();
+ File[] roots = performListRoots();
+
+ SecurityManager s = System.getSecurityManager();
+ if (s != null)
+ {
+ // Only return roots to which the security manager permits read access.
+ int count = roots.length;
+ for (int i = 0; i < roots.length; i++)
+ {
+ try
+ {
+ s.checkRead (roots[i].path);
+ }
+ catch (SecurityException sx)
+ {
+ roots[i] = null;
+ count--;
+ }
+ }
+ if (count != roots.length)
+ {
+ File[] newRoots = new File[count];
+ int k = 0;
+ for (int i=0; i < roots.length; i++)
+ {
+ if (roots[i] != null)
+ newRoots[k++] = roots[i];
+ }
+ roots = newRoots;
+ }
+ }
+ return roots;
}
/**
@@ -1217,7 +1243,7 @@
*/
public int compareTo(File other)
{
- if (VMFile.IS_CASE_SENSITIVE)
+ if (caseSensitive)
return path.compareTo (other.path);
else
return path.compareToIgnoreCase (other.path);
@@ -1249,6 +1275,11 @@
return compareTo((File) obj);
}
+ /*
+ * This native method actually performs the rename.
+ */
+ private native boolean performRenameTo (File dest);
+
/**
* This method renames the file represented by this object to the path
* of the file represented by the argument File.
@@ -1263,12 +1294,22 @@
*/
public synchronized boolean renameTo(File dest)
{
- checkWrite();
- dest.checkWrite();
- // Call our native rename method
- return VMFile.renameTo(path, dest.path);
+ SecurityManager s = System.getSecurityManager();
+ String sname = getName();
+ String dname = dest.getName();
+ if (s != null)
+ {
+ s.checkWrite (sname);
+ s.checkWrite (dname);
+ }
+ return performRenameTo (dest);
}
+ /*
+ * This method does the actual setting of the modification time.
+ */
+ private native boolean performSetLastModified(long time);
+
/**
* This method sets the modification time on the file to the specified
* value. This is specified as the number of seconds since midnight
@@ -1291,7 +1332,7 @@
throw new IllegalArgumentException("Negative modification time: " + time);
checkWrite();
- return VMFile.setLastModified(path, time);
+ return performSetLastModified(time);
}
private void checkWrite()
@@ -1322,14 +1363,15 @@
*
* @since 1.2
*/
+ // FIXME: This should use the ShutdownHook API once we implement that.
public void deleteOnExit()
{
// Check the SecurityManager
SecurityManager sm = System.getSecurityManager();
if (sm != null)
- sm.checkDelete(path);
+ sm.checkDelete (getName());
- DeleteFileHelper.add(this);
+ FileDeleter.add (this);
}
private void writeObject(ObjectOutputStream oos) throws IOException