OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / io / File.java
1 /* File.java -- Class representing a file on disk
2    Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Classpath.
6
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11  
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38
39
40 package java.io;
41
42 import gnu.classpath.SystemProperties;
43
44 import java.net.MalformedURLException;
45 import java.net.URI;
46 import java.net.URISyntaxException;
47 import java.net.URL;
48
49 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
50  * "The Java Language Specification", ISBN 0-201-63451-1
51  * Status:  Complete to version 1.3.
52  */
53
54 /**
55  * This class represents a file or directory on a local disk.  It provides
56  * facilities for dealing with a variety of systems that use various
57  * types of path separators ("/" versus "\", for example).  It also
58  * contains method useful for creating and deleting files and directories.
59  *
60  * @author Aaron M. Renn (arenn@urbanophile.com)
61  * @author Tom Tromey (tromey@cygnus.com)
62  */
63 public class File implements Serializable, Comparable<File>
64 {
65   private static final long serialVersionUID = 301077366599181567L;
66
67   /**
68    * This is the path separator string for the current host. This field
69    * contains the value of the <code>file.separator</code> system property.
70    * An example separator string would be "/" on the GNU system.
71    */
72   public static final String separator = SystemProperties.getProperty("file.separator");
73   private static final String dupSeparator = separator + separator;
74
75   /**
76    * This is the first character of the file separator string.  On many
77    * hosts (for example, on the GNU system), this represents the entire 
78    * separator string.  The complete separator string is obtained from the
79    * <code>file.separator</code>system property.
80    */
81   public static final char separatorChar = separator.charAt(0);
82   
83   /**
84    * This is the string that is used to separate the host name from the
85    * path name in paths that include the host name.  It is the value of
86    * the <code>path.separator</code> system property.
87    */
88   public static final String pathSeparator
89     = SystemProperties.getProperty("path.separator");
90   
91   /**
92    * This is the first character of the string used to separate the host name
93    * from the path name in paths that include a host.  The separator string
94    * is taken from the <code>path.separator</code> system property.
95    */
96   public static final char pathSeparatorChar = pathSeparator.charAt(0);
97
98   /**
99    * This is the path to the file set when the object is created.  It
100    * may be an absolute or relative path name.
101    */
102   private String path;
103   
104   
105   /**
106    * The time (millisecond), when the last temporary file was created.
107    */
108   private static long last_tmp;
109   
110   /**
111    * The number of files, created during the current millisecond.
112    */
113   private static int n_created;  
114
115   /**
116    * This method tests whether or not the current thread is allowed to
117    * to read the file pointed to by this object.  This will be true if and
118    * and only if 1) the file exists and 2) the <code>SecurityManager</code>
119    * (if any) allows access to the file via it's <code>checkRead</code>
120    * method 3) the file is readable.
121    *
122    * @return <code>true</code> if reading is allowed, 
123    * <code>false</code> otherwise
124    *
125    * @exception SecurityException If the <code>SecurityManager</code> 
126    * does not allow access to the file
127    */
128   public boolean canRead()
129   {
130     // Test for existence. This also does the SecurityManager check
131     if (!exists())
132       return false;
133
134     return VMFile.canRead(path);
135   }
136
137   /**
138    * This method test whether or not the current thread is allowed to
139    * write to this object.  This will be true if and only if 1) The
140    * <code>SecurityManager</code> (if any) allows write access to the
141    * file and 2) The file exists and 3) The file is writable.  To determine
142    * whether or not a non-existent file can be created, check the parent
143    * directory for write access.
144    *
145    * @return <code>true</code> if writing is allowed, <code>false</code> 
146    * otherwise
147    *
148    * @exception SecurityException If the <code>SecurityManager</code> 
149    * does not allow access to the file
150    */
151   public boolean canWrite()
152   {
153     // First do a SecurityCheck before doing anything else.
154     checkWrite();
155      
156     // Test for existence.  This is required by the spec
157     if (! VMFile.exists(path))
158       return false;
159
160     if (VMFile.isDirectory(path))
161       return VMFile.canWriteDirectory(this);
162     else
163       return VMFile.canWrite(path);
164   }
165
166   /**
167    * This method creates a new file of zero length with the same name as
168    * the path of this <code>File</code> object if an only if that file
169    * does not already exist.
170    * <p>
171    * A <code>SecurityManager.checkWrite</code> check is done prior
172    * to performing this action.
173    *
174    * @return <code>true</code> if the file was created, <code>false</code> if
175    * the file alread existed.
176    *
177    * @exception IOException If an I/O error occurs
178    * @exception SecurityException If the <code>SecurityManager</code> will
179    * not allow this operation to be performed.
180    *
181    * @since 1.2
182    */
183   public boolean createNewFile() throws IOException
184   {
185     checkWrite();
186     return VMFile.create(path);
187   }
188   /**
189    * This method deletes the file represented by this object.  If this file
190    * is a directory, it must be empty in order for the delete to succeed.
191    *
192    * @return <code>true</code> if the file was deleted, <code>false</code> 
193    * otherwise
194    *
195    * @exception SecurityException If deleting of the file is not allowed
196    */
197   public synchronized boolean delete()
198   {
199     SecurityManager s = System.getSecurityManager();
200     
201     if (s != null)
202       s.checkDelete(path);
203     
204     return VMFile.delete(path);
205   }
206
207   /**
208    * This method tests two <code>File</code> objects for equality by 
209    * comparing the path of the specified <code>File</code> against the path
210    * of this object.  The two objects are equal if an only if 1) The
211    * argument is not null 2) The argument is a <code>File</code> object and
212    * 3) The path of the <code>File</code>argument is equal to the path
213    * of this object.
214    * <p>
215    * The paths of the files are determined by calling the 
216    * <code>getPath()</code>
217    * method on each object.
218    *
219    * @return <code>true</code> if the two objects are equal, 
220    * <code>false</code> otherwise.
221    */
222   public boolean equals(Object obj)
223   {
224     if (! (obj instanceof File))
225       return false;
226     
227     File other = (File) obj;
228
229     if (VMFile.IS_CASE_SENSITIVE)
230       return path.equals(other.path);
231     else
232       return path.equalsIgnoreCase(other.path);
233   }
234
235   /**
236    * This method tests whether or not the file represented by the object
237    * actually exists on the filesystem.
238    *
239    * @return <code>true</code> if the file exists, <code>false</code>otherwise.
240    *
241    * @exception SecurityException If reading of the file is not permitted
242    */
243   public boolean exists()
244   {
245     checkRead();
246     return VMFile.exists(path);
247   }
248
249   /**
250    * This method initializes a new <code>File</code> object to represent
251    * a file with the specified path.
252    *
253    * @param name The path name of the file
254    */
255   public File(String name)
256   {
257     path = normalizePath (name);
258   }
259  
260   // Remove duplicate and redundant separator characters.
261   private String normalizePath(String p)
262   {
263     // On Windows, convert any '/' to '\'.  This appears to be the same logic
264     // that Sun's Win32 Java performs.
265     if (separatorChar == '\\')
266       {
267         p = p.replace ('/', '\\');
268         // We have to special case the "\c:" prefix.
269         if (p.length() > 2 && p.charAt(0) == '\\' &&
270             ((p.charAt(1) >= 'a' && p.charAt(1) <= 'z') ||
271             (p.charAt(1) >= 'A' && p.charAt(1) <= 'Z')) &&
272             p.charAt(2) == ':')
273           p = p.substring(1);
274       }
275
276     int dupIndex = p.indexOf(dupSeparator);
277     int plen = p.length();
278
279     // Special case: permit Windows UNC path prefix.
280     if (dupSeparator.equals("\\\\") && dupIndex == 0)
281       dupIndex = p.indexOf(dupSeparator, 1);
282
283     if (dupIndex == -1)
284       {
285         // Ignore trailing separator (though on Windows "a:\", for
286         // example, is a valid and minimal path).
287         if (plen > 1 && p.charAt (plen - 1) == separatorChar)
288           {
289             if (! (separatorChar == '\\' && ((plen == 3 && p.charAt(1) == ':')
290                 || (plen == 2 && p.charAt(0) == separatorChar))))
291               return p.substring (0, plen - 1);
292           }
293         else
294           return p;
295       }
296     
297     StringBuffer newpath = new StringBuffer(plen);
298     int last = 0;
299     while (dupIndex != -1)
300       {
301         newpath.append(p.substring(last, dupIndex));
302         // Ignore the duplicate path characters.
303         while (p.charAt(dupIndex) == separatorChar)
304           {
305             dupIndex++;
306             if (dupIndex == plen)
307               {
308                 if ((separatorChar == '\\'
309                     && newpath.length() == 2
310                     && newpath.charAt(1) == ':')
311                     || (separatorChar != '\\' && newpath.length() == 0))
312                   {
313                     newpath.append(separatorChar);
314                   }
315                 return newpath.toString();
316               }
317           }
318         newpath.append(separatorChar);
319         last = dupIndex;
320         dupIndex = p.indexOf(dupSeparator, last);
321       }
322     
323     // Again, ignore possible trailing separator (except special cases
324     // like "a:\" on Windows).
325     int end;
326     if (plen > 1 && p.charAt (plen - 1) == separatorChar)
327     {
328       if (separatorChar == '\\'
329         && ((plen == 3 && p.charAt(1) == ':')
330             || (plen == 2 && p.charAt(0) == separatorChar)))
331         end = plen;
332       else
333         end = plen - 1;
334     }
335     else
336       end = plen;
337     newpath.append(p.substring(last, end));
338     
339     return newpath.toString();
340   }
341  
342   /**
343    * This method initializes a new <code>File</code> object to represent
344    * a file in the specified named directory.  The path name to the file
345    * will be the directory name plus the separator string plus the file
346    * name.  If the directory path name ends in the separator string, another
347    * separator string will still be appended.
348    *
349    * @param dirPath The path to the directory the file resides in
350    * @param name The name of the file
351    */
352   public File(String dirPath, String name)
353   {
354     if (name == null)
355       throw new NullPointerException();
356     if (dirPath != null)
357       {
358         if (dirPath.length() > 0)
359           {
360             // Try to be smart about the number of separator characters.
361             if (dirPath.charAt(dirPath.length() - 1) == separatorChar
362                 || name.length() == 0)
363               path = normalizePath(dirPath + name);
364             else
365               path = normalizePath(dirPath + separatorChar + name);
366           }
367         else
368           {
369             // If dirPath is empty, use a system dependant
370             // default prefix.
371             // Note that the leading separators in name have
372             // to be chopped off, to prevent them forming
373             // a UNC prefix on Windows.
374             if (separatorChar == '\\' /* TODO use ON_WINDOWS */)
375               {
376                 int skip = 0;
377                 while(name.length() > skip
378                     && (name.charAt(skip) == separatorChar
379                     || name.charAt(skip) == '/'))
380                   {
381                     skip++;
382                   }
383                 name = name.substring(skip);
384               }
385             path = normalizePath(separatorChar + name);
386           }
387       }
388     else
389       path = normalizePath(name);
390   }
391
392   /**
393    * This method initializes a new <code>File</code> object to represent
394    * a file in the specified directory.  If the <code>directory</code>
395    * argument is <code>null</code>, the file is assumed to be in the
396    * current directory as specified by the <code>user.dir</code> system
397    * property
398    *
399    * @param directory The directory this file resides in
400    * @param name The name of the file
401    */
402   public File(File directory, String name)
403   {
404     this (directory == null ? null : directory.path, name);
405   }
406
407   /**
408    * This method initializes a new <code>File</code> object to represent
409    * a file corresponding to the specified <code>file:</code> protocol URI.
410    *
411    * @param uri The URI
412    * @throws IllegalArgumentException if the URI is not hierarchical
413    */
414   public File(URI uri)
415   {
416     if (uri == null)
417         throw new NullPointerException("uri is null");
418
419     if (!uri.getScheme().equals("file"))
420         throw new IllegalArgumentException("invalid uri protocol");
421
422     String name = uri.getPath();
423     if (name == null)
424       throw new IllegalArgumentException("URI \"" + uri
425                      + "\" is not hierarchical");
426     path = normalizePath(name);
427   }
428
429   /**
430    * This method returns the path of this file as an absolute path name.
431    * If the path name is already absolute, then it is returned.  Otherwise
432    * the value returned is the current directory plus the separatory
433    * string plus the path of the file.  The current directory is determined
434    * from the <code>user.dir</code> system property.
435    *
436    * @return The absolute path of this file
437    */
438   public String getAbsolutePath()
439   {
440     if (isAbsolute())
441       return path;
442     else
443       return VMFile.getAbsolutePath(path);
444   }
445
446   /**
447    * This method returns a <code>File</code> object representing the
448    * absolute path of this object.
449    *
450    * @return A <code>File</code> with the absolute path of the object.
451    *
452    * @since 1.2
453    */
454   public File getAbsoluteFile()
455   {
456     return new File(getAbsolutePath());
457   }
458
459   /**
460    * This method returns a canonical representation of the pathname of
461    * this file.  The actual form of the canonical representation is
462    * system-dependent.  On the GNU system, conversion to canonical
463    * form involves the removal of redundant separators, references to
464    * "." and "..", and symbolic links.
465    * <p>
466    * Note that this method, unlike the other methods which return path
467    * names, can throw an IOException.  This is because native method 
468    * might be required in order to resolve the canonical path
469    *
470    * @exception IOException If an error occurs
471    */
472   public String getCanonicalPath() throws IOException
473   {
474     // On Windows, getAbsolutePath might end up calling us, so we
475     // have to special case that call to avoid infinite recursion.
476     if (separatorChar == '\\' && path.length() == 2 &&
477         ((path.charAt(0) >= 'a' && path.charAt(0) <= 'z') ||
478          (path.charAt(0) >= 'A' && path.charAt(0) <= 'Z')) &&
479         path.charAt(1) == ':')
480     {
481         return VMFile.toCanonicalForm(path);
482     }
483     // Call getAbsolutePath first to make sure that we do the
484     // current directory handling, because the native code
485     // may have a different idea of the current directory.
486     return VMFile.toCanonicalForm(getAbsolutePath());
487   }
488
489   /**
490    * This method returns a <code>File</code> object representing the
491    * canonical path of this object.
492    *
493    * @return A <code>File</code> instance representing the canonical path of
494    * this object.
495    *
496    * @exception IOException If an error occurs.
497    *
498    * @since 1.2
499    */
500   public File getCanonicalFile() throws IOException
501   {
502     return new File(getCanonicalPath());
503   }
504
505   /**
506    * This method returns the name of the file.  This is everything in the
507    * complete path of the file after the last instance of the separator
508    * string.
509    *
510    * @return The file name
511    */
512   public String getName()
513   {
514         return VMFile.getName(path);
515   }
516
517   /**
518    * This method returns a <code>String</code> the represents this file's
519    * parent.  <code>null</code> is returned if the file has no parent.  The
520    * parent is determined via a simple operation which removes the name
521    * after the last file separator character, as determined by the platform.
522    *
523    * @return The parent directory of this file
524    */
525   public String getParent()
526   {
527     String prefix = null;
528     int nameSeqIndex = 0;
529     
530     if (path.equals(""))
531       return null;
532
533     // The "prefix", if present, is the leading "/" on UNIX and 
534     // either the drive specifier (e.g. "C:") or the leading "\\"
535     // of a UNC network path on Windows.
536     if (separatorChar == '/' && path.charAt (0) == '/')
537       {
538         prefix = "/";
539         nameSeqIndex = 1;
540       }
541     else if (separatorChar == '\\' && path.length() > 1)
542       {
543         if ((path.charAt (0) == '\\' && path.charAt (1) == '\\')
544             || (((path.charAt (0) >= 'a' && path.charAt (0) <= 'z')
545                  || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z'))
546                 && path.charAt (1) == ':'))
547           {
548             prefix = path.substring (0, 2);
549             nameSeqIndex = 2;
550           }
551       }
552
553     // According to the JDK docs, the returned parent path is the 
554     // portion of the name sequence before the last separator
555     // character, if found, prefixed by the prefix, otherwise null.
556     if (nameSeqIndex < path.length())
557       {
558         String nameSeq = path.substring (nameSeqIndex, path.length());
559         int last = nameSeq.lastIndexOf (separatorChar);
560         if (last == -1)
561           return prefix;
562         else if (last == (nameSeq.length() - 1))
563           // Note: The path would not have a trailing separator
564           // except for cases like "C:\" on Windows (see 
565           // normalizePath( )), where Sun's JRE 1.4 returns null.
566           return null;
567         else if (last == 0)
568           last++;
569
570         if (prefix != null)
571           return prefix + nameSeq.substring (0, last);
572         else
573           return nameSeq.substring (0, last);
574       }
575     else
576       // Sun's JRE 1.4 returns null if the prefix is the only 
577       // component of the path - so "/" gives null on UNIX and 
578       // "C:", "\\", etc. return null on Windows.
579       return null;
580   }
581
582   /**
583    * This method returns a <code>File</code> object representing the parent
584    * file of this one.
585    *
586    * @return a <code>File</code> for the parent of this object.  
587    * <code>null</code>
588    * will be returned if this object does not have a parent.
589    *
590    * @since 1.2
591    */
592   public File getParentFile()
593   {
594     String parent = getParent();
595     return parent != null ? new File(parent) : null;
596   }
597
598   /**
599    * Returns the path name that represents this file.  May be a relative
600    * or an absolute path name
601    *
602    * @return The pathname of this file
603    */
604   public String getPath()
605   {
606     return path;
607   }
608
609   /**
610    * This method returns a hash code representing this file.  It is the
611    * hash code of the path of this file (as returned by <code>getPath()</code>)
612    * exclusived or-ed with the value 1234321.
613    *
614    * @return The hash code for this object
615    */
616   public int hashCode()
617   {
618     if (VMFile.IS_CASE_SENSITIVE)
619       return path.hashCode() ^ 1234321;
620     else
621       return path.toLowerCase().hashCode() ^ 1234321;
622   }
623
624   /**
625    * This method returns true if this object represents an absolute file
626    * path and false if it does not.  The definition of an absolute path varies
627    * by system.  As an example, on GNU systems, a path is absolute if it starts
628    * with a "/".
629    *
630    * @return <code>true</code> if this object represents an absolute 
631    * file name, <code>false</code> otherwise.
632    */
633   public boolean isAbsolute()
634   {
635     return VMFile.isAbsolute(path);
636   }
637
638   /**
639    * This method tests whether or not the file represented by this object
640    * is a directory.  In order for this method to return <code>true</code>,
641    * the file represented by this object must exist and be a directory.
642    * 
643    * @return <code>true</code> if this file is a directory, <code>false</code>
644    * otherwise
645    *
646    * @exception SecurityException If reading of the file is not permitted
647    */
648   public boolean isDirectory()
649   {
650     checkRead();
651     return VMFile.isDirectory(path); 
652   }
653
654   /**
655    * This method tests whether or not the file represented by this object
656    * is a "plain" file.  A file is a plain file if and only if it 1) Exists,
657    * 2) Is not a directory or other type of special file.
658    *
659    * @return <code>true</code> if this is a plain file, <code>false</code> 
660    * otherwise
661    *
662    * @exception SecurityException If reading of the file is not permitted
663    */
664   public boolean isFile()
665   {
666     checkRead();
667     return VMFile.isFile(path);
668   }
669
670   /**
671    * This method tests whether or not this file represents a "hidden" file.
672    * On GNU systems, a file is hidden if its name begins with a "."
673    * character.  Files with these names are traditionally not shown with
674    * directory listing tools.
675    *
676    * @return <code>true</code> if the file is hidden, <code>false</code>
677    * otherwise.
678    *
679    * @since 1.2
680    */
681   public boolean isHidden()
682   {
683     return VMFile.isHidden(path);
684   }
685
686   /**
687    * This method returns the last modification time of this file.  The
688    * time value returned is an abstract value that should not be interpreted
689    * as a specified time value.  It is only useful for comparing to other
690    * such time values returned on the same system.  In that case, the larger
691    * value indicates a more recent modification time. 
692    * <p>
693    * If the file does not exist, then a value of 0 is returned.
694    *
695    * @return The last modification time of the file
696    *
697    * @exception SecurityException If reading of the file is not permitted
698    */
699   public long lastModified()
700   {
701     checkRead();
702     return VMFile.lastModified(path);
703   }
704
705   /**
706    * This method returns the length of the file represented by this object,
707    * or 0 if the specified file does not exist.
708    *
709    * @return The length of the file
710    *
711    * @exception SecurityException If reading of the file is not permitted
712    */
713   public long length()
714   {
715     checkRead();
716     return VMFile.length(path);
717   }
718
719   /**
720    * This method returns a array of <code>String</code>'s representing the
721    * list of files is then directory represented by this object.  If this
722    * object represents a non-directory file or a non-existent file, then
723    * <code>null</code> is returned.  The list of files will not contain
724    * any names such as "." or ".." which indicate the current or parent
725    * directory.  Also, the names are not guaranteed to be sorted.
726    * <p>
727    * In this form of the <code>list()</code> method, a filter is specified
728    * that allows the caller to control which files are returned in the
729    * list.  The <code>FilenameFilter</code> specified is called for each
730    * file returned to determine whether or not that file should be included
731    * in the list.
732    * <p>
733    * A <code>SecurityManager</code> check is made prior to reading the
734    * directory.  If read access to the directory is denied, an exception
735    * will be thrown.
736    *
737    * @param filter An object which will identify files to exclude from 
738    * the directory listing.
739    *
740    * @return An array of files in the directory, or <code>null</code> 
741    * if this object does not represent a valid directory.
742    * 
743    * @exception SecurityException If read access is not allowed to the 
744    * directory by the <code>SecurityManager</code>
745    */
746   public String[] list(FilenameFilter filter)
747   {
748     checkRead();
749
750     if (!exists() || !isDirectory())
751       return null;
752     
753     // Get the list of files
754     String files[] = VMFile.list(path);
755     
756     // Check if an error occured in listInternal().
757     // This is an unreadable directory, pretend there is nothing inside.
758     if (files == null)
759       return new String[0];
760
761     if (filter == null)
762       return files;
763     
764     // Apply the filter
765     int count = 0;
766     for (int i = 0; i < files.length; i++)
767       {
768         if (filter.accept(this, files[i]))
769           ++count;
770         else
771           files[i] = null;
772       }
773
774     String[] retfiles = new String[count];
775     count = 0;
776     for (int i = 0; i < files.length; i++)
777       if (files[i] != null)
778         retfiles[count++] = files[i];
779
780     return retfiles;
781   }
782
783   /**
784    * This method returns a array of <code>String</code>'s representing the
785    * list of files is then directory represented by this object.  If this
786    * object represents a non-directory file or a non-existent file, then
787    * <code>null</code> is returned.  The list of files will not contain
788    * any names such as "." or ".." which indicate the current or parent
789    * directory.  Also, the names are not guaranteed to be sorted.
790    * <p>
791    * A <code>SecurityManager</code> check is made prior to reading the
792    * directory.  If read access to the directory is denied, an exception
793    * will be thrown.
794    *
795    * @return An array of files in the directory, or <code>null</code> if 
796    * this object does not represent a valid directory.
797    * 
798    * @exception SecurityException If read access is not allowed to the 
799    * directory by the <code>SecurityManager</code>
800    */
801   public String[] list()
802   {
803     return list(null);
804   }
805
806   /**
807    * This method returns an array of <code>File</code> objects representing
808    * all the files in the directory represented by this object. If this
809    * object does not represent a directory, <code>null</code> is returned.
810    * Each of the returned <code>File</code> object is constructed with this
811    * object as its parent.
812    * <p>
813    * A <code>SecurityManager</code> check is made prior to reading the
814    * directory.  If read access to the directory is denied, an exception
815    * will be thrown.
816    *
817    * @return An array of <code>File</code> objects for this directory.
818    *
819    * @exception SecurityException If the <code>SecurityManager</code> denies
820    * access to this directory.
821    *
822    * @since 1.2
823    */
824   public File[] listFiles()
825   {
826     return listFiles((FilenameFilter) null);
827   }
828   
829   /**
830    * This method returns an array of <code>File</code> objects representing
831    * all the files in the directory represented by this object. If this
832    * object does not represent a directory, <code>null</code> is returned.
833    * Each of the returned <code>File</code> object is constructed with this
834    * object as its parent.
835    * <p> 
836    * In this form of the <code>listFiles()</code> method, a filter is specified
837    * that allows the caller to control which files are returned in the
838    * list.  The <code>FilenameFilter</code> specified is called for each
839    * file returned to determine whether or not that file should be included
840    * in the list.
841    * <p>
842    * A <code>SecurityManager</code> check is made prior to reading the
843    * directory.  If read access to the directory is denied, an exception
844    * will be thrown.
845    *
846    * @return An array of <code>File</code> objects for this directory.
847    *
848    * @exception SecurityException If the <code>SecurityManager</code> denies
849    * access to this directory.
850    *
851    * @since 1.2
852    */
853   public File[] listFiles(FilenameFilter filter)
854   {
855     String[] filelist = list(filter);
856     
857     if (filelist == null)
858       return null;
859
860     File[] fobjlist = new File [filelist.length];
861
862     for (int i = 0; i < filelist.length; i++)
863       fobjlist [i] = new File(this, filelist [i]);
864
865     return fobjlist;
866   }
867
868   /**
869    * This method returns an array of <code>File</code> objects representing
870    * all the files in the directory represented by this object. If this
871    * object does not represent a directory, <code>null</code> is returned.
872    * Each of the returned <code>File</code> object is constructed with this
873    * object as its parent.
874    * <p> 
875    * In this form of the <code>listFiles()</code> method, a filter is specified
876    * that allows the caller to control which files are returned in the
877    * list.  The <code>FileFilter</code> specified is called for each
878    * file returned to determine whether or not that file should be included
879    * in the list.
880    * <p>
881    * A <code>SecurityManager</code> check is made prior to reading the
882    * directory.  If read access to the directory is denied, an exception
883    * will be thrown.
884    *
885    * @return An array of <code>File</code> objects for this directory.
886    *
887    * @exception SecurityException If the <code>SecurityManager</code> denies
888    * access to this directory.
889    *
890    * @since 1.2
891    */
892   public File[] listFiles(FileFilter filter)
893   {
894     File[] fobjlist = listFiles((FilenameFilter) null);
895
896     if (fobjlist == null)
897       return null;
898
899     if (filter == null)
900       return fobjlist;
901
902     int count = 0;
903     for (int i = 0; i < fobjlist.length; i++)
904       if (filter.accept(fobjlist[i]) == true)
905         ++count;
906
907     File[] final_list = new File[count];
908     count = 0;
909     for (int i = 0; i < fobjlist.length; i++)
910       if (filter.accept(fobjlist[i]) == true)
911         {
912           final_list[count] = fobjlist[i];
913           ++count;
914         }
915
916     return final_list;
917   }
918
919   /**
920    * This method returns a <code>String</code> that is the path name of the
921    * file as returned by <code>getPath</code>.
922    *
923    * @return A <code>String</code> representation of this file
924    */
925   public String toString()
926   {
927     return path;
928   }
929
930   /**
931    * @return A <code>URI</code> for this object.
932    */
933   public URI toURI()
934   {
935     String abspath = getAbsolutePath();
936        
937     if (isDirectory() || path.equals(""))
938       abspath = abspath + separatorChar;
939
940     if (separatorChar == '\\')
941       abspath = separatorChar + abspath;
942         
943     try
944       {
945         return new URI("file", null, null, -1,
946                        abspath.replace(separatorChar, '/'),
947                        null, null);
948       }
949     catch (URISyntaxException use)
950       {
951         // Can't happen.
952         throw (InternalError) new InternalError("Unconvertible file: "
953                                                 + this).initCause(use);
954       }
955   }
956
957   /**
958    * This method returns a <code>URL</code> with the <code>file:</code>
959    * protocol that represents this file.  The exact form of this URL is
960    * system dependent.
961    *
962    * @return A <code>URL</code> for this object.
963    *
964    * @exception MalformedURLException If the URL cannot be created 
965    * successfully.
966    */
967   public URL toURL() throws MalformedURLException
968   {
969     return VMFile.toURL(this);
970   }
971
972
973   /**
974    * This method creates a directory for the path represented by this object.
975    *
976    * @return <code>true</code> if the directory was created, 
977    * <code>false</code> otherwise
978    *
979    * @exception SecurityException If write access is not allowed to this file
980    */
981   public boolean mkdir()
982   {
983     checkWrite();
984     return VMFile.mkdir(path);
985   }
986
987   /**
988    * This method creates a directory for the path represented by this file.
989    * It will also create any intervening parent directories if necessary.
990    *
991    * @return <code>true</code> if the directory was created, 
992    * <code>false</code> otherwise
993    *
994    * @exception SecurityException If write access is not allowed to this file
995    */
996   public boolean mkdirs()
997   {
998     String parent = getParent();
999     if (parent == null)
1000       {
1001         return mkdir();
1002       }
1003       
1004     File f = new File(parent);
1005     if (!f.exists())
1006       {
1007         boolean rc = f.mkdirs();
1008         if (rc == false)
1009           return false;
1010       }
1011
1012     return mkdir();
1013   }
1014
1015   /**
1016    * This method creates a temporary file in the specified directory.  If 
1017    * the directory name is null, then this method uses the system temporary 
1018    * directory. The files created are guaranteed not to currently exist and 
1019    * the same file name will never be used twice in the same virtual 
1020    * machine instance.  
1021    * The system temporary directory is determined by examinging the 
1022    * <code>java.io.tmpdir</code> system property.
1023    * <p>
1024    * The <code>prefix</code> parameter is a sequence of at least three
1025    * characters that are used as the start of the generated filename.  The
1026    * <code>suffix</code> parameter is a sequence of characters that is used
1027    * to terminate the file name.  This parameter may be <code>null</code>
1028    * and if it is, the suffix defaults to ".tmp".
1029    * <p>
1030    * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code>
1031    * method is used to verify that this operation is permitted.
1032    *
1033    * @param prefix The character prefix to use in generating the path name.
1034    * @param suffix The character suffix to use in generating the path name.
1035    * @param directory The directory to create the file in, or 
1036    * <code>null</code> for the default temporary directory
1037    *
1038    * @exception IllegalArgumentException If the patterns is not valid
1039    * @exception SecurityException If there is no permission to perform 
1040    * this operation
1041    * @exception IOException If an error occurs
1042    *
1043    * @since 1.2
1044    */
1045   public static synchronized File createTempFile(String prefix, String suffix,
1046                                     File directory)
1047     throws IOException
1048   {
1049     // Grab the system temp directory if necessary
1050     if (directory == null)
1051       {
1052         String dirname = System.getProperty("java.io.tmpdir");
1053         if (dirname == null)
1054           throw new IOException("Cannot determine system temporary directory"); 
1055         
1056         directory = new File(dirname);
1057         if (! VMFile.exists(directory.path))
1058           throw new IOException("System temporary directory "
1059                                 + directory.getName() + " does not exist.");
1060         if (! VMFile.isDirectory(directory.path))
1061           throw new IOException("System temporary directory "
1062                                 + directory.getName()
1063                                 + " is not really a directory.");
1064       }
1065
1066     // Check if prefix is at least 3 characters long
1067     if (prefix.length() < 3)
1068       throw new IllegalArgumentException("Prefix too short: " + prefix);
1069
1070     // Set default value of suffix
1071     if (suffix == null)
1072       suffix = ".tmp";
1073
1074     // Now identify a file name and make sure it doesn't exist.
1075     File file;
1076     if (!VMFile.IS_DOS_8_3)
1077       { 
1078         do
1079           {
1080             long now = System.currentTimeMillis();
1081             if (now > last_tmp)
1082               {
1083                 // The last temporary file was created more than 1 ms ago.
1084                 last_tmp = now;
1085                 n_created = 0;
1086               }
1087             else
1088               n_created++;
1089             
1090             String name = Long.toHexString(now);
1091             if (n_created > 0)
1092               name += '_'+Integer.toHexString(n_created);
1093             String filename = prefix + name + suffix;
1094             file = new File(directory, filename);
1095           }
1096         while (VMFile.exists(file.path));
1097       }
1098     else
1099       {
1100         // make sure prefix is not longer than 7 characters
1101         if (prefix.length() >= 8)
1102           throw new IllegalArgumentException("Prefix too long: " + prefix + "(valid length 3..7)");
1103
1104         long mask = 0x000000ffffFFFFL >> (prefix.length() * 4);
1105         do
1106           {
1107             int n = (int) (System.currentTimeMillis() & mask);
1108             String filename = prefix + java.lang.Integer.toHexString(n) + suffix;
1109             file = new File(directory, filename);
1110           }
1111         while (VMFile.exists(file.path));
1112       }
1113
1114     // Verify that we are allowed to create this file
1115     SecurityManager sm = System.getSecurityManager();
1116     if (sm != null)
1117       sm.checkWrite(file.getAbsolutePath());
1118
1119     // Now create the file and return our file object
1120     // XXX - FIXME race condition.
1121     VMFile.create(file.getAbsolutePath()); 
1122     return file;
1123   }
1124
1125   /**
1126    * This method sets the file represented by this object to be read only.
1127    * A read only file or directory cannot be modified.  Please note that 
1128    * GNU systems allow read only files to be deleted if the directory it
1129    * is contained in is writable.
1130    *
1131    * @return <code>true</code> if the operation succeeded, <code>false</code>
1132    * otherwise.
1133    *
1134    * @exception SecurityException If the <code>SecurityManager</code> does
1135    * not allow this operation.
1136    *
1137    * @since 1.2
1138    */
1139   public boolean setReadOnly()
1140   {
1141     // Do a security check before trying to do anything else.
1142     checkWrite();
1143
1144     // Test for existence.
1145     if (! VMFile.exists(path))
1146       return false;
1147
1148     return VMFile.setReadOnly(path);
1149   }
1150
1151   /**
1152    * This method returns an array of filesystem roots.  Some operating systems
1153    * have volume oriented filesystem.  This method provides a mechanism for
1154    * determining which volumes exist.  GNU systems use a single hierarchical
1155    * filesystem, so will have only one "/" filesystem root.
1156    *
1157    * @return An array of <code>File</code> objects for each filesystem root
1158    * available.
1159    *
1160    * @since 1.2
1161    */
1162   public static File[] listRoots()
1163   {
1164     File[] roots = VMFile.listRoots();
1165     
1166     SecurityManager s = System.getSecurityManager();
1167     if (s != null)
1168       {
1169         // Only return roots to which the security manager permits read access.
1170         int count = roots.length;
1171         for (int i = 0; i < roots.length; i++)
1172           {
1173             try
1174               {
1175                 s.checkRead (roots[i].path);            
1176               }
1177             catch (SecurityException sx)
1178               {
1179                 roots[i] = null;
1180                 count--;
1181               }
1182           }
1183         if (count != roots.length)
1184           {
1185             File[] newRoots = new File[count];
1186             int k = 0;
1187             for (int i = 0; i < roots.length; i++)
1188               {
1189                 if (roots[i] != null)
1190                   newRoots[k++] = roots[i];
1191               }
1192             roots = newRoots;
1193           }
1194       }
1195     return roots;
1196   }
1197
1198   /**
1199    * This method creates a temporary file in the system temporary directory. 
1200    * The files created are guaranteed not to currently exist and the same file
1201    * name will never be used twice in the same virtual machine instance.  The
1202    * system temporary directory is determined by examinging the 
1203    * <code>java.io.tmpdir</code> system property.
1204    * <p>
1205    * The <code>prefix</code> parameter is a sequence of at least three
1206    * characters that are used as the start of the generated filename.  The
1207    * <code>suffix</code> parameter is a sequence of characters that is used
1208    * to terminate the file name.  This parameter may be <code>null</code>
1209    * and if it is, the suffix defaults to ".tmp".
1210    * <p>
1211    * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code>
1212    * method is used to verify that this operation is permitted.
1213    * <p>
1214    * This method is identical to calling 
1215    * <code>createTempFile(prefix, suffix, null)</code>.
1216    *
1217    * @param prefix The character prefix to use in generating the path name.
1218    * @param suffix The character suffix to use in generating the path name.
1219    *
1220    * @exception IllegalArgumentException If the prefix or suffix are not valid.
1221    * @exception SecurityException If there is no permission to perform 
1222    * this operation
1223    * @exception IOException If an error occurs
1224    */
1225   public static File createTempFile(String prefix, String suffix)
1226     throws IOException
1227   {
1228     return createTempFile(prefix, suffix, null);
1229   }
1230
1231   /**
1232    * This method compares the specified <code>File</code> to this one
1233    * to test for equality.  It does this by comparing the canonical path names
1234    * of the files. 
1235    * <p>
1236    * The canonical paths of the files are determined by calling the
1237    * <code>getCanonicalPath</code> method on each object.
1238    * <p>
1239    * This method returns a 0 if the specified <code>Object</code> is equal
1240    * to this one, a negative value if it is less than this one 
1241    * a positive value if it is greater than this one.
1242    *
1243    * @return An integer as described above
1244    *
1245    * @since 1.2
1246    */
1247   public int compareTo(File other)
1248   {
1249     if (VMFile.IS_CASE_SENSITIVE)
1250       return path.compareTo (other.path);
1251     else
1252       return path.compareToIgnoreCase (other.path);
1253   }
1254
1255   /**
1256    * This method renames the file represented by this object to the path
1257    * of the file represented by the argument <code>File</code>.
1258    *
1259    * @param dest The <code>File</code> object representing the target name
1260    *
1261    * @return <code>true</code> if the rename succeeds, <code>false</code> 
1262    * otherwise.
1263    *
1264    * @exception SecurityException If write access is not allowed to the 
1265    * file by the <code>SecurityMananger</code>.
1266    */
1267   public synchronized boolean renameTo(File dest)
1268   {
1269     checkWrite();
1270     dest.checkWrite();
1271     // Call our native rename method
1272     return VMFile.renameTo(path, dest.path);
1273   }
1274
1275   /**
1276    * This method sets the modification time on the file to the specified
1277    * value.  This is specified as the number of seconds since midnight
1278    * on January 1, 1970 GMT.
1279    *
1280    * @param time The desired modification time.
1281    *
1282    * @return <code>true</code> if the operation succeeded, <code>false</code>
1283    * otherwise.
1284    *
1285    * @exception IllegalArgumentException If the specified time is negative.
1286    * @exception SecurityException If the <code>SecurityManager</code> will
1287    * not allow this operation.
1288    *
1289    * @since 1.2
1290    */
1291   public boolean setLastModified(long time) 
1292   {
1293     if (time < 0)
1294       throw new IllegalArgumentException("Negative modification time: " + time);
1295
1296     checkWrite();
1297     return VMFile.setLastModified(path, time);
1298   }
1299
1300   private void checkWrite()
1301   {
1302     // Check the SecurityManager
1303     SecurityManager s = System.getSecurityManager();
1304     
1305     if (s != null)
1306       s.checkWrite(path);
1307   }
1308
1309   private void checkRead()
1310   {
1311     // Check the SecurityManager
1312     SecurityManager s = System.getSecurityManager();
1313     
1314     if (s != null)
1315       s.checkRead(path);
1316   }
1317
1318   /** 
1319    * Calling this method requests that the file represented by this object
1320    * be deleted when the virtual machine exits.  Note that this request cannot
1321    * be cancelled.  Also, it will only be carried out if the virtual machine
1322    * exits normally.
1323    *
1324    * @exception SecurityException If deleting of the file is not allowed
1325    *
1326    * @since 1.2 
1327    */
1328   public void deleteOnExit()
1329   {
1330     // Check the SecurityManager
1331     SecurityManager sm = System.getSecurityManager();
1332     if (sm != null)
1333       sm.checkDelete(path);
1334
1335     DeleteFileHelper.add(this);
1336   }
1337
1338   private void writeObject(ObjectOutputStream oos) throws IOException
1339   {
1340     oos.defaultWriteObject();
1341     oos.writeChar(separatorChar);
1342   }
1343
1344   private void readObject(ObjectInputStream ois)
1345     throws ClassNotFoundException, IOException
1346   {
1347     ois.defaultReadObject();
1348
1349     // If the file was from an OS with a different dir separator,
1350     // fixup the path to use the separator on this OS.
1351     char oldSeparatorChar = ois.readChar();
1352     
1353     if (oldSeparatorChar != separatorChar)
1354       path = path.replace(oldSeparatorChar, separatorChar);
1355   }
1356   
1357 } // class File
1358