1 /* File.java -- Class representing a file on disk
2 Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
43 import gnu.gcj.runtime.FileDeleter;
46 * @author Tom Tromey <tromey@cygnus.com>
47 * @date September 24, 1998
50 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
51 * "The Java Language Specification", ISBN 0-201-63451-1
52 * Status: Complete to version 1.3.
55 public class File implements Serializable, Comparable
57 public boolean canRead ()
60 return _access (READ);
63 public boolean canWrite ()
66 return _access (WRITE);
69 private native boolean performCreate() throws IOException;
72 public boolean createNewFile() throws IOException
75 return performCreate();
78 private native boolean performDelete ();
79 public boolean delete ()
81 SecurityManager s = System.getSecurityManager();
85 return performDelete ();
88 public boolean equals (Object obj)
90 if (! (obj instanceof File))
92 File other = (File) obj;
94 return (path.equals(other.path));
96 return (path.equalsIgnoreCase(other.path));
99 public boolean exists ()
102 return _access (EXISTS);
105 public File (String p)
107 path = normalizePath(p);
110 // Remove duplicate and redundant separator characters.
111 private String normalizePath(String p)
113 // On Windows, convert any '/' to '\'. This appears to be the same logic
114 // that Sun's Win32 Java performs.
115 if (separatorChar == '\\')
116 p = p.replace ('/', '\\');
118 int dupIndex = p.indexOf(dupSeparator);
119 int plen = p.length();
121 // Special case: permit Windows UNC path prefix.
122 if (dupSeparator.equals("\\\\") && dupIndex == 0)
123 dupIndex = p.indexOf(dupSeparator, 1);
127 // Ignore trailing separator (though on Windows "a:\", for
128 // example, is a valid and minimal path).
129 if (plen > 1 && p.charAt (plen - 1) == separatorChar)
131 if (! (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':'))
132 return p.substring (0, plen - 1);
138 StringBuffer newpath = new StringBuffer(plen);
140 while (dupIndex != -1)
142 newpath.append(p.substring(last, dupIndex));
143 // Ignore the duplicate path characters.
144 while (p.charAt(dupIndex) == separatorChar)
147 if (dupIndex == plen)
148 return newpath.toString();
150 newpath.append(separatorChar);
152 dupIndex = p.indexOf(dupSeparator, last);
155 // Again, ignore possible trailing separator (except special cases
156 // like "a:\" on Windows).
158 if (plen > 1 && p.charAt (plen - 1) == separatorChar)
160 if (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':')
167 newpath.append(p.substring(last, end));
169 return newpath.toString();
172 public File (String dirPath, String name)
175 throw new NullPointerException ();
176 if (dirPath != null && dirPath.length() > 0)
178 // Try to be smart about the number of separator characters.
179 if (dirPath.charAt(dirPath.length() - 1) == separatorChar
180 || name.length() == 0)
181 path = normalizePath(dirPath + name);
183 path = normalizePath(dirPath + separatorChar + name);
186 path = normalizePath(name);
189 public File (File dir, String name)
191 this (dir == null ? null : dir.path, name);
194 public String getAbsolutePath ()
198 else if (separatorChar == '\\'
199 && path.length () > 0 && path.charAt (0) == '\\')
201 // On Windows, even if the path starts with a '\\' it is not
202 // really absolute until we prefix the drive specifier from
203 // the current working directory to it.
204 return System.getProperty ("user.dir").substring (0, 2) + path;
207 return System.getProperty ("user.dir") + separatorChar + path;
211 public File getAbsoluteFile ()
213 return new File (getAbsolutePath());
216 public native String getCanonicalPath () throws IOException;
219 public File getCanonicalFile () throws IOException
221 return new File (getCanonicalPath());
224 public String getName ()
226 int last = path.lastIndexOf(separatorChar);
227 return path.substring(last + 1);
230 public String getParent ()
232 int last = path.lastIndexOf(separatorChar);
235 // FIXME: POSIX assumption.
236 if (last == 0 && path.charAt (0) == '/')
238 return path.substring(0, last);
242 public File getParentFile ()
244 String parent = getParent ();
245 return (parent == null ? null : new File (parent));
248 public String getPath ()
253 public int hashCode ()
256 return (path.hashCode() ^ 1234321);
258 return (path.toLowerCase().hashCode() ^ 1234321);
261 public native boolean isAbsolute ();
263 public boolean isDirectory ()
266 return _stat (DIRECTORY);
269 public boolean isFile ()
272 return _stat (ISFILE);
276 public boolean isHidden()
279 return _stat (ISHIDDEN);
282 public long lastModified ()
285 return attr (MODIFIED);
288 public long length ()
291 return attr (LENGTH);
294 private final native Object[] performList (FilenameFilter filter,
295 FileFilter fileFilter,
298 public String[] list (FilenameFilter filter)
301 return (String[]) performList (filter, null, String.class);
304 public String[] list ()
307 return (String[]) performList (null, null, String.class);
311 public File[] listFiles()
314 return (File[]) performList (null, null, File.class);
318 public File[] listFiles(FilenameFilter filter)
321 return (File[]) performList (filter, null, File.class);
325 public File[] listFiles(FileFilter filter)
328 return (File[]) performList (null, filter, File.class);
331 public String toString ()
336 public URL toURL () throws MalformedURLException
338 // On Win32, Sun's JDK returns URLs of the form "file:/c:/foo/bar.txt",
339 // while on UNIX, it returns URLs of the form "file:/foo/bar.txt".
340 if (separatorChar == '\\')
341 return new URL ("file:/" + getAbsolutePath ().replace ('\\', '/')
342 + (isDirectory() ? "/" : ""));
344 return new URL ("file:" + getAbsolutePath ()
345 + (isDirectory() ? "/" : ""));
348 private final native boolean performMkdir ();
350 public boolean mkdir ()
353 return performMkdir ();
356 private static boolean mkdirs (File x)
360 String p = x.getPath();
361 String parent = x.getParent();
372 public boolean mkdirs ()
377 return mkdirs (new File (path));
380 private static synchronized String nextValue ()
382 return Long.toString(counter++, Character.MAX_RADIX);
386 public static File createTempFile (String prefix, String suffix,
390 // Grab the system temp directory if necessary
391 if (directory == null)
393 String dirname = tmpdir;
396 new IOException("Cannot determine system temporary directory");
398 directory = new File(dirname);
399 if (!directory.exists())
400 throw new IOException("System temporary directory "
401 + directory.getName() + " does not exist.");
402 if (!directory.isDirectory())
403 throw new IOException("System temporary directory "
404 + directory.getName()
405 + " is not really a directory.");
408 if (prefix.length () < 3)
409 throw new IllegalArgumentException ("Prefix too short: " + prefix);
414 // `6' is the number of characters we generate.
415 if (prefix.length () + 6 + suffix.length () > maxPathLen)
418 if (suffix.charAt(0) == '.')
420 suffix = suffix.substring(0, suf_len);
421 if (prefix.length () + 6 + suf_len > maxPathLen)
422 prefix = prefix.substring(0, maxPathLen - 6 - suf_len);
427 // How many times should we try? We choose 100.
428 for (int i = 0; i < 100; ++i)
431 String t = "ZZZZZZ" + nextValue ();
432 String l = prefix + t.substring(t.length() - 6) + suffix;
435 f = new File(directory, l);
436 if (f.createNewFile())
439 catch (IOException ignored)
444 throw new IOException ("cannot create temporary file");
447 private native boolean performSetReadOnly();
450 public boolean setReadOnly()
453 return performSetReadOnly();
456 private static native File[] performListRoots();
459 public static File[] listRoots()
461 File[] roots = performListRoots();
463 SecurityManager s = System.getSecurityManager();
466 // Only return roots to which the security manager permits read access.
467 int count = roots.length;
468 for (int i = 0; i < roots.length; i++)
472 s.checkRead(roots[i].path);
474 catch (SecurityException sx)
480 if (count != roots.length)
482 File[] newRoots = new File[count];
484 for (int i=0; i < roots.length; i++)
486 if (roots[i] != null)
487 newRoots[k++] = roots[i];
495 public static File createTempFile (String prefix, String suffix)
498 return createTempFile (prefix, suffix, null);
502 public int compareTo(File other)
505 return path.compareTo (other.path);
507 return path.compareToIgnoreCase (other.path);
511 public int compareTo(Object o)
513 File other = (File) o;
514 return compareTo (other);
517 private native boolean performRenameTo (File dest);
518 public boolean renameTo (File dest)
520 SecurityManager s = System.getSecurityManager();
521 String sname = getName();
522 String dname = dest.getName();
528 return performRenameTo (dest);
531 private native boolean performSetLastModified(long time);
534 public boolean setLastModified(long time)
537 return performSetLastModified(time);
540 public static final String pathSeparator
541 = System.getProperty("path.separator");
542 public static final char pathSeparatorChar = pathSeparator.charAt(0);
543 public static final String separator = System.getProperty("file.separator");
544 public static final char separatorChar = separator.charAt(0);
546 static final String tmpdir = System.getProperty("java.io.tmpdir");
547 static int maxPathLen;
548 static boolean caseSensitive;
549 static String dupSeparator = separator + separator;
556 // Native function called at class initialization. This should should
557 // set the maxPathLen and caseSensitive variables.
558 private static native void init_native();
563 // We keep a counter for use by createTempFile. We choose the first
564 // value randomly to try to avoid clashes with other VMs.
565 private static long counter = Double.doubleToLongBits (Math.random ());
567 private void checkWrite ()
569 SecurityManager s = System.getSecurityManager();
574 private void checkRead ()
576 SecurityManager s = System.getSecurityManager();
582 * Add this File to the set of files to be deleted upon normal
587 // FIXME: This should use the ShutdownHook API once we implement that.
588 public void deleteOnExit ()
590 SecurityManager sm = System.getSecurityManager ();
592 sm.checkDelete (getName ());
594 FileDeleter.add (this);
597 private void writeObject (ObjectOutputStream oos) throws IOException
599 oos.defaultWriteObject ();
600 oos.writeChar (separatorChar);
603 private void readObject (ObjectInputStream ois)
604 throws ClassNotFoundException, IOException
606 ois.defaultReadObject ();
608 // If the file was from an OS with a different dir separator,
609 // fixup the path to use the separator on this OS.
610 char oldSeparatorChar = ois.readChar ();
611 if (oldSeparatorChar != separatorChar)
612 path = path.replace (oldSeparatorChar, separatorChar);
615 // QUERY arguments to access function.
616 private final static int READ = 0;
617 private final static int WRITE = 1;
618 private final static int EXISTS = 2;
620 // QUERY arguments to stat function.
621 private final static int DIRECTORY = 0;
622 private final static int ISFILE = 1;
623 private final static int ISHIDDEN = 2;
625 // QUERY arguments to attr function.
626 private final static int MODIFIED = 0;
627 private final static int LENGTH = 1;
629 private final native long attr (int query);
630 // On OSF1 V5.0, `stat' is a macro. It is easiest to use the name
631 // `_stat' instead. We do the same thing for `_access' just in
633 private final native boolean _access (int query);
634 private final native boolean _stat (int query);
636 private static final long serialVersionUID = 301077366599181567L;