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