OSDN Git Service

libjava/classpath/ChangeLog.gcj:
[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 tests whether or not the current thread is allowed to
168    * to execute the file pointed to by this object. This will be true if and
169    * and only if 1) the file exists and 2) the <code>SecurityManager</code>
170    * (if any) allows access to the file via it's <code>checkExec</code>
171    * method 3) the file is executable.
172    *
173    * @return <code>true</code> if execution is allowed, 
174    * <code>false</code> otherwise
175    *
176    * @exception SecurityException If the <code>SecurityManager</code> 
177    * does not allow access to the file
178    */
179   public boolean canExecute()
180   {
181     if (!VMFile.exists(path))
182       return false;
183
184     checkExec();
185     
186     return VMFile.canExecute(path);
187   }
188
189   /**
190    * This method creates a new file of zero length with the same name as
191    * the path of this <code>File</code> object if an only if that file
192    * does not already exist.
193    * <p>
194    * A <code>SecurityManager.checkWrite</code> check is done prior
195    * to performing this action.
196    *
197    * @return <code>true</code> if the file was created, <code>false</code> if
198    * the file alread existed.
199    *
200    * @exception IOException If an I/O error occurs
201    * @exception SecurityException If the <code>SecurityManager</code> will
202    * not allow this operation to be performed.
203    *
204    * @since 1.2
205    */
206   public boolean createNewFile() throws IOException
207   {
208     checkWrite();
209     return VMFile.create(path);
210   }
211   /**
212    * This method deletes the file represented by this object.  If this file
213    * is a directory, it must be empty in order for the delete to succeed.
214    *
215    * @return <code>true</code> if the file was deleted, <code>false</code> 
216    * otherwise
217    *
218    * @exception SecurityException If deleting of the file is not allowed
219    */
220   public synchronized boolean delete()
221   {
222     SecurityManager s = System.getSecurityManager();
223     
224     if (s != null)
225       s.checkDelete(path);
226     
227     return VMFile.delete(path);
228   }
229
230   /**
231    * This method tests two <code>File</code> objects for equality by 
232    * comparing the path of the specified <code>File</code> against the path
233    * of this object.  The two objects are equal if an only if 1) The
234    * argument is not null 2) The argument is a <code>File</code> object and
235    * 3) The path of the <code>File</code>argument is equal to the path
236    * of this object.
237    * <p>
238    * The paths of the files are determined by calling the 
239    * <code>getPath()</code>
240    * method on each object.
241    *
242    * @return <code>true</code> if the two objects are equal, 
243    * <code>false</code> otherwise.
244    */
245   public boolean equals(Object obj)
246   {
247     if (! (obj instanceof File))
248       return false;
249     
250     File other = (File) obj;
251
252     if (VMFile.IS_CASE_SENSITIVE)
253       return path.equals(other.path);
254     else
255       return path.equalsIgnoreCase(other.path);
256   }
257
258   /**
259    * This method tests whether or not the file represented by the object
260    * actually exists on the filesystem.
261    *
262    * @return <code>true</code> if the file exists, <code>false</code>otherwise.
263    *
264    * @exception SecurityException If reading of the file is not permitted
265    */
266   public boolean exists()
267   {
268     checkRead();
269     return VMFile.exists(path);
270   }
271
272   /**
273    * This method initializes a new <code>File</code> object to represent
274    * a file with the specified path.
275    *
276    * @param name The path name of the file
277    */
278   public File(String name)
279   {
280     path = normalizePath (name);
281   }
282  
283   // Remove duplicate and redundant separator characters.
284   private String normalizePath(String p)
285   {
286     // On Windows, convert any '/' to '\'.  This appears to be the same logic
287     // that Sun's Win32 Java performs.
288     if (separatorChar == '\\')
289       {
290         p = p.replace ('/', '\\');
291         // We have to special case the "\c:" prefix.
292         if (p.length() > 2 && p.charAt(0) == '\\' &&
293             ((p.charAt(1) >= 'a' && p.charAt(1) <= 'z') ||
294             (p.charAt(1) >= 'A' && p.charAt(1) <= 'Z')) &&
295             p.charAt(2) == ':')
296           p = p.substring(1);
297       }
298
299     int dupIndex = p.indexOf(dupSeparator);
300     int plen = p.length();
301
302     // Special case: permit Windows UNC path prefix.
303     if (dupSeparator.equals("\\\\") && dupIndex == 0)
304       dupIndex = p.indexOf(dupSeparator, 1);
305
306     if (dupIndex == -1)
307       {
308         // Ignore trailing separator (though on Windows "a:\", for
309         // example, is a valid and minimal path).
310         if (plen > 1 && p.charAt (plen - 1) == separatorChar)
311           {
312             if (! (separatorChar == '\\' && ((plen == 3 && p.charAt(1) == ':')
313                 || (plen == 2 && p.charAt(0) == separatorChar))))
314               return p.substring (0, plen - 1);
315           }
316         else
317           return p;
318       }
319     
320     StringBuffer newpath = new StringBuffer(plen);
321     int last = 0;
322     while (dupIndex != -1)
323       {
324         newpath.append(p.substring(last, dupIndex));
325         // Ignore the duplicate path characters.
326         while (p.charAt(dupIndex) == separatorChar)
327           {
328             dupIndex++;
329             if (dupIndex == plen)
330               {
331                 if ((separatorChar == '\\'
332                     && newpath.length() == 2
333                     && newpath.charAt(1) == ':')
334                     || (separatorChar != '\\' && newpath.length() == 0))
335                   {
336                     newpath.append(separatorChar);
337                   }
338                 return newpath.toString();
339               }
340           }
341         newpath.append(separatorChar);
342         last = dupIndex;
343         dupIndex = p.indexOf(dupSeparator, last);
344       }
345     
346     // Again, ignore possible trailing separator (except special cases
347     // like "a:\" on Windows).
348     int end;
349     if (plen > 1 && p.charAt (plen - 1) == separatorChar)
350     {
351       if (separatorChar == '\\'
352         && ((plen == 3 && p.charAt(1) == ':')
353             || (plen == 2 && p.charAt(0) == separatorChar)))
354         end = plen;
355       else
356         end = plen - 1;
357     }
358     else
359       end = plen;
360     newpath.append(p.substring(last, end));
361     
362     return newpath.toString();
363   }
364  
365   /**
366    * This method initializes a new <code>File</code> object to represent
367    * a file in the specified named directory.  The path name to the file
368    * will be the directory name plus the separator string plus the file
369    * name.  If the directory path name ends in the separator string, another
370    * separator string will still be appended.
371    *
372    * @param dirPath The path to the directory the file resides in
373    * @param name The name of the file
374    */
375   public File(String dirPath, String name)
376   {
377     if (name == null)
378       throw new NullPointerException();
379     if (dirPath != null)
380       {
381         if (dirPath.length() > 0)
382           {
383             // Try to be smart about the number of separator characters.
384             if (dirPath.charAt(dirPath.length() - 1) == separatorChar
385                 || name.length() == 0)
386               path = normalizePath(dirPath + name);
387             else
388               path = normalizePath(dirPath + separatorChar + name);
389           }
390         else
391           {
392             // If dirPath is empty, use a system dependant
393             // default prefix.
394             // Note that the leading separators in name have
395             // to be chopped off, to prevent them forming
396             // a UNC prefix on Windows.
397             if (separatorChar == '\\' /* TODO use ON_WINDOWS */)
398               {
399                 int skip = 0;
400                 while(name.length() > skip
401                     && (name.charAt(skip) == separatorChar
402                     || name.charAt(skip) == '/'))
403                   {
404                     skip++;
405                   }
406                 name = name.substring(skip);
407               }
408             path = normalizePath(separatorChar + name);
409           }
410       }
411     else
412       path = normalizePath(name);
413   }
414
415   /**
416    * This method initializes a new <code>File</code> object to represent
417    * a file in the specified directory.  If the <code>directory</code>
418    * argument is <code>null</code>, the file is assumed to be in the
419    * current directory as specified by the <code>user.dir</code> system
420    * property
421    *
422    * @param directory The directory this file resides in
423    * @param name The name of the file
424    */
425   public File(File directory, String name)
426   {
427     this (directory == null ? null : directory.path, name);
428   }
429
430   /**
431    * This method initializes a new <code>File</code> object to represent
432    * a file corresponding to the specified <code>file:</code> protocol URI.
433    *
434    * @param uri The URI
435    * @throws IllegalArgumentException if the URI is not hierarchical
436    */
437   public File(URI uri)
438   {
439     if (uri == null)
440         throw new NullPointerException("uri is null");
441
442     if (!uri.getScheme().equals("file"))
443         throw new IllegalArgumentException("invalid uri protocol");
444
445     String name = uri.getPath();
446     if (name == null)
447       throw new IllegalArgumentException("URI \"" + uri
448                      + "\" is not hierarchical");
449     path = normalizePath(name);
450   }
451
452   /**
453    * This method returns the path of this file as an absolute path name.
454    * If the path name is already absolute, then it is returned.  Otherwise
455    * the value returned is the current directory plus the separatory
456    * string plus the path of the file.  The current directory is determined
457    * from the <code>user.dir</code> system property.
458    *
459    * @return The absolute path of this file
460    */
461   public String getAbsolutePath()
462   {
463     if (isAbsolute())
464       return path;
465     else
466       return VMFile.getAbsolutePath(path);
467   }
468
469   /**
470    * This method returns a <code>File</code> object representing the
471    * absolute path of this object.
472    *
473    * @return A <code>File</code> with the absolute path of the object.
474    *
475    * @since 1.2
476    */
477   public File getAbsoluteFile()
478   {
479     return new File(getAbsolutePath());
480   }
481
482   /**
483    * This method returns a canonical representation of the pathname of
484    * this file.  The actual form of the canonical representation is
485    * system-dependent.  On the GNU system, conversion to canonical
486    * form involves the removal of redundant separators, references to
487    * "." and "..", and symbolic links.
488    * <p>
489    * Note that this method, unlike the other methods which return path
490    * names, can throw an IOException.  This is because native method 
491    * might be required in order to resolve the canonical path
492    *
493    * @exception IOException If an error occurs
494    */
495   public String getCanonicalPath() throws IOException
496   {
497     // On Windows, getAbsolutePath might end up calling us, so we
498     // have to special case that call to avoid infinite recursion.
499     if (separatorChar == '\\' && path.length() == 2 &&
500         ((path.charAt(0) >= 'a' && path.charAt(0) <= 'z') ||
501          (path.charAt(0) >= 'A' && path.charAt(0) <= 'Z')) &&
502         path.charAt(1) == ':')
503     {
504         return VMFile.toCanonicalForm(path);
505     }
506     // Call getAbsolutePath first to make sure that we do the
507     // current directory handling, because the native code
508     // may have a different idea of the current directory.
509     return VMFile.toCanonicalForm(getAbsolutePath());
510   }
511
512   /**
513    * This method returns a <code>File</code> object representing the
514    * canonical path of this object.
515    *
516    * @return A <code>File</code> instance representing the canonical path of
517    * this object.
518    *
519    * @exception IOException If an error occurs.
520    *
521    * @since 1.2
522    */
523   public File getCanonicalFile() throws IOException
524   {
525     return new File(getCanonicalPath());
526   }
527
528   /**
529    * This method returns the name of the file.  This is everything in the
530    * complete path of the file after the last instance of the separator
531    * string.
532    *
533    * @return The file name
534    */
535   public String getName()
536   {
537         return VMFile.getName(path);
538   }
539
540   /**
541    * This method returns a <code>String</code> the represents this file's
542    * parent.  <code>null</code> is returned if the file has no parent.  The
543    * parent is determined via a simple operation which removes the name
544    * after the last file separator character, as determined by the platform.
545    *
546    * @return The parent directory of this file
547    */
548   public String getParent()
549   {
550     String prefix = null;
551     int nameSeqIndex = 0;
552     
553     if (path.equals(""))
554       return null;
555
556     // The "prefix", if present, is the leading "/" on UNIX and 
557     // either the drive specifier (e.g. "C:") or the leading "\\"
558     // of a UNC network path on Windows.
559     if (separatorChar == '/' && path.charAt (0) == '/')
560       {
561         prefix = "/";
562         nameSeqIndex = 1;
563       }
564     else if (separatorChar == '\\' && path.length() > 1)
565       {
566         if ((path.charAt (0) == '\\' && path.charAt (1) == '\\')
567             || (((path.charAt (0) >= 'a' && path.charAt (0) <= 'z')
568                  || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z'))
569                 && path.charAt (1) == ':'))
570           {
571             prefix = path.substring (0, 2);
572             nameSeqIndex = 2;
573           }
574       }
575
576     // According to the JDK docs, the returned parent path is the 
577     // portion of the name sequence before the last separator
578     // character, if found, prefixed by the prefix, otherwise null.
579     if (nameSeqIndex < path.length())
580       {
581         String nameSeq = path.substring (nameSeqIndex, path.length());
582         int last = nameSeq.lastIndexOf (separatorChar);
583         if (last == -1)
584           return prefix;
585         else if (last == (nameSeq.length() - 1))
586           // Note: The path would not have a trailing separator
587           // except for cases like "C:\" on Windows (see 
588           // normalizePath( )), where Sun's JRE 1.4 returns null.
589           return null;
590         else if (last == 0)
591           last++;
592
593         if (prefix != null)
594           return prefix + nameSeq.substring (0, last);
595         else
596           return nameSeq.substring (0, last);
597       }
598     else
599       // Sun's JRE 1.4 returns null if the prefix is the only 
600       // component of the path - so "/" gives null on UNIX and 
601       // "C:", "\\", etc. return null on Windows.
602       return null;
603   }
604
605   /**
606    * This method returns a <code>File</code> object representing the parent
607    * file of this one.
608    *
609    * @return a <code>File</code> for the parent of this object.  
610    * <code>null</code>
611    * will be returned if this object does not have a parent.
612    *
613    * @since 1.2
614    */
615   public File getParentFile()
616   {
617     String parent = getParent();
618     return parent != null ? new File(parent) : null;
619   }
620
621   /**
622    * Returns the path name that represents this file.  May be a relative
623    * or an absolute path name
624    *
625    * @return The pathname of this file
626    */
627   public String getPath()
628   {
629     return path;
630   }
631
632   /**
633    * This method returns a hash code representing this file.  It is the
634    * hash code of the path of this file (as returned by <code>getPath()</code>)
635    * exclusived or-ed with the value 1234321.
636    *
637    * @return The hash code for this object
638    */
639   public int hashCode()
640   {
641     if (VMFile.IS_CASE_SENSITIVE)
642       return path.hashCode() ^ 1234321;
643     else
644       return path.toLowerCase().hashCode() ^ 1234321;
645   }
646
647   /**
648    * This method returns true if this object represents an absolute file
649    * path and false if it does not.  The definition of an absolute path varies
650    * by system.  As an example, on GNU systems, a path is absolute if it starts
651    * with a "/".
652    *
653    * @return <code>true</code> if this object represents an absolute 
654    * file name, <code>false</code> otherwise.
655    */
656   public boolean isAbsolute()
657   {
658     return VMFile.isAbsolute(path);
659   }
660
661   /**
662    * This method tests whether or not the file represented by this object
663    * is a directory.  In order for this method to return <code>true</code>,
664    * the file represented by this object must exist and be a directory.
665    * 
666    * @return <code>true</code> if this file is a directory, <code>false</code>
667    * otherwise
668    *
669    * @exception SecurityException If reading of the file is not permitted
670    */
671   public boolean isDirectory()
672   {
673     checkRead();
674     return VMFile.isDirectory(path); 
675   }
676
677   /**
678    * This method tests whether or not the file represented by this object
679    * is a "plain" file.  A file is a plain file if and only if it 1) Exists,
680    * 2) Is not a directory or other type of special file.
681    *
682    * @return <code>true</code> if this is a plain file, <code>false</code> 
683    * otherwise
684    *
685    * @exception SecurityException If reading of the file is not permitted
686    */
687   public boolean isFile()
688   {
689     checkRead();
690     return VMFile.isFile(path);
691   }
692
693   /**
694    * This method tests whether or not this file represents a "hidden" file.
695    * On GNU systems, a file is hidden if its name begins with a "."
696    * character.  Files with these names are traditionally not shown with
697    * directory listing tools.
698    *
699    * @return <code>true</code> if the file is hidden, <code>false</code>
700    * otherwise.
701    *
702    * @since 1.2
703    */
704   public boolean isHidden()
705   {
706     return VMFile.isHidden(path);
707   }
708
709   /**
710    * This method returns the last modification time of this file.  The
711    * time value returned is an abstract value that should not be interpreted
712    * as a specified time value.  It is only useful for comparing to other
713    * such time values returned on the same system.  In that case, the larger
714    * value indicates a more recent modification time. 
715    * <p>
716    * If the file does not exist, then a value of 0 is returned.
717    *
718    * @return The last modification time of the file
719    *
720    * @exception SecurityException If reading of the file is not permitted
721    */
722   public long lastModified()
723   {
724     checkRead();
725     return VMFile.lastModified(path);
726   }
727
728   /**
729    * This method returns the length of the file represented by this object,
730    * or 0 if the specified file does not exist.
731    *
732    * @return The length of the file
733    *
734    * @exception SecurityException If reading of the file is not permitted
735    */
736   public long length()
737   {
738     checkRead();
739     return VMFile.length(path);
740   }
741
742   /**
743    * This method returns a array of <code>String</code>'s representing the
744    * list of files is then directory represented by this object.  If this
745    * object represents a non-directory file or a non-existent file, then
746    * <code>null</code> is returned.  The list of files will not contain
747    * any names such as "." or ".." which indicate the current or parent
748    * directory.  Also, the names are not guaranteed to be sorted.
749    * <p>
750    * In this form of the <code>list()</code> method, a filter is specified
751    * that allows the caller to control which files are returned in the
752    * list.  The <code>FilenameFilter</code> specified is called for each
753    * file returned to determine whether or not that file should be included
754    * in the list.
755    * <p>
756    * A <code>SecurityManager</code> check is made prior to reading the
757    * directory.  If read access to the directory is denied, an exception
758    * will be thrown.
759    *
760    * @param filter An object which will identify files to exclude from 
761    * the directory listing.
762    *
763    * @return An array of files in the directory, or <code>null</code> 
764    * if this object does not represent a valid directory.
765    * 
766    * @exception SecurityException If read access is not allowed to the 
767    * directory by the <code>SecurityManager</code>
768    */
769   public String[] list(FilenameFilter filter)
770   {
771     checkRead();
772
773     if (!exists() || !isDirectory())
774       return null;
775     
776     // Get the list of files
777     String files[] = VMFile.list(path);
778     
779     // Check if an error occured in listInternal().
780     // This is an unreadable directory, pretend there is nothing inside.
781     if (files == null)
782       return new String[0];
783
784     if (filter == null)
785       return files;
786     
787     // Apply the filter
788     int count = 0;
789     for (int i = 0; i < files.length; i++)
790       {
791         if (filter.accept(this, files[i]))
792           ++count;
793         else
794           files[i] = null;
795       }
796
797     String[] retfiles = new String[count];
798     count = 0;
799     for (int i = 0; i < files.length; i++)
800       if (files[i] != null)
801         retfiles[count++] = files[i];
802
803     return retfiles;
804   }
805
806   /**
807    * This method returns a array of <code>String</code>'s representing the
808    * list of files is then directory represented by this object.  If this
809    * object represents a non-directory file or a non-existent file, then
810    * <code>null</code> is returned.  The list of files will not contain
811    * any names such as "." or ".." which indicate the current or parent
812    * directory.  Also, the names are not guaranteed to be sorted.
813    * <p>
814    * A <code>SecurityManager</code> check is made prior to reading the
815    * directory.  If read access to the directory is denied, an exception
816    * will be thrown.
817    *
818    * @return An array of files in the directory, or <code>null</code> if 
819    * this object does not represent a valid directory.
820    * 
821    * @exception SecurityException If read access is not allowed to the 
822    * directory by the <code>SecurityManager</code>
823    */
824   public String[] list()
825   {
826     return list(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    * A <code>SecurityManager</code> check is made prior to reading the
837    * directory.  If read access to the directory is denied, an exception
838    * will be thrown.
839    *
840    * @return An array of <code>File</code> objects for this directory.
841    *
842    * @exception SecurityException If the <code>SecurityManager</code> denies
843    * access to this directory.
844    *
845    * @since 1.2
846    */
847   public File[] listFiles()
848   {
849     return listFiles((FilenameFilter) null);
850   }
851   
852   /**
853    * This method returns an array of <code>File</code> objects representing
854    * all the files in the directory represented by this object. If this
855    * object does not represent a directory, <code>null</code> is returned.
856    * Each of the returned <code>File</code> object is constructed with this
857    * object as its parent.
858    * <p> 
859    * In this form of the <code>listFiles()</code> method, a filter is specified
860    * that allows the caller to control which files are returned in the
861    * list.  The <code>FilenameFilter</code> specified is called for each
862    * file returned to determine whether or not that file should be included
863    * in the list.
864    * <p>
865    * A <code>SecurityManager</code> check is made prior to reading the
866    * directory.  If read access to the directory is denied, an exception
867    * will be thrown.
868    *
869    * @return An array of <code>File</code> objects for this directory.
870    *
871    * @exception SecurityException If the <code>SecurityManager</code> denies
872    * access to this directory.
873    *
874    * @since 1.2
875    */
876   public File[] listFiles(FilenameFilter filter)
877   {
878     String[] filelist = list(filter);
879     
880     if (filelist == null)
881       return null;
882
883     File[] fobjlist = new File [filelist.length];
884
885     for (int i = 0; i < filelist.length; i++)
886       fobjlist [i] = new File(this, filelist [i]);
887
888     return fobjlist;
889   }
890
891   /**
892    * This method returns an array of <code>File</code> objects representing
893    * all the files in the directory represented by this object. If this
894    * object does not represent a directory, <code>null</code> is returned.
895    * Each of the returned <code>File</code> object is constructed with this
896    * object as its parent.
897    * <p> 
898    * In this form of the <code>listFiles()</code> method, a filter is specified
899    * that allows the caller to control which files are returned in the
900    * list.  The <code>FileFilter</code> specified is called for each
901    * file returned to determine whether or not that file should be included
902    * in the list.
903    * <p>
904    * A <code>SecurityManager</code> check is made prior to reading the
905    * directory.  If read access to the directory is denied, an exception
906    * will be thrown.
907    *
908    * @return An array of <code>File</code> objects for this directory.
909    *
910    * @exception SecurityException If the <code>SecurityManager</code> denies
911    * access to this directory.
912    *
913    * @since 1.2
914    */
915   public File[] listFiles(FileFilter filter)
916   {
917     File[] fobjlist = listFiles((FilenameFilter) null);
918
919     if (fobjlist == null)
920       return null;
921
922     if (filter == null)
923       return fobjlist;
924
925     int count = 0;
926     for (int i = 0; i < fobjlist.length; i++)
927       if (filter.accept(fobjlist[i]) == true)
928         ++count;
929
930     File[] final_list = new File[count];
931     count = 0;
932     for (int i = 0; i < fobjlist.length; i++)
933       if (filter.accept(fobjlist[i]) == true)
934         {
935           final_list[count] = fobjlist[i];
936           ++count;
937         }
938
939     return final_list;
940   }
941
942   /**
943    * This method returns a <code>String</code> that is the path name of the
944    * file as returned by <code>getPath</code>.
945    *
946    * @return A <code>String</code> representation of this file
947    */
948   public String toString()
949   {
950     return path;
951   }
952
953   /**
954    * @return A <code>URI</code> for this object.
955    */
956   public URI toURI()
957   {
958     String abspath = getAbsolutePath();
959        
960     if (isDirectory() || path.equals(""))
961       abspath = abspath + separatorChar;
962
963     if (separatorChar == '\\')
964       abspath = separatorChar + abspath;
965         
966     try
967       {
968         return new URI("file", null, null, -1,
969                        abspath.replace(separatorChar, '/'),
970                        null, null);
971       }
972     catch (URISyntaxException use)
973       {
974         // Can't happen.
975         throw (InternalError) new InternalError("Unconvertible file: "
976                                                 + this).initCause(use);
977       }
978   }
979
980   /**
981    * This method returns a <code>URL</code> with the <code>file:</code>
982    * protocol that represents this file.  The exact form of this URL is
983    * system dependent.
984    *
985    * @return A <code>URL</code> for this object.
986    *
987    * @exception MalformedURLException If the URL cannot be created 
988    * successfully.
989    */
990   public URL toURL() throws MalformedURLException
991   {
992     return VMFile.toURL(this);
993   }
994
995
996   /**
997    * This method creates a directory for the path represented by this object.
998    *
999    * @return <code>true</code> if the directory was created, 
1000    * <code>false</code> otherwise
1001    *
1002    * @exception SecurityException If write access is not allowed to this file
1003    */
1004   public boolean mkdir()
1005   {
1006     checkWrite();
1007     return VMFile.mkdir(path);
1008   }
1009
1010   /**
1011    * This method creates a directory for the path represented by this file.
1012    * It will also create any intervening parent directories if necessary.
1013    *
1014    * @return <code>true</code> if the directory was created, 
1015    * <code>false</code> otherwise
1016    *
1017    * @exception SecurityException If write access is not allowed to this file
1018    */
1019   public boolean mkdirs()
1020   {
1021     String parent = getParent();
1022     if (parent == null)
1023       {
1024         return mkdir();
1025       }
1026       
1027     File f = new File(parent);
1028     if (!f.exists())
1029       {
1030         boolean rc = f.mkdirs();
1031         if (rc == false)
1032           return false;
1033       }
1034
1035     return mkdir();
1036   }
1037
1038   /**
1039    * This method creates a temporary file in the specified directory.  If 
1040    * the directory name is null, then this method uses the system temporary 
1041    * directory. The files created are guaranteed not to currently exist and 
1042    * the same file name will never be used twice in the same virtual 
1043    * machine instance.  
1044    * The system temporary directory is determined by examinging the 
1045    * <code>java.io.tmpdir</code> system property.
1046    * <p>
1047    * The <code>prefix</code> parameter is a sequence of at least three
1048    * characters that are used as the start of the generated filename.  The
1049    * <code>suffix</code> parameter is a sequence of characters that is used
1050    * to terminate the file name.  This parameter may be <code>null</code>
1051    * and if it is, the suffix defaults to ".tmp".
1052    * <p>
1053    * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code>
1054    * method is used to verify that this operation is permitted.
1055    *
1056    * @param prefix The character prefix to use in generating the path name.
1057    * @param suffix The character suffix to use in generating the path name.
1058    * @param directory The directory to create the file in, or 
1059    * <code>null</code> for the default temporary directory
1060    *
1061    * @exception IllegalArgumentException If the patterns is not valid
1062    * @exception SecurityException If there is no permission to perform 
1063    * this operation
1064    * @exception IOException If an error occurs
1065    *
1066    * @since 1.2
1067    */
1068   public static synchronized File createTempFile(String prefix, String suffix,
1069                                     File directory)
1070     throws IOException
1071   {
1072     // Grab the system temp directory if necessary
1073     if (directory == null)
1074       {
1075         String dirname = System.getProperty("java.io.tmpdir");
1076         if (dirname == null)
1077           throw new IOException("Cannot determine system temporary directory"); 
1078         
1079         directory = new File(dirname);
1080         if (! VMFile.exists(directory.path))
1081           throw new IOException("System temporary directory "
1082                                 + directory.getName() + " does not exist.");
1083         if (! VMFile.isDirectory(directory.path))
1084           throw new IOException("System temporary directory "
1085                                 + directory.getName()
1086                                 + " is not really a directory.");
1087       }
1088
1089     // Check if prefix is at least 3 characters long
1090     if (prefix.length() < 3)
1091       throw new IllegalArgumentException("Prefix too short: " + prefix);
1092
1093     // Set default value of suffix
1094     if (suffix == null)
1095       suffix = ".tmp";
1096
1097     // Now identify a file name and make sure it doesn't exist.
1098     File file;
1099     if (!VMFile.IS_DOS_8_3)
1100       { 
1101         do
1102           {
1103             long now = System.currentTimeMillis();
1104             if (now > last_tmp)
1105               {
1106                 // The last temporary file was created more than 1 ms ago.
1107                 last_tmp = now;
1108                 n_created = 0;
1109               }
1110             else
1111               n_created++;
1112             
1113             String name = Long.toHexString(now);
1114             if (n_created > 0)
1115               name += '_'+Integer.toHexString(n_created);
1116             String filename = prefix + name + suffix;
1117             file = new File(directory, filename);
1118           }
1119         while (VMFile.exists(file.path));
1120       }
1121     else
1122       {
1123         // make sure prefix is not longer than 7 characters
1124         if (prefix.length() >= 8)
1125           throw new IllegalArgumentException("Prefix too long: " + prefix + "(valid length 3..7)");
1126
1127         long mask = 0x000000ffffFFFFL >> (prefix.length() * 4);
1128         do
1129           {
1130             int n = (int) (System.currentTimeMillis() & mask);
1131             String filename = prefix + java.lang.Integer.toHexString(n) + suffix;
1132             file = new File(directory, filename);
1133           }
1134         while (VMFile.exists(file.path));
1135       }
1136
1137     // Verify that we are allowed to create this file
1138     SecurityManager sm = System.getSecurityManager();
1139     if (sm != null)
1140       sm.checkWrite(file.getAbsolutePath());
1141
1142     // Now create the file and return our file object
1143     // XXX - FIXME race condition.
1144     VMFile.create(file.getAbsolutePath()); 
1145     return file;
1146   }
1147
1148   /**
1149    * This method sets the owner's read permission for the File represented by
1150    * this object.
1151    * 
1152    * It is the same as calling <code>setReadable(readable, true)</code>.
1153    * 
1154    * @param <code>readable</code> <code>true</code> to set read permission,
1155    * <code>false</code> to unset the read permission.
1156    * @return <code>true</code> if the file permissions are changed,
1157    * <code>false</code> otherwise.
1158    * @exception SecurityException If write access of the file is not permitted.
1159    * @see #setReadable(boolean, boolean)
1160    * @since 1.6
1161    */
1162   public boolean setReadable(boolean readable)
1163   {
1164     return setReadable(readable, true);
1165   }
1166   
1167   /**
1168    * This method sets the read permissions for the File represented by
1169    * this object.
1170    * 
1171    * If <code>ownerOnly</code> is set to <code>true</code> then only the
1172    * read permission bit for the owner of the file is changed.
1173    * 
1174    * If <code>ownerOnly</code> is set to <code>false</code>, the file
1175    * permissions are changed so that the file can be read by everyone.
1176    * 
1177    * On unix like systems this sets the <code>user</code>, <code>group</code>
1178    * and <code>other</code> read bits and is equal to call
1179    * <code>chmod a+r</code> on the file.
1180    * 
1181    * @param <code>readable</code> <code>true</code> to set read permission,
1182    * <code>false</code> to unset the read permission.
1183    * @param <code>ownerOnly</code> <code>true</code> to set read permission
1184    * for owner only, <code>false</code> for all.
1185    * @return <code>true</code> if the file permissions are changed,
1186    * <code>false</code> otherwise.
1187    * @exception SecurityException If write access of the file is not permitted.
1188    * @see #setReadable(boolean)
1189    * @since 1.6
1190    */
1191   public boolean setReadable(boolean readable, boolean ownerOnly)
1192   {
1193     checkWrite();
1194     return VMFile.setReadable(path, readable, ownerOnly);
1195   }
1196   
1197   /**
1198    * This method sets the owner's write permission for the File represented by
1199    * this object.
1200    * 
1201    * It is the same as calling <code>setWritable(readable, true)</code>. 
1202    * 
1203    * @param <code>writable</code> <code>true</code> to set write permission,
1204    * <code>false</code> to unset write permission.
1205    * @return <code>true</code> if the file permissions are changed,
1206    * <code>false</code> otherwise.
1207    * @exception SecurityException If write access of the file is not permitted.
1208    * @see #setWritable(boolean, boolean)
1209    * @since 1.6
1210    */
1211   public boolean setWritable(boolean writable)
1212   {
1213     return setWritable(writable, true);
1214   }
1215   
1216   /**
1217    * This method sets the write permissions for the File represented by
1218    * this object.
1219    * 
1220    * If <code>ownerOnly</code> is set to <code>true</code> then only the
1221    * write permission bit for the owner of the file is changed.
1222    * 
1223    * If <code>ownerOnly</code> is set to <code>false</code>, the file
1224    * permissions are changed so that the file can be written by everyone.
1225    * 
1226    * On unix like systems this set the <code>user</code>, <code>group</code>
1227    * and <code>other</code> write bits and is equal to call
1228    * <code>chmod a+w</code> on the file.
1229    * 
1230    * @param <code>writable</code> <code>true</code> to set write permission,
1231    * <code>false</code> to unset write permission.
1232    * @param <code>ownerOnly</code> <code>true</code> to set write permission
1233    * for owner only, <code>false</code> for all. 
1234    * @return <code>true</code> if the file permissions are changed,
1235    * <code>false</code> otherwise.
1236    * @exception SecurityException If write access of the file is not permitted.
1237    * @see #setWritable(boolean)
1238    * @since 1.6
1239    */
1240   public boolean setWritable(boolean writable, boolean ownerOnly)
1241   {
1242     checkWrite();
1243     return VMFile.setWritable(path, writable, ownerOnly);
1244   }
1245   
1246   /**
1247    * This method sets the owner's execute permission for the File represented
1248    * by this object.
1249    * 
1250    * It is the same as calling <code>setExecutable(readable, true)</code>. 
1251    * 
1252    * @param <code>executable</code> <code>true</code> to set execute permission,
1253    * <code>false</code> to unset execute permission.
1254    * @return <code>true</code> if the file permissions are changed,
1255    * <code>false</code> otherwise.
1256    * @exception SecurityException If write access of the file is not permitted.
1257    * @see #setExecutable(boolean, boolean)
1258    * @since 1.6
1259    */
1260   public boolean setExecutable(boolean executable) 
1261   {
1262     return setExecutable(executable, true);
1263   }
1264   
1265   /**
1266    * This method sets the execute permissions for the File represented by
1267    * this object.
1268    * 
1269    * If <code>ownerOnly</code> is set to <code>true</code> then only the
1270    * execute permission bit for the owner of the file is changed.
1271    * 
1272    * If <code>ownerOnly</code> is set to <code>false</code>, the file
1273    * permissions are changed so that the file can be executed by everyone.
1274    * 
1275    * On unix like systems this set the <code>user</code>, <code>group</code>
1276    * and <code>other</code> write bits and is equal to call
1277    * <code>chmod a+x</code> on the file.
1278    * 
1279    * @param <code>executable</code> <code>true</code> to set write permission,
1280    * <code>false</code> to unset write permission.
1281    * @param <code>ownerOnly</code> <code>true</code> to set write permission
1282    * for owner only, <code>false</code> for all. 
1283    * @return <code>true</code> if the file permissions are changed,
1284    * <code>false</code> otherwise.
1285    * @exception SecurityException If write access of the file is not permitted.
1286    * @see #setExecutable(boolean)
1287    * @since 1.6
1288    */
1289   public boolean setExecutable(boolean executable, boolean ownerOnly)
1290   {
1291     checkWrite();
1292     return VMFile.setExecutable(path, executable, ownerOnly);
1293   }
1294
1295   /**
1296    * This method sets the file represented by this object to be read only.
1297    * A read only file or directory cannot be modified.  Please note that 
1298    * GNU systems allow read only files to be deleted if the directory it
1299    * is contained in is writable.
1300    *
1301    * @return <code>true</code> if the operation succeeded, <code>false</code>
1302    * otherwise.
1303    *
1304    * @exception SecurityException If the <code>SecurityManager</code> does
1305    * not allow this operation.
1306    *
1307    * @since 1.2
1308    */
1309   public boolean setReadOnly()
1310   {
1311     // Do a security check before trying to do anything else.
1312     checkWrite();
1313
1314     // Test for existence.
1315     if (! VMFile.exists(path))
1316       return false;
1317
1318     return VMFile.setReadOnly(path);
1319   }
1320
1321   /**
1322    * This method returns an array of filesystem roots.  Some operating systems
1323    * have volume oriented filesystem.  This method provides a mechanism for
1324    * determining which volumes exist.  GNU systems use a single hierarchical
1325    * filesystem, so will have only one "/" filesystem root.
1326    *
1327    * @return An array of <code>File</code> objects for each filesystem root
1328    * available.
1329    *
1330    * @since 1.2
1331    */
1332   public static File[] listRoots()
1333   {
1334     File[] roots = VMFile.listRoots();
1335     
1336     SecurityManager s = System.getSecurityManager();
1337     if (s != null)
1338       {
1339         // Only return roots to which the security manager permits read access.
1340         int count = roots.length;
1341         for (int i = 0; i < roots.length; i++)
1342           {
1343             try
1344               {
1345                 s.checkRead (roots[i].path);            
1346               }
1347             catch (SecurityException sx)
1348               {
1349                 roots[i] = null;
1350                 count--;
1351               }
1352           }
1353         if (count != roots.length)
1354           {
1355             File[] newRoots = new File[count];
1356             int k = 0;
1357             for (int i = 0; i < roots.length; i++)
1358               {
1359                 if (roots[i] != null)
1360                   newRoots[k++] = roots[i];
1361               }
1362             roots = newRoots;
1363           }
1364       }
1365     return roots;
1366   }
1367
1368   /**
1369    * This method creates a temporary file in the system temporary directory. 
1370    * The files created are guaranteed not to currently exist and the same file
1371    * name will never be used twice in the same virtual machine instance.  The
1372    * system temporary directory is determined by examinging the 
1373    * <code>java.io.tmpdir</code> system property.
1374    * <p>
1375    * The <code>prefix</code> parameter is a sequence of at least three
1376    * characters that are used as the start of the generated filename.  The
1377    * <code>suffix</code> parameter is a sequence of characters that is used
1378    * to terminate the file name.  This parameter may be <code>null</code>
1379    * and if it is, the suffix defaults to ".tmp".
1380    * <p>
1381    * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code>
1382    * method is used to verify that this operation is permitted.
1383    * <p>
1384    * This method is identical to calling 
1385    * <code>createTempFile(prefix, suffix, null)</code>.
1386    *
1387    * @param prefix The character prefix to use in generating the path name.
1388    * @param suffix The character suffix to use in generating the path name.
1389    *
1390    * @exception IllegalArgumentException If the prefix or suffix are not valid.
1391    * @exception SecurityException If there is no permission to perform 
1392    * this operation
1393    * @exception IOException If an error occurs
1394    */
1395   public static File createTempFile(String prefix, String suffix)
1396     throws IOException
1397   {
1398     return createTempFile(prefix, suffix, null);
1399   }
1400
1401   /**
1402    * This method compares the specified <code>File</code> to this one
1403    * to test for equality.  It does this by comparing the canonical path names
1404    * of the files. 
1405    * <p>
1406    * The canonical paths of the files are determined by calling the
1407    * <code>getCanonicalPath</code> method on each object.
1408    * <p>
1409    * This method returns a 0 if the specified <code>Object</code> is equal
1410    * to this one, a negative value if it is less than this one 
1411    * a positive value if it is greater than this one.
1412    *
1413    * @return An integer as described above
1414    *
1415    * @since 1.2
1416    */
1417   public int compareTo(File other)
1418   {
1419     if (VMFile.IS_CASE_SENSITIVE)
1420       return path.compareTo (other.path);
1421     else
1422       return path.compareToIgnoreCase (other.path);
1423   }
1424
1425   /**
1426    * This method renames the file represented by this object to the path
1427    * of the file represented by the argument <code>File</code>.
1428    *
1429    * @param dest The <code>File</code> object representing the target name
1430    *
1431    * @return <code>true</code> if the rename succeeds, <code>false</code> 
1432    * otherwise.
1433    *
1434    * @exception SecurityException If write access is not allowed to the 
1435    * file by the <code>SecurityMananger</code>.
1436    */
1437   public synchronized boolean renameTo(File dest)
1438   {
1439     checkWrite();
1440     dest.checkWrite();
1441     // Call our native rename method
1442     return VMFile.renameTo(path, dest.path);
1443   }
1444
1445   /**
1446    * This method sets the modification time on the file to the specified
1447    * value.  This is specified as the number of seconds since midnight
1448    * on January 1, 1970 GMT.
1449    *
1450    * @param time The desired modification time.
1451    *
1452    * @return <code>true</code> if the operation succeeded, <code>false</code>
1453    * otherwise.
1454    *
1455    * @exception IllegalArgumentException If the specified time is negative.
1456    * @exception SecurityException If the <code>SecurityManager</code> will
1457    * not allow this operation.
1458    *
1459    * @since 1.2
1460    */
1461   public boolean setLastModified(long time) 
1462   {
1463     if (time < 0)
1464       throw new IllegalArgumentException("Negative modification time: " + time);
1465
1466     checkWrite();
1467     return VMFile.setLastModified(path, time);
1468   }
1469
1470   private void checkWrite()
1471   {
1472     // Check the SecurityManager
1473     SecurityManager s = System.getSecurityManager();
1474     
1475     if (s != null)
1476       s.checkWrite(path);
1477   }
1478
1479   private void checkRead()
1480   {
1481     // Check the SecurityManager
1482     SecurityManager s = System.getSecurityManager();
1483     
1484     if (s != null)
1485       s.checkRead(path);
1486   }
1487
1488   private void checkExec()
1489   {
1490     // Check the SecurityManager
1491     SecurityManager s = System.getSecurityManager();
1492     
1493     if (s != null)
1494       s.checkExec(path);
1495   }
1496   
1497   /** 
1498    * Calling this method requests that the file represented by this object
1499    * be deleted when the virtual machine exits.  Note that this request cannot
1500    * be cancelled.  Also, it will only be carried out if the virtual machine
1501    * exits normally.
1502    *
1503    * @exception SecurityException If deleting of the file is not allowed
1504    *
1505    * @since 1.2 
1506    */
1507   public void deleteOnExit()
1508   {
1509     // Check the SecurityManager
1510     SecurityManager sm = System.getSecurityManager();
1511     if (sm != null)
1512       sm.checkDelete(path);
1513
1514     DeleteFileHelper.add(this);
1515   }
1516
1517   private void writeObject(ObjectOutputStream oos) throws IOException
1518   {
1519     oos.defaultWriteObject();
1520     oos.writeChar(separatorChar);
1521   }
1522
1523   private void readObject(ObjectInputStream ois)
1524     throws ClassNotFoundException, IOException
1525   {
1526     ois.defaultReadObject();
1527
1528     // If the file was from an OS with a different dir separator,
1529     // fixup the path to use the separator on this OS.
1530     char oldSeparatorChar = ois.readChar();
1531     
1532     if (oldSeparatorChar != separatorChar)
1533       path = path.replace(oldSeparatorChar, separatorChar);
1534   }
1535   
1536 } // class File
1537