OSDN Git Service

Fix for PR libgcj/4481:
[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     path = normalizePath(p);
80   }
81
82   // Remove duplicate and redundant separator characters.
83   private String normalizePath(String p)
84   {
85     int dupIndex = p.indexOf(dupSeparator);
86     int plen = p.length();
87
88     // Special case: permit Windows UNC path prefix.
89     if (dupSeparator.equals("\\\\") && dupIndex == 0)
90       dupIndex = p.indexOf(dupSeparator, 1);
91
92     if (dupIndex == -1)
93       {
94         // Ignore trailing separator.
95         if (plen > 1 && p.charAt(plen - 1) == separatorChar)
96           return p.substring(0, plen - 1);
97         else
98           return p;
99       }
100     
101     StringBuffer newpath = new StringBuffer(plen);
102     int last = 0;
103     while (dupIndex != -1)
104       {
105         newpath.append(p.substring(last, dupIndex));
106         // Ignore the duplicate path characters.
107         while (p.charAt(dupIndex) == separatorChar)
108           {
109             dupIndex++;
110             if (dupIndex == plen)
111               return newpath.toString();
112           }
113         newpath.append(separatorChar);
114         last = dupIndex;
115         dupIndex = p.indexOf(dupSeparator, last);
116       }
117     
118     // Again, ignore possible trailing separator.
119     int end;
120     if (plen > 1 && p.charAt(plen - 1) == separatorChar)
121       end = plen - 1;
122     else
123       end = plen;
124     newpath.append(p.substring(last, end));
125     
126     return newpath.toString();
127   }
128   
129   public File (String dirPath, String name)
130   {
131     if (name == null)
132       throw new NullPointerException ();
133     if (dirPath != null && dirPath.length() > 0)
134       {
135         // Try to be smart about the number of separator characters.
136         if (dirPath.charAt(dirPath.length() - 1) == separatorChar
137             || name.length() == 0)
138           path = normalizePath(dirPath + name);
139         else
140           path = normalizePath(dirPath + separatorChar + name);
141       }
142     else
143       path = normalizePath(name);
144   }
145
146   public File (File dir, String name)
147   {
148     this (dir == null ? null : dir.path, name);
149   }
150
151   // FIXME  ???
152   public String getAbsolutePath ()
153   {
154     if (isAbsolute ())
155       return path;
156     return System.getProperty("user.dir") + separatorChar + path;
157   }
158
159   /** @since 1.2 */
160   public File getAbsoluteFile ()
161   {
162     return new File (getAbsolutePath());
163   }
164
165   public native String getCanonicalPath () throws IOException;
166
167   /** @since 1.2 */
168   public File getCanonicalFile () throws IOException
169   {
170     return new File (getCanonicalPath());
171   }
172
173   public String getName ()
174   {
175     int last = path.lastIndexOf(separatorChar);
176     return path.substring(last + 1);
177   }
178
179   public String getParent ()
180   {
181     int last = path.lastIndexOf(separatorChar);
182     if (last == -1)
183       return null;
184     // FIXME: POSIX assumption.
185     if (last == 0 && path.charAt (0) == '/')
186       ++last;
187     return path.substring(0, last);
188   }
189
190   /** @since 1.2 */
191   public File getParentFile ()
192   {
193     String parent = getParent ();
194     return (parent == null ? null : new File (parent));
195   }
196
197   public String getPath ()
198   {
199     return path;
200   }
201
202   public int hashCode ()
203   {
204     if (caseSensitive)
205       return (path.hashCode() ^ 1234321);
206     else
207       return (path.toLowerCase().hashCode() ^ 1234321);
208   }
209
210   public native boolean isAbsolute ();
211
212   public boolean isDirectory ()
213   {
214     checkRead();
215     return _stat (DIRECTORY);
216   }
217
218   public boolean isFile ()
219   {
220     checkRead();
221     return _stat (ISFILE);
222   }
223
224   /** @since 1.2 */
225   public boolean isHidden()
226   {
227     checkRead();
228     return _stat (ISHIDDEN);
229   }
230
231   public long lastModified ()
232   {
233     checkRead();
234     return attr (MODIFIED);
235   }
236
237   public long length ()
238   {
239     checkRead();
240     return attr (LENGTH);
241   }
242     
243   private final native Object[] performList (FilenameFilter filter,
244                                              FileFilter fileFilter,
245                                              Class result_type);
246
247   public String[] list (FilenameFilter filter)
248   {
249     checkRead();
250     return (String[]) performList (filter, null, String.class);
251   }
252
253   public String[] list ()
254   {
255     checkRead();
256     return (String[]) performList (null, null, String.class);
257   }
258
259   /** @since 1.2 */
260   public File[] listFiles()
261   {
262     checkRead();
263     return (File[]) performList (null, null, File.class);
264   }
265   
266   /** @since 1.2 */
267   public File[] listFiles(FilenameFilter filter)
268   {
269     checkRead();
270     return (File[]) performList (filter, null, File.class);
271   }
272   
273   /** @since 1.2 */
274   public File[] listFiles(FileFilter filter)
275   {
276     checkRead();
277     return (File[]) performList (null, filter, File.class);
278   }
279
280   public String toString ()
281   {
282     return path;
283   }
284
285   public URL toURL () throws MalformedURLException
286   {
287     return new URL ("file://" + getAbsolutePath ()
288                     + (isDirectory() ? "/" : ""));
289   }
290
291   private final native boolean performMkdir ();
292
293   public boolean mkdir ()
294   {
295     checkWrite();
296     return performMkdir ();
297   }
298
299   private static boolean mkdirs (File x)
300   {
301     if (x.isDirectory())
302       return true;
303     String p = x.getPath();
304     String parent = x.getParent();
305     if (parent != null)
306       {
307         x.path = parent;
308         if (! mkdirs (x))
309           return false;
310         x.path = p;
311       }
312     return x.mkdir();
313   }
314
315   public boolean mkdirs ()
316   {
317     checkWrite();
318     if (isDirectory ())
319       return false;
320     return mkdirs (new File (path));
321   }
322
323   private static synchronized String nextValue ()
324   {
325     return Long.toString(counter++, Character.MAX_RADIX);
326   }
327
328   /** @since 1.2 */
329   public static File createTempFile (String prefix, String suffix,
330                                      File directory)
331     throws IOException
332   {
333     // Grab the system temp directory if necessary
334     if (directory == null)
335       {
336         String dirname = tmpdir;
337         if (dirname == null)
338           throw 
339             new IOException("Cannot determine system temporary directory"); 
340         
341         directory = new File(dirname);
342         if (!directory.exists())
343           throw new IOException("System temporary directory " 
344                                 + directory.getName() + " does not exist.");
345         if (!directory.isDirectory())
346           throw new IOException("System temporary directory " 
347                                 + directory.getName() 
348                                 + " is not really a directory.");
349       }
350
351     if (prefix.length () < 3)
352       throw new IllegalArgumentException ("Prefix too short: " + prefix);
353     if (suffix == null)
354       suffix = ".tmp";
355
356     // Truncation rules.
357     // `6' is the number of characters we generate.
358     if (prefix.length () + 6 + suffix.length () > maxPathLen)
359       {
360         int suf_len = 0;
361         if (suffix.charAt(0) == '.')
362           suf_len = 4;
363         suffix = suffix.substring(0, suf_len);
364         if (prefix.length () + 6 + suf_len > maxPathLen)
365           prefix = prefix.substring(0, maxPathLen - 6 - suf_len);
366       }
367
368     File f;
369
370     // How many times should we try?  We choose 100.
371     for (int i = 0; i < 100; ++i)
372       {
373         // This is ugly.
374         String t = "ZZZZZZ" + nextValue ();
375         String l = prefix + t.substring(t.length() - 6) + suffix;
376         try
377           {
378             f = new File(directory, l);
379             if (f.createNewFile())
380               return f;
381           }
382         catch (IOException ignored)
383           {
384           }
385       }
386
387     throw new IOException ("cannot create temporary file");
388   }
389
390   private native boolean performSetReadOnly();
391
392   /** @since 1.2 */
393   public boolean setReadOnly()
394   {
395     checkWrite();
396     return performSetReadOnly();
397   }
398
399   private static native File[] performListRoots();
400
401   /** @since 1.2 */
402   public static File[] listRoots()
403   {
404     File[] roots = performListRoots();
405     
406     SecurityManager s = System.getSecurityManager();
407     if (s != null)
408       {
409         // Only return roots to which the security manager permits read access.
410         int count = roots.length;
411         for (int i = 0; i < roots.length; i++)
412           {
413             try
414               {
415                 s.checkRead(roots[i].path);             
416               }
417             catch (SecurityException sx)
418               {
419                 roots[i] = null;
420                 count--;
421               }
422           }
423         if (count != roots.length)
424           {
425             File[] newRoots = new File[count];
426             int k = 0;
427             for (int i=0; i < roots.length; i++)
428               {
429                 if (roots[i] != null)
430                   newRoots[k++] = roots[i];
431               }
432             roots = newRoots;
433           }
434       }
435     return roots;
436   }
437
438   public static File createTempFile (String prefix, String suffix)
439     throws IOException
440   {
441     return createTempFile (prefix, suffix, null);
442   }
443
444   /** @since 1.2 */
445   public int compareTo(File other)
446   {
447     if (caseSensitive)
448       return path.compareTo (other.path);
449     else
450       return path.compareToIgnoreCase (other.path);
451   }
452
453   /** @since 1.2 */
454   public int compareTo(Object o)
455   {
456     File other = (File) o;
457     return compareTo (other);
458   }
459
460   private native boolean performRenameTo (File dest);
461   public boolean renameTo (File dest)
462   {
463     SecurityManager s = System.getSecurityManager();
464     String sname = getName();
465     String dname = dest.getName();
466     if (s != null)
467       {
468         s.checkWrite(sname);
469         s.checkWrite(dname);
470       }
471     return performRenameTo (dest);
472   }
473
474   private native boolean performSetLastModified(long time);
475   
476   /** @since 1.2 */
477   public boolean setLastModified(long time)
478   {
479     checkWrite();
480     return performSetLastModified(time);
481   }
482
483   public static final String pathSeparator
484     = System.getProperty("path.separator");
485   public static final char pathSeparatorChar = pathSeparator.charAt(0);
486   public static final String separator = System.getProperty("file.separator");
487   public static final char separatorChar = separator.charAt(0);
488
489   static final String tmpdir = System.getProperty("java.io.tmpdir");
490   static int maxPathLen;
491   static boolean caseSensitive;
492   static String dupSeparator = separator + separator;
493   
494   static
495   {
496     init_native();
497   }
498   
499   // Native function called at class initialization. This should should
500   // set the maxPathLen and caseSensitive variables.
501   private static native void init_native();
502
503   // The path.
504   private String path;
505
506   // We keep a counter for use by createTempFile.  We choose the first
507   // value randomly to try to avoid clashes with other VMs.
508   private static long counter = Double.doubleToLongBits (Math.random ());
509
510   private void checkWrite ()
511   {
512     SecurityManager s = System.getSecurityManager();
513     if (s != null)
514       s.checkWrite(path);
515   }
516
517   private void checkRead ()
518   {
519     SecurityManager s = System.getSecurityManager();
520     if (s != null)
521       s.checkRead(path);
522   }
523
524   /** 
525     * Add this File to the set of files to be deleted upon normal
526     * termination.
527     *
528     * @since 1.2 
529     */
530   // FIXME: This should use the ShutdownHook API once we implement that.
531   public void deleteOnExit ()
532   {
533     SecurityManager sm = System.getSecurityManager ();
534     if (sm != null)
535       sm.checkDelete (getName ());
536
537     FileDeleter.add (this);
538   }
539
540   private void writeObject (ObjectOutputStream oos) throws IOException
541   {
542     oos.defaultWriteObject ();
543     oos.writeChar (separatorChar);
544   }
545
546   private void readObject (ObjectInputStream ois)
547     throws ClassNotFoundException, IOException
548   {
549     ois.defaultReadObject ();
550
551     // If the file was from an OS with a different dir separator,
552     // fixup the path to use the separator on this OS.
553     char oldSeparatorChar = ois.readChar ();
554     if (oldSeparatorChar != separatorChar)
555       path = path.replace (oldSeparatorChar, separatorChar);
556   }
557
558   // QUERY arguments to access function.
559   private final static int READ = 0;
560   private final static int WRITE = 1;
561   private final static int EXISTS = 2;
562
563   // QUERY arguments to stat function.
564   private final static int DIRECTORY = 0;
565   private final static int ISFILE = 1;
566   private final static int ISHIDDEN = 2;
567
568   // QUERY arguments to attr function.
569   private final static int MODIFIED = 0;
570   private final static int LENGTH = 1;
571   
572   private final native long attr (int query);
573   // On OSF1 V5.0, `stat' is a macro.  It is easiest to use the name
574   // `_stat' instead.  We do the same thing for `_access' just in
575   // case.
576   private final native boolean _access (int query);
577   private final native boolean _stat (int query);
578
579   private static final long serialVersionUID = 301077366599181567L;
580 }