OSDN Git Service

1.3-Compliant Implementation of java.io.File.
[pf3gnuchains/gcc-fork.git] / libjava / java / io / File.java
1 // File.java - File name
2
3 /* Copyright (C) 1998, 1999, 2000, 2001  Free Software Foundation
4
5    This file is part of libgcj.
6
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
9 details.  */
10
11 package java.io;
12
13 import java.util.*;
14 import java.net.*;
15 import gnu.gcj.runtime.FileDeleter;
16
17 /**
18  * @author Tom Tromey <tromey@cygnus.com>
19  * @date September 24, 1998 
20  */
21
22 /* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3
23  * "The Java Language Specification", ISBN 0-201-63451-1
24  * Status:  Complete to version 1.3.
25  */
26
27 public class File implements Serializable, Comparable
28 {
29   public boolean canRead ()
30   {
31     checkRead();
32     return access (READ);
33   }
34
35   public boolean canWrite ()
36   {
37     checkWrite();
38     return access (WRITE);
39   }
40   
41   private native boolean performCreate() throws IOException;
42
43   /** @since 1.2 */
44   public boolean createNewFile() throws IOException
45   {
46     checkWrite();
47     return performCreate();
48   }
49   
50   private native boolean performDelete ();
51   public boolean delete ()
52   {
53     SecurityManager s = System.getSecurityManager();
54     String name = path;
55     if (s != null)
56       s.checkDelete(path);
57     return performDelete ();
58   }
59
60   public boolean equals (Object obj)
61   {
62     if (! (obj instanceof File))
63       return false;
64     File other = (File) obj;
65     if (caseSensitive)
66       return (path.equals(other.path));
67     else
68       return (path.equalsIgnoreCase(other.path));      
69   }
70
71   public boolean exists ()
72   {
73     checkRead();
74     return access (EXISTS);
75   }
76
77   public File (String p)
78   {
79     if (p == null)
80       throw new NullPointerException ();
81     path = p;
82   }
83
84   public File (String dirPath, String name)
85   {
86     if (name == null)
87       throw new NullPointerException ();
88     if (dirPath != null && dirPath.length() > 0)
89       {
90         // Try to be smart about the number of separator characters.
91         if (dirPath.charAt(dirPath.length() - 1) == separatorChar)
92           path = dirPath + name;
93         else
94           path = dirPath + separatorChar + name;
95       }
96     else
97       path = name;
98   }
99
100   public File (File dir, String name)
101   {
102     this (dir == null ? null : dir.path, name);
103   }
104
105   // FIXME  ???
106   public String getAbsolutePath ()
107   {
108     if (isAbsolute ())
109       return path;
110     return System.getProperty("user.dir") + separatorChar + path;
111   }
112
113   /** @since 1.2 */
114   public File getAbsoluteFile () throws IOException
115   {
116     return new File (getAbsolutePath());
117   }
118
119   public native String getCanonicalPath () throws IOException;
120
121   /** @since 1.2 */
122   public File getCanonicalFile () throws IOException
123   {
124     return new File (getCanonicalPath());
125   }
126
127   public String getName ()
128   {
129     int last = path.lastIndexOf(separatorChar);
130     return path.substring(last + 1);
131   }
132
133   public String getParent ()
134   {
135     int last = path.lastIndexOf(separatorChar);
136     if (last == -1)
137       return null;
138     return path.substring(0, last);
139   }
140
141   /** @since 1.2 */
142   public File getParentFile ()
143   {
144     String parent = getParent ();
145     return (parent == null ? null : new File (parent));
146   }
147
148   public String getPath ()
149   {
150     return path;
151   }
152
153   public int hashCode ()
154   {
155     if (caseSensitive)
156       return (path.hashCode() ^ 1234321);
157     else
158       return (path.toLowerCase().hashCode() ^ 1234321);
159   }
160
161   public native boolean isAbsolute ();
162
163   public boolean isDirectory ()
164   {
165     checkRead();
166     return stat (DIRECTORY);
167   }
168
169   public boolean isFile ()
170   {
171     checkRead();
172     return stat (ISFILE);
173   }
174
175   /** @since 1.2 */
176   public boolean isHidden()
177   {
178     checkRead();
179     return stat (ISHIDDEN);
180   }
181
182   public long lastModified ()
183   {
184     checkRead();
185     return attr (MODIFIED);
186   }
187
188   public long length ()
189   {
190     checkRead();
191     return attr (LENGTH);
192   }
193     
194   private final native Object[] performList (FilenameFilter filter,
195                                              FileFilter fileFilter,
196                                              Class result_type);
197
198   // Arguments for the performList function. Specifies whether we want
199   // File objects or path strings in the returned object array.
200   private final static int OBJECTS = 0;
201   private final static int STRINGS = 1;
202
203   public String[] list (FilenameFilter filter)
204   {
205     checkRead();
206     return (String[]) performList (filter, null, String.class);
207   }
208
209   public String[] list ()
210   {
211     checkRead();
212     return (String[]) performList (null, null, String.class);
213   }
214
215   /** @since 1.2 */
216   public File[] listFiles()
217   {
218     checkRead();
219     return (File[]) performList (null, null, File.class);
220   }
221   
222   /** @since 1.2 */
223   public File[] listFiles(FilenameFilter filter)
224   {
225     checkRead();
226     return (File[]) performList (filter, null, File.class);
227   }
228   
229   /** @since 1.2 */
230   public File[] listFiles(FileFilter filter)
231   {
232     checkRead();
233     return (File[]) performList (null, filter, File.class);
234   }
235
236   public String toString ()
237   {
238     return path;
239   }
240
241   public URL toURL () throws MalformedURLException
242   {
243     return new URL ("file:" + path + (isDirectory() ? "/" : ""));
244   }
245
246   private final native boolean performMkdir ();
247
248   public boolean mkdir ()
249   {
250     checkWrite();
251     return performMkdir ();
252   }
253
254   private static boolean mkdirs (File x)
255   {
256     if (x.isDirectory())
257       return true;
258     String p = x.getPath();
259     String parent = x.getParent();
260     if (parent != null)
261       {
262         x.path = parent;
263         if (! mkdirs (x))
264           return false;
265         x.path = p;
266       }
267     return x.mkdir();
268   }
269
270   public boolean mkdirs ()
271   {
272     checkWrite();
273     if (isDirectory ())
274       return false;
275     return mkdirs (new File (path));
276   }
277
278   private static synchronized String nextValue ()
279   {
280     return Long.toString(counter++, Character.MAX_RADIX);
281   }
282
283   /** @since 1.2 */
284   public static File createTempFile (String prefix, String suffix,
285                                      File directory)
286     throws IOException
287   {
288     // Grab the system temp directory if necessary
289     if (directory == null)
290       {
291         String dirname = tmpdir;
292         if (dirname == null)
293           throw 
294             new IOException("Cannot determine system temporary directory"); 
295         
296         directory = new File(dirname);
297         if (!directory.exists())
298           throw new IOException("System temporary directory " 
299                                 + directory.getName() + " does not exist.");
300         if (!directory.isDirectory())
301           throw new IOException("System temporary directory " 
302                                 + directory.getName() 
303                                 + " is not really a directory.");
304       }
305
306     if (prefix.length () < 3)
307       throw new IllegalArgumentException ("Prefix too short: " + prefix);
308     if (suffix == null)
309       suffix = ".tmp";
310
311     // Truncation rules.
312     // `6' is the number of characters we generate.
313     if (prefix.length () + 6 + suffix.length () > maxPathLen)
314       {
315         int suf_len = 0;
316         if (suffix.charAt(0) == '.')
317           suf_len = 4;
318         suffix = suffix.substring(0, suf_len);
319         if (prefix.length () + 6 + suf_len > maxPathLen)
320           prefix = prefix.substring(0, maxPathLen - 6 - suf_len);
321       }
322
323     File f;
324
325     // How many times should we try?  We choose 100.
326     for (int i = 0; i < 100; ++i)
327       {
328         // This is ugly.
329         String t = "ZZZZZZ" + nextValue ();
330         String l = prefix + t.substring(t.length() - 6) + suffix;
331         try
332           {
333             f = new File(directory, l);
334             if (f.createNewFile())
335               return f;
336           }
337         catch (IOException ignored)
338           {
339           }
340       }
341
342     throw new IOException ("cannot create temporary file");
343   }
344
345   private native boolean performSetReadOnly();
346
347   /** @since 1.2 */
348   public boolean setReadOnly()
349   {
350     checkWrite();
351     return performSetReadOnly();
352   }
353
354   private static native File[] performListRoots();
355
356   /** @since 1.2 */
357   public static File[] listRoots()
358   {
359     File[] roots = performListRoots();
360     
361     SecurityManager s = System.getSecurityManager();
362     if (s != null)
363       {
364         // Only return roots to which the security manager permits read access.
365         int count = roots.length;
366         for (int i = 0; i < roots.length; i++)
367           {
368             try
369               {
370                 s.checkRead(roots[i].path);             
371               }
372             catch (SecurityException sx)
373               {
374                 roots[i] = null;
375                 count--;
376               }
377           }
378         if (count != roots.length)
379           {
380             File[] newRoots = new File[count];
381             int k = 0;
382             for (int i=0; i < roots.length; i++)
383               {
384                 if (roots[i] != null)
385                   newRoots[k++] = roots[i];
386               }
387             roots = newRoots;
388           }
389       }
390     return roots;
391   }
392
393   public static File createTempFile (String prefix, String suffix)
394     throws IOException
395   {
396     return createTempFile (prefix, suffix, null);
397   }
398
399   /** @since 1.2 */
400   public int compareTo(File other)
401   {
402     if (caseSensitive)
403       return path.compareTo (other.path);
404     else
405       return path.compareToIgnoreCase (other.path);
406   }
407
408   /** @since 1.2 */
409   public int compareTo(Object o)
410   {
411     File other = (File) o;
412     return compareTo (other);
413   }
414
415   private native boolean performRenameTo (File dest);
416   public boolean renameTo (File dest)
417   {
418     SecurityManager s = System.getSecurityManager();
419     String sname = getName();
420     String dname = dest.getName();
421     if (s != null)
422       {
423         s.checkWrite(sname);
424         s.checkWrite(dname);
425       }
426     return performRenameTo (dest);
427   }
428
429   private native boolean performSetLastModified(long time);
430   
431   /** @since 1.2 */
432   public boolean setLastModified(long time)
433   {
434     checkWrite();
435     return performSetLastModified(time);
436   }
437
438   public static final String separator = null;
439   public static final String pathSeparator = null;
440   static final String tmpdir = null;
441   static int maxPathLen;
442   static boolean caseSensitive;
443   
444   public static final char separatorChar;
445   public static final char pathSeparatorChar;
446   
447   static
448   {
449     init_native();
450     pathSeparatorChar = pathSeparator.charAt(0);
451     separatorChar = separator.charAt(0);
452   }
453   
454   // Native function called at class initialization. This should should
455   // set the separator, pathSeparator, tmpdir, maxPathLen, and caseSensitive
456   // variables.
457   private static native void init_native();
458
459   // The path.
460   private String path;
461
462   // We keep a counter for use by createTempFile.  We choose the first
463   // value randomly to try to avoid clashes with other VMs.
464   private static long counter = Double.doubleToLongBits (Math.random ());
465
466   private void checkWrite ()
467   {
468     SecurityManager s = System.getSecurityManager();
469     if (s != null)
470       s.checkWrite(path);
471   }
472
473   private void checkRead ()
474   {
475     SecurityManager s = System.getSecurityManager();
476     if (s != null)
477       s.checkRead(path);
478   }
479
480   /** 
481     * Add this File to the set of files to be deleted upon normal
482     * termination.
483     *
484     * @since 1.2 
485     */
486   // FIXME: This should use the ShutdownHook API once we implement that.
487   public void deleteOnExit ()
488   {
489     SecurityManager sm = System.getSecurityManager ();
490     if (sm != null)
491       sm.checkDelete (getName ());
492
493     FileDeleter.add (this);
494   }
495
496   private void writeObject (ObjectOutputStream oos) throws IOException
497   {
498     oos.defaultWriteObject ();
499     oos.writeChar (separatorChar);
500   }
501
502   private void readObject (ObjectInputStream ois)
503     throws ClassNotFoundException, IOException
504   {
505     ois.defaultReadObject ();
506
507     // If the file was from an OS with a different dir separator,
508     // fixup the path to use the separator on this OS.
509     char oldSeparatorChar = ois.readChar ();
510     if (oldSeparatorChar != separatorChar)
511       path = path.replace (oldSeparatorChar, separatorChar);
512   }
513
514   // QUERY arguments to access function.
515   private final static int READ = 0;
516   private final static int WRITE = 1;
517   private final static int EXISTS = 2;
518
519   // QUERY arguments to stat function.
520   private final static int DIRECTORY = 0;
521   private final static int ISFILE = 1;
522   private final static int ISHIDDEN = 2;
523
524   // QUERY arguments to attr function.
525   private final static int MODIFIED = 0;
526   private final static int LENGTH = 1;
527   
528   private final native long attr (int query);
529   private final native boolean access (int query);
530   private final native boolean stat (int query);
531
532   private static final long serialVersionUID = 301077366599181567L;
533 }