Source for java.io.File

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