Source for java.io.File

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