0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package java.io;
0019:
0020: import java.net.URI;
0021: import java.net.URISyntaxException;
0022: import java.net.URL;
0023: import java.security.AccessController;
0024: import java.security.SecureRandom;
0025: import java.util.ArrayList;
0026: import java.util.List;
0027:
0028: import org.apache.harmony.luni.util.DeleteOnExit;
0029: import org.apache.harmony.luni.util.Msg;
0030: import org.apache.harmony.luni.util.PriviAction;
0031: import org.apache.harmony.luni.util.Util;
0032:
0033: /**
0034: * File is a class which represents a file name or directory. The file may be
0035: * absolute relative to the root directory of the file system or relative to the
0036: * current directory in which the program is running.
0037: * <p>
0038: * This class provides methods for querying/changing information about the file
0039: * and also directory listing capabilities if the File represents a directory.
0040: * <p>
0041: * When manipulating file paths, the static fields of this class may be used to
0042: * determine the platform specific separators.
0043: *
0044: * @see java.io.Serializable
0045: * @see java.lang.Comparable
0046: */
0047: public class File implements Serializable, Comparable<File> {
0048:
0049: private static final long serialVersionUID = 301077366599181567L;
0050:
0051: private static final String EMPTY_STRING = ""; //$NON-NLS-1$
0052:
0053: private String path;
0054:
0055: transient byte[] properPath;
0056:
0057: /**
0058: * System dependent file separator character.
0059: */
0060: public static final char separatorChar;
0061:
0062: /**
0063: * System dependent file separator String. The initial value of this field
0064: * is the System property "file.separator".
0065: */
0066: public static final String separator;
0067:
0068: /**
0069: * System dependent path separator character.
0070: */
0071: public static final char pathSeparatorChar;
0072:
0073: /**
0074: * System dependent path separator String. The initial value of this field
0075: * is the System property "path.separator".
0076: */
0077: public static final String pathSeparator;
0078:
0079: /* Temp file counter */
0080: private static int counter;
0081:
0082: private static boolean caseSensitive;
0083:
0084: private static native void oneTimeInitialization();
0085:
0086: static {
0087: oneTimeInitialization();
0088:
0089: // The default protection domain grants access to these properties
0090: separatorChar = System
0091: .getProperty("file.separator", "\\").charAt(0); //$NON-NLS-1$ //$NON-NLS-2$
0092: pathSeparatorChar = System
0093: .getProperty("path.separator", ";").charAt(0); //$NON-NLS-1$//$NON-NLS-2$
0094: separator = new String(new char[] { separatorChar }, 0, 1);
0095: pathSeparator = new String(new char[] { pathSeparatorChar }, 0,
0096: 1);
0097: caseSensitive = isCaseSensitiveImpl();
0098: }
0099:
0100: /**
0101: * Constructs a new File using the specified directory and name.
0102: *
0103: * @param dir
0104: * the directory for the file name
0105: * @param name
0106: * the file name to be contained in the dir
0107: */
0108: public File(File dir, String name) {
0109: if (name == null) {
0110: throw new NullPointerException();
0111: }
0112: if (dir == null) {
0113: this .path = fixSlashes(name);
0114: } else {
0115: this .path = calculatePath(dir.getPath(), name);
0116: }
0117: }
0118:
0119: /**
0120: * Constructs a new File using the specified path.
0121: *
0122: * @param path
0123: * the path to be used for the file
0124: */
0125: public File(String path) {
0126: // path == null check & NullPointerException thrown by fixSlashes
0127: this .path = fixSlashes(path);
0128: }
0129:
0130: /**
0131: * Constructs a new File using the specified directory and name placing a
0132: * path separator between the two.
0133: *
0134: * @param dirPath
0135: * the directory for the file name
0136: * @param name
0137: * the file name to be contained in the dir
0138: */
0139: public File(String dirPath, String name) {
0140: if (name == null) {
0141: throw new NullPointerException();
0142: }
0143: if (dirPath == null) {
0144: this .path = fixSlashes(name);
0145: } else {
0146: this .path = calculatePath(dirPath, name);
0147: }
0148: }
0149:
0150: /**
0151: * Constructs a new File using the path of the specified URI
0152: *
0153: * <code>uri</code> needs to be an absolute and hierarchical
0154: * <code>URI </code> with file scheme, and non-empty path component, but
0155: * with undefined authority, query or fragment components.
0156: *
0157: * @param uri
0158: * the URI instance which will be used to construct this file
0159: *
0160: * @throws IllegalArgumentException
0161: * if <code>uri</code> does not comply with the conditions
0162: * above.
0163: *
0164: * @see #toURI
0165: * @see java.net.URI
0166: */
0167: public File(URI uri) {
0168: // check pre-conditions
0169: checkURI(uri);
0170: this .path = fixSlashes(uri.getPath());
0171: }
0172:
0173: private String calculatePath(String dirPath, String name) {
0174: dirPath = fixSlashes(dirPath);
0175: if (!name.equals(EMPTY_STRING) || dirPath.equals(EMPTY_STRING)) {
0176: // Remove all the proceeding separator chars from name
0177: name = fixSlashes(name);
0178:
0179: int separatorIndex = 0;
0180: while ((separatorIndex < name.length())
0181: && (name.charAt(separatorIndex) == separatorChar)) {
0182: separatorIndex++;
0183: }
0184: if (separatorIndex > 0) {
0185: name = name.substring(separatorIndex, name.length());
0186: }
0187:
0188: // Ensure there is a separator char between dirPath and name
0189: if (dirPath.length() > 0
0190: && (dirPath.charAt(dirPath.length() - 1) == separatorChar)) {
0191: return dirPath + name;
0192: }
0193: return dirPath + separatorChar + name;
0194: }
0195:
0196: return dirPath;
0197: }
0198:
0199: @SuppressWarnings("nls")
0200: private void checkURI(URI uri) {
0201: if (!uri.isAbsolute()) {
0202: throw new IllegalArgumentException(Msg.getString("K031a",
0203: uri));
0204: } else if (!uri.getRawSchemeSpecificPart().startsWith("/")) {
0205: throw new IllegalArgumentException(Msg.getString("K031b",
0206: uri));
0207: }
0208:
0209: String temp = uri.getScheme();
0210: if (temp == null || !temp.equals("file")) {
0211: throw new IllegalArgumentException(Msg.getString("K031c",
0212: uri));
0213: }
0214:
0215: temp = uri.getRawPath();
0216: if (temp == null || temp.length() == 0) {
0217: throw new IllegalArgumentException(Msg.getString("K031d",
0218: uri));
0219: }
0220:
0221: if (uri.getRawAuthority() != null) {
0222: throw new IllegalArgumentException(Msg.getString("K031e",
0223: new String[] { "authority", uri.toString() }));
0224: }
0225:
0226: if (uri.getRawQuery() != null) {
0227: throw new IllegalArgumentException(Msg.getString("K031e",
0228: new String[] { "query", uri.toString() }));
0229: }
0230:
0231: if (uri.getRawFragment() != null) {
0232: throw new IllegalArgumentException(Msg.getString("K031e",
0233: new String[] { "fragment", uri.toString() }));
0234: }
0235: }
0236:
0237: private static native byte[][] rootsImpl();
0238:
0239: private static native boolean isCaseSensitiveImpl();
0240:
0241: /**
0242: * Lists the filesystem roots.
0243: *
0244: * The Java platform may support zero or more filesystems, each with its own
0245: * platform-dependent root. Further, the canonical pathname of any file on
0246: * the system will always begin with one of the returned filesystem roots.
0247: *
0248: * @return the array of filesystem roots
0249: */
0250: public static File[] listRoots() {
0251: byte[][] rootsList = rootsImpl();
0252: if (rootsList == null) {
0253: return new File[0];
0254: }
0255: File result[] = new File[rootsList.length];
0256: for (int i = 0; i < rootsList.length; i++) {
0257: result[i] = new File(Util.toString(rootsList[i]));
0258: }
0259: return result;
0260: }
0261:
0262: /**
0263: * The purpose of this method is to take a path and fix the slashes up. This
0264: * includes changing them all to the current platforms fileSeparator and
0265: * removing duplicates.
0266: */
0267: private String fixSlashes(String origPath) {
0268: int uncIndex = 1;
0269: int length = origPath.length(), newLength = 0;
0270: if (separatorChar == '/') {
0271: uncIndex = 0;
0272: } else if (length > 2 && origPath.charAt(1) == ':') {
0273: uncIndex = 2;
0274: }
0275:
0276: boolean foundSlash = false;
0277: char newPath[] = origPath.toCharArray();
0278: for (int i = 0; i < length; i++) {
0279: char pathChar = newPath[i];
0280: if (pathChar == '\\' || pathChar == '/') {
0281: /* UNC Name requires 2 leading slashes */
0282: if ((foundSlash && i == uncIndex) || !foundSlash) {
0283: newPath[newLength++] = separatorChar;
0284: foundSlash = true;
0285: }
0286: } else {
0287: // check for leading slashes before a drive
0288: if (pathChar == ':'
0289: && uncIndex > 0
0290: && (newLength == 2 || (newLength == 3 && newPath[1] == separatorChar))
0291: && newPath[0] == separatorChar) {
0292: newPath[0] = newPath[newLength - 1];
0293: newLength = 1;
0294: // allow trailing slash after drive letter
0295: uncIndex = 2;
0296: }
0297: newPath[newLength++] = pathChar;
0298: foundSlash = false;
0299: }
0300: }
0301: // remove trailing slash
0302: if (foundSlash
0303: && (newLength > (uncIndex + 1) || (newLength == 2 && newPath[0] != separatorChar))) {
0304: newLength--;
0305: }
0306: String tempPath = new String(newPath, 0, newLength);
0307: // If it's the same keep it identical for SecurityManager purposes
0308: if (!tempPath.equals(origPath)) {
0309: return tempPath;
0310: }
0311: return origPath;
0312: }
0313:
0314: /**
0315: * Answers a boolean indicating whether or not the current context is
0316: * allowed to read this File.
0317: *
0318: * @return <code>true</code> if this File can be read, <code>false</code>
0319: * otherwise.
0320: *
0321: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0322: */
0323: public boolean canRead() {
0324: SecurityManager security = System.getSecurityManager();
0325: if (security != null) {
0326: security.checkRead(path);
0327: }
0328: return exists() && !isWriteOnlyImpl(properPath(true));
0329: }
0330:
0331: /**
0332: * Answers a boolean indicating whether or not the current context is
0333: * allowed to write to this File.
0334: *
0335: * @return <code>true</code> if this File can be written,
0336: * <code>false</code> otherwise.
0337: *
0338: * @see java.lang.SecurityManager#checkWrite(FileDescriptor)
0339: */
0340: public boolean canWrite() {
0341: SecurityManager security = System.getSecurityManager();
0342: if (security != null) {
0343: security.checkWrite(path);
0344: }
0345:
0346: // Cannot use exists() since that does an unwanted read-check.
0347: boolean exists = false;
0348: if (path.length() > 0) {
0349: exists = existsImpl(properPath(true));
0350: }
0351: return exists && !isReadOnlyImpl(properPath(true));
0352: }
0353:
0354: /**
0355: * Answers the relative sort ordering of paths for the receiver and given
0356: * argument. The ordering is platform dependent.
0357: *
0358: * @param another
0359: * a File to compare the receiver to
0360: * @return an int determined by comparing the two paths. The meaning is
0361: * described in the Comparable interface.
0362: * @see Comparable
0363: */
0364: public int compareTo(File another) {
0365: if (caseSensitive) {
0366: return this .getPath().compareTo(another.getPath());
0367: }
0368: return this .getPath().compareToIgnoreCase(another.getPath());
0369: }
0370:
0371: /**
0372: * Deletes the file specified by this File. Directories must be empty before
0373: * they will be deleted.
0374: *
0375: * @return <code>true</code> if this File was deleted, <code>false</code>
0376: * otherwise.
0377: *
0378: * @see java.lang.SecurityManager#checkDelete
0379: */
0380: public boolean delete() {
0381: SecurityManager security = System.getSecurityManager();
0382: if (security != null) {
0383: security.checkDelete(path);
0384: }
0385: byte[] propPath = properPath(true);
0386: if ((path.length() != 0) && isDirectoryImpl(propPath)) {
0387: return deleteDirImpl(propPath);
0388: }
0389: return deleteFileImpl(propPath);
0390: }
0391:
0392: private native boolean deleteDirImpl(byte[] filePath);
0393:
0394: private native boolean deleteFileImpl(byte[] filePath);
0395:
0396: /**
0397: * When the virtual machine terminates, any abstract files which have been
0398: * sent <code>deleteOnExit()</code> will be deleted. This will only happen
0399: * when the virtual machine terminates normally as described by the Java
0400: * Language Specification section 12.9.
0401: *
0402: */
0403: public void deleteOnExit() {
0404: SecurityManager security = System.getSecurityManager();
0405: if (security != null) {
0406: security.checkDelete(path);
0407: }
0408:
0409: DeleteOnExit.addFile(Util.toUTF8String(properPath(true)));
0410: }
0411:
0412: /**
0413: * Compares the argument <code>obj</code> to the receiver, and answers
0414: * <code>true</code> if they represent the <em>same</em> object using a
0415: * path specific comparison.
0416: *
0417: * @param obj
0418: * the Object to compare with this Object
0419: * @return <code>true</code> if the object is the same as this object,
0420: * <code>false</code> otherwise.
0421: */
0422: @Override
0423: public boolean equals(Object obj) {
0424: if (!(obj instanceof File)) {
0425: return false;
0426: }
0427: if (!caseSensitive) {
0428: return path.equalsIgnoreCase(((File) obj).getPath());
0429: }
0430: return path.equals(((File) obj).getPath());
0431: }
0432:
0433: /**
0434: * Answers a boolean indicating whether or not this File can be found on the
0435: * underlying file system.
0436: *
0437: * @return <code>true</code> if this File exists, <code>false</code>
0438: * otherwise.
0439: *
0440: * @see #getPath
0441: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0442: */
0443: public boolean exists() {
0444: if (path.length() == 0) {
0445: return false;
0446: }
0447: SecurityManager security = System.getSecurityManager();
0448: if (security != null) {
0449: security.checkRead(path);
0450: }
0451: return existsImpl(properPath(true));
0452: }
0453:
0454: private native boolean existsImpl(byte[] filePath);
0455:
0456: /**
0457: * Answers the absolute file path of this File.
0458: *
0459: * @return the absolute file path
0460: *
0461: * @see java.lang.SecurityManager#checkPropertyAccess
0462: */
0463: public String getAbsolutePath() {
0464: byte[] absolute = properPath(false);
0465: return Util.toUTF8String(absolute);
0466: }
0467:
0468: /**
0469: * Answers a new File constructed using the absolute file path of this File.
0470: *
0471: * @return a new File from this absolute file path
0472: *
0473: * @see java.lang.SecurityManager#checkPropertyAccess
0474: */
0475: public File getAbsoluteFile() {
0476: return new File(this .getAbsolutePath());
0477: }
0478:
0479: /**
0480: * Answers the absolute file path of this File with all references resolved.
0481: * An <em>absolute</em> file path is one which begins at the root of the
0482: * file system. The canonical path is one in which all references have been
0483: * resolved. For the cases of '..' and '.' where the file system supports
0484: * parent and working directory respectively, these should be removed and
0485: * replaced with a direct directory reference. If the File does not exist,
0486: * getCanonicalPath() may not resolve any references and simply return an
0487: * absolute path name or throw an IOException.
0488: *
0489: * @return the canonical file path
0490: *
0491: * @throws IOException
0492: * if an IO error occurs
0493: *
0494: * @see java.lang.SecurityManager#checkPropertyAccess
0495: */
0496: public String getCanonicalPath() throws IOException {
0497: byte[] result = properPath(false);
0498:
0499: boolean exists = false;
0500: byte[] pathBytes = result;
0501: do {
0502: byte[] linkBytes = getLinkImpl(pathBytes);
0503: if (linkBytes == pathBytes) {
0504: break;
0505: }
0506: if (linkBytes[0] == separatorChar) {
0507: pathBytes = linkBytes;
0508: } else {
0509: int index = pathBytes.length - 1;
0510: while (pathBytes[index] != separatorChar) {
0511: index--;
0512: }
0513: byte[] temp = new byte[index + 1 + linkBytes.length];
0514: System.arraycopy(pathBytes, 0, temp, 0, index + 1);
0515: System.arraycopy(linkBytes, 0, temp, index + 1,
0516: linkBytes.length);
0517: pathBytes = temp;
0518: }
0519: exists = existsImpl(pathBytes);
0520: } while (exists);
0521: if (exists) {
0522: result = pathBytes;
0523: }
0524:
0525: int numSeparators = 1;
0526: for (int i = 0; i < result.length; i++) {
0527: if (result[i] == separatorChar) {
0528: numSeparators++;
0529: }
0530: }
0531: int sepLocations[] = new int[numSeparators];
0532: int rootLoc = 0;
0533: if (separatorChar != '/') {
0534: if (result[0] == '\\') {
0535: rootLoc = (result.length > 1 && result[1] == '\\') ? 1
0536: : 0;
0537: } else {
0538: rootLoc = 2; // skip drive i.e. c:
0539: }
0540: }
0541: byte newResult[] = new byte[result.length + 1];
0542: int newLength = 0, lastSlash = 0, foundDots = 0;
0543: sepLocations[lastSlash] = rootLoc;
0544: for (int i = 0; i <= result.length; i++) {
0545: if (i < rootLoc) {
0546: newResult[newLength++] = result[i];
0547: } else {
0548: if (i == result.length || result[i] == separatorChar) {
0549: if (i == result.length && foundDots == 0) {
0550: break;
0551: }
0552: if (foundDots == 1) {
0553: /* Don't write anything, just reset and continue */
0554: foundDots = 0;
0555: continue;
0556: }
0557: if (foundDots > 1) {
0558: /* Go back N levels */
0559: lastSlash = lastSlash > (foundDots - 1) ? lastSlash
0560: - (foundDots - 1)
0561: : 0;
0562: newLength = sepLocations[lastSlash] + 1;
0563: foundDots = 0;
0564: continue;
0565: }
0566: sepLocations[++lastSlash] = newLength;
0567: newResult[newLength++] = (byte) separatorChar;
0568: continue;
0569: }
0570: if (result[i] == '.') {
0571: foundDots++;
0572: continue;
0573: }
0574: /* Found some dots within text, write them out */
0575: if (foundDots > 0) {
0576: for (int j = 0; j < foundDots; j++) {
0577: newResult[newLength++] = (byte) '.';
0578: }
0579: }
0580: newResult[newLength++] = result[i];
0581: foundDots = 0;
0582: }
0583: }
0584: // remove trailing slash
0585: if (newLength > (rootLoc + 1)
0586: && newResult[newLength - 1] == separatorChar) {
0587: newLength--;
0588: }
0589: newResult[newLength] = 0;
0590: newResult = getCanonImpl(newResult);
0591: newLength = newResult.length;
0592: return Util.toUTF8String(newResult, 0, newLength);
0593: }
0594:
0595: /**
0596: * Answers a new File created using the canonical file path of this File.
0597: * Equivalent to <code>new File(this.getCanonicalPath())</code>.
0598: *
0599: * @return the canonical file path
0600: *
0601: * @throws IOException
0602: * If an IO error occurs
0603: *
0604: * @see java.lang.SecurityManager#checkPropertyAccess
0605: */
0606: public File getCanonicalFile() throws IOException {
0607: return new File(getCanonicalPath());
0608: }
0609:
0610: private native byte[] getCanonImpl(byte[] filePath);
0611:
0612: /**
0613: * Answers the filename (not directory) of this File.
0614: *
0615: * @return the filename or empty string
0616: */
0617: public String getName() {
0618: int separatorIndex = path.lastIndexOf(separator);
0619: return (separatorIndex < 0) ? path : path.substring(
0620: separatorIndex + 1, path.length());
0621: }
0622:
0623: /**
0624: * Answers the pathname of the parent of this File. This is the path up to
0625: * but not including the last name. <code>null</code> is returned when
0626: * there is no parent.
0627: *
0628: * @return the parent name or <code>null</code>
0629: */
0630: public String getParent() {
0631: int length = path.length(), firstInPath = 0;
0632: if (separatorChar == '\\' && length > 2
0633: && path.charAt(1) == ':') {
0634: firstInPath = 2;
0635: }
0636: int index = path.lastIndexOf(separatorChar);
0637: if (index == -1 && firstInPath > 0) {
0638: index = 2;
0639: }
0640: if (index == -1 || path.charAt(length - 1) == separatorChar) {
0641: return null;
0642: }
0643: if (path.indexOf(separatorChar) == index
0644: && path.charAt(firstInPath) == separatorChar) {
0645: return path.substring(0, index + 1);
0646: }
0647: return path.substring(0, index);
0648: }
0649:
0650: /**
0651: * Answers a new File made from the pathname of the parent of this File.
0652: * This is the path up to but not including the last name. <code>null</code>
0653: * is returned when there is no parent.
0654: *
0655: * @return a new File representing parent or <code>null</code>
0656: */
0657: public File getParentFile() {
0658: String tempParent = getParent();
0659: if (tempParent == null) {
0660: return null;
0661: }
0662: return new File(tempParent);
0663: }
0664:
0665: /**
0666: * Answers the file path of this File.
0667: *
0668: * @return the file path
0669: */
0670: public String getPath() {
0671: return path;
0672: }
0673:
0674: /**
0675: * Answers an integer hash code for the receiver. Any two objects which
0676: * answer <code>true</code> when passed to <code>equals</code> must
0677: * answer the same value for this method.
0678: *
0679: * @return the receiver's hash
0680: *
0681: * @see #equals
0682: */
0683: @Override
0684: public int hashCode() {
0685: if (caseSensitive) {
0686: return path.hashCode() ^ 1234321;
0687: }
0688: return path.toLowerCase().hashCode() ^ 1234321;
0689: }
0690:
0691: /**
0692: * Answers if this File is an absolute pathname. Whether a pathname is
0693: * absolute is platform specific. On UNIX it is if the path starts with the
0694: * character '/', on Windows it is absolute if either it starts with '\',
0695: * '/', '\\' (to represent a file server), or a letter followed by a colon.
0696: *
0697: * @return <code>true</code> if this File is absolute, <code>false</code>
0698: * otherwise.
0699: *
0700: * @see #getPath
0701: */
0702: public boolean isAbsolute() {
0703: return isAbsoluteImpl(Util.getUTF8Bytes(path));
0704: }
0705:
0706: private native boolean isAbsoluteImpl(byte[] filePath);
0707:
0708: /**
0709: * Answers if this File represents a <em>directory</em> on the underlying
0710: * file system.
0711: *
0712: * @return <code>true</code> if this File is a directory,
0713: * <code>false</code> otherwise.
0714: *
0715: * @see #getPath
0716: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0717: */
0718: public boolean isDirectory() {
0719: if (path.length() == 0) {
0720: return false;
0721: }
0722: SecurityManager security = System.getSecurityManager();
0723: if (security != null) {
0724: security.checkRead(path);
0725: }
0726: return isDirectoryImpl(properPath(true));
0727: }
0728:
0729: private native boolean isDirectoryImpl(byte[] filePath);
0730:
0731: /**
0732: * Answers if this File represents a <em>file</em> on the underlying file
0733: * system.
0734: *
0735: * @return <code>true</code> if this File is a file, <code>false</code>
0736: * otherwise.
0737: *
0738: * @see #getPath
0739: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0740: */
0741: public boolean isFile() {
0742: if (path.length() == 0) {
0743: return false;
0744: }
0745: SecurityManager security = System.getSecurityManager();
0746: if (security != null) {
0747: security.checkRead(path);
0748: }
0749: return isFileImpl(properPath(true));
0750: }
0751:
0752: private native boolean isFileImpl(byte[] filePath);
0753:
0754: /**
0755: * Returns whether or not this file is a hidden file as defined by the
0756: * operating system.
0757: *
0758: * @return <code>true</code> if the file is hidden, <code>false</code>
0759: * otherwise.
0760: */
0761: public boolean isHidden() {
0762: if (path.length() == 0) {
0763: return false;
0764: }
0765: SecurityManager security = System.getSecurityManager();
0766: if (security != null) {
0767: security.checkRead(path);
0768: }
0769: return isHiddenImpl(properPath(true));
0770: }
0771:
0772: private native boolean isHiddenImpl(byte[] filePath);
0773:
0774: private native boolean isReadOnlyImpl(byte[] filePath);
0775:
0776: private native boolean isWriteOnlyImpl(byte[] filePath);
0777:
0778: private native byte[] getLinkImpl(byte[] filePath);
0779:
0780: /**
0781: * Answers the time this File was last modified.
0782: *
0783: * @return the time this File was last modified.
0784: *
0785: * @see #getPath
0786: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0787: */
0788: public long lastModified() {
0789: SecurityManager security = System.getSecurityManager();
0790: if (security != null) {
0791: security.checkRead(path);
0792: }
0793: long result = lastModifiedImpl(properPath(true));
0794: /* Temporary code to handle both return cases until natives fixed */
0795: if (result == -1 || result == 0) {
0796: return 0;
0797: }
0798: return result;
0799: }
0800:
0801: private native long lastModifiedImpl(byte[] filePath);
0802:
0803: /**
0804: * Sets the time this File was last modified.
0805: *
0806: * @param time
0807: * The time to set the file as last modified.
0808: * @return the time this File was last modified.
0809: *
0810: * @see java.lang.SecurityManager#checkWrite(FileDescriptor)
0811: */
0812: public boolean setLastModified(long time) {
0813: if (time < 0) {
0814: throw new IllegalArgumentException(Msg.getString("K006a")); //$NON-NLS-1$
0815: }
0816: SecurityManager security = System.getSecurityManager();
0817: if (security != null) {
0818: security.checkWrite(path);
0819: }
0820: return (setLastModifiedImpl(properPath(true), time));
0821: }
0822:
0823: private native boolean setLastModifiedImpl(byte[] path, long time);
0824:
0825: /**
0826: * Marks this file or directory to be read-only as defined by the operating
0827: * system.
0828: *
0829: * @return <code>true</code> if the operation was a success,
0830: * <code>false</code> otherwise
0831: */
0832: public boolean setReadOnly() {
0833: SecurityManager security = System.getSecurityManager();
0834: if (security != null) {
0835: security.checkWrite(path);
0836: }
0837: return (setReadOnlyImpl(properPath(true)));
0838: }
0839:
0840: private native boolean setReadOnlyImpl(byte[] path);
0841:
0842: /**
0843: * Answers the length of this File in bytes.
0844: *
0845: * @return the number of bytes in the file.
0846: *
0847: * @see #getPath
0848: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0849: */
0850: public long length() {
0851: SecurityManager security = System.getSecurityManager();
0852: if (security != null) {
0853: security.checkRead(path);
0854: }
0855: return lengthImpl(properPath(true));
0856: }
0857:
0858: private native long lengthImpl(byte[] filePath);
0859:
0860: /**
0861: * Answers an array of Strings representing the file names in the directory
0862: * represented by this File. If this File is not a directory the result is
0863: * <code>null</code>.
0864: * <p>
0865: * The entries <code>.</code> and <code>..</code> representing current
0866: * directory and parent directory are not returned as part of the list.
0867: *
0868: * @return an array of Strings or <code>null</code>.
0869: *
0870: * @see #getPath
0871: * @see #isDirectory
0872: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0873: */
0874: public java.lang.String[] list() {
0875: SecurityManager security = System.getSecurityManager();
0876: if (security != null) {
0877: security.checkRead(path);
0878: }
0879: if (!isDirectory() || !canRead()) {
0880: return null;
0881: }
0882: byte[][] implList = listImpl(properPath(true));
0883: if (implList == null) {
0884: // empty list
0885: return new String[0];
0886: }
0887: String result[] = new String[implList.length];
0888: for (int index = 0; index < implList.length; index++) {
0889: result[index] = Util.toUTF8String(implList[index]);
0890: }
0891: return result;
0892: }
0893:
0894: /**
0895: * Answers an array of Files representing the file names in the directory
0896: * represented by this File. If this File is not a directory the result is
0897: * <code>null</code>. The Files returned will be absolute if this File is
0898: * absolute, relative otherwise.
0899: *
0900: * @return an array of Files or <code>null</code>.
0901: *
0902: * @see #getPath
0903: * @see #list()
0904: * @see #isDirectory
0905: */
0906: public File[] listFiles() {
0907: String[] tempNames = list();
0908: if (tempNames == null) {
0909: return null;
0910: }
0911: int resultLength = tempNames.length;
0912: File results[] = new File[resultLength];
0913: for (int i = 0; i < resultLength; i++) {
0914: results[i] = new File(this , tempNames[i]);
0915: }
0916: return results;
0917: }
0918:
0919: /**
0920: * Answers an array of Files representing the file names in the directory
0921: * represented by this File that match a specific filter. If this File is
0922: * not a directory the result is <code>null</code>. If the filter is
0923: * <code>null</code> then all filenames match.
0924: * <p>
0925: * The entries <code>.</code> and <code>..</code> representing current
0926: * directory and parent directory are not returned as part of the list.
0927: *
0928: * @param filter
0929: * the filter to match names to or <code>null</code>.
0930: * @return an array of Files or <code>null</code>.
0931: *
0932: * @see #list(FilenameFilter filter)
0933: * @see #getPath
0934: * @see #isDirectory
0935: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0936: */
0937: public File[] listFiles(FilenameFilter filter) {
0938: String[] tempNames = list(filter);
0939: if (tempNames == null) {
0940: return null;
0941: }
0942: int resultLength = tempNames.length;
0943: File results[] = new File[resultLength];
0944: for (int i = 0; i < resultLength; i++) {
0945: results[i] = new File(this , tempNames[i]);
0946: }
0947: return results;
0948: }
0949:
0950: /**
0951: * Answers an array of Files representing the file names in the directory
0952: * represented by this File that match a specific filter. If this File is
0953: * not a directory the result is <code>null</code>. If the filter is
0954: * <code>null</code> then all filenames match.
0955: * <p>
0956: * The entries <code>.</code> and <code>..</code> representing current
0957: * directory and parent directory are not returned as part of the list.
0958: *
0959: * @param filter
0960: * the filter to match names to or <code>null</code>.
0961: * @return an array of Files or <code>null</code>.
0962: *
0963: * @see #getPath
0964: * @see #isDirectory
0965: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
0966: */
0967: public File[] listFiles(FileFilter filter) {
0968: SecurityManager security = System.getSecurityManager();
0969: if (security != null) {
0970: security.checkRead(path);
0971: }
0972: if (!isDirectory() || !canRead()) {
0973: return null;
0974: }
0975: byte[][] implList = listImpl(properPath(true));
0976: if (implList == null) {
0977: return new File[0];
0978: }
0979: List<File> tempResult = new ArrayList<File>();
0980: for (int index = 0; index < implList.length; index++) {
0981: String aName = Util.toString(implList[index]);
0982: File aFile = new File(this , aName);
0983: if (filter == null || filter.accept(aFile)) {
0984: tempResult.add(aFile);
0985: }
0986: }
0987: return tempResult.toArray(new File[tempResult.size()]);
0988: }
0989:
0990: /**
0991: * Answers an array of Strings representing the file names in the directory
0992: * represented by this File that match a specific filter. If this File is
0993: * not a directory the result is <code>null</code>. If the filter is
0994: * <code>null</code> then all filenames match.
0995: * <p>
0996: * The entries <code>.</code> and <code>..</code> representing current
0997: * directory and parent directory are not returned as part of the list.
0998: *
0999: * @param filter
1000: * the filter to match names to or <code>null</code>.
1001: * @return an array of Strings or <code>null</code>.
1002: *
1003: * @see #getPath
1004: * @see #isDirectory
1005: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
1006: */
1007: public java.lang.String[] list(FilenameFilter filter) {
1008: SecurityManager security = System.getSecurityManager();
1009: if (security != null) {
1010: security.checkRead(path);
1011: }
1012: if (!isDirectory() || !canRead()) {
1013: return null;
1014: }
1015: byte[][] implList = listImpl(properPath(true));
1016: if (implList == null) {
1017: // empty list
1018: return new String[0];
1019: }
1020: java.util.Vector<String> tempResult = new java.util.Vector<String>();
1021: for (int index = 0; index < implList.length; index++) {
1022: String aName = Util.toString(implList[index]);
1023: if (filter == null || filter.accept(this , aName)) {
1024: tempResult.addElement(aName);
1025: }
1026: }
1027: String[] result = new String[tempResult.size()];
1028: tempResult.copyInto(result);
1029: return result;
1030: }
1031:
1032: private synchronized static native byte[][] listImpl(byte[] path);
1033:
1034: /**
1035: * Creates the directory named by the trailing filename of this File. Not
1036: * all directories required to create this File are created.
1037: *
1038: * @return <code>true</code> if the directory was created,
1039: * <code>false</code> otherwise.
1040: *
1041: * @see #getPath
1042: * @see java.lang.SecurityManager#checkWrite(FileDescriptor)
1043: */
1044: public boolean mkdir() {
1045: SecurityManager security = System.getSecurityManager();
1046: if (security != null) {
1047: security.checkWrite(path);
1048: }
1049: return mkdirImpl(properPath(true));
1050: }
1051:
1052: private native boolean mkdirImpl(byte[] filePath);
1053:
1054: /**
1055: * Create all the directories needed for this File. If the terminal
1056: * directory already exists, answer false. If the directories were created
1057: * successfully, answer <code>true</code>.
1058: *
1059: * @return <code>true</code> if the necessary directories were created,
1060: * <code>false</code> otherwise.
1061: *
1062: */
1063: public boolean mkdirs() {
1064: /* If the terminal directory already exists, answer false */
1065: if (exists()) {
1066: return false;
1067: }
1068:
1069: /* If the receiver can be created, answer true */
1070: if (mkdir()) {
1071: return true;
1072: }
1073:
1074: String parentDir = getParent();
1075: /* If there is no parent and we were not created, answer false */
1076: if (parentDir == null) {
1077: return false;
1078: }
1079:
1080: /* Otherwise, try to create a parent directory and then this directory */
1081: return (new File(parentDir).mkdirs() && mkdir());
1082: }
1083:
1084: /**
1085: * Creates the file specified by this File. If the file already exists this
1086: * method returns <code>false</code>. Otherwise, if the file is created
1087: * successfully, the result is <code>true</code>. An IOException will be
1088: * thrown if the directory to contain this file does not exist.
1089: *
1090: * @return <code>true</code> if this File was created, <code>false</code>
1091: * otherwise.
1092: *
1093: * @throws IOException
1094: * if an I/O error occurs or the directory does not exist.
1095: *
1096: * @see java.lang.SecurityManager#checkWrite(FileDescriptor)
1097: */
1098: public boolean createNewFile() throws IOException {
1099: SecurityManager security = System.getSecurityManager();
1100: if (security != null) {
1101: security.checkWrite(path);
1102: }
1103: if (0 == path.length()) {
1104: throw new IOException(Msg.getString("KA012")); //$NON-NLS-1$
1105: }
1106: int result = newFileImpl(properPath(true));
1107: switch (result) {
1108: case 0:
1109: return true;
1110: case 1:
1111: return false;
1112: default:
1113: throw new IOException(Msg.getString("K01c2", path)); //$NON-NLS-1$
1114: }
1115: }
1116:
1117: private native int newFileImpl(byte[] filePath);
1118:
1119: /**
1120: * Creates an empty temporary file using the given prefix and suffix as part
1121: * of the file name. If suffix is null, <code>.tmp</code> is used.
1122: *
1123: * @param prefix
1124: * the prefix to the temp file name
1125: * @param suffix
1126: * the suffix to the temp file name
1127: * @return the temporary file
1128: *
1129: * @throws IOException
1130: * If an error occurs when writing the file
1131: */
1132: public static File createTempFile(String prefix, String suffix)
1133: throws IOException {
1134: return createTempFile(prefix, suffix, null);
1135: }
1136:
1137: /**
1138: * Creates an empty temporary file in the given directory using the given
1139: * prefix and suffix as part of the file name.
1140: *
1141: * @param prefix
1142: * the prefix to the temp file name
1143: * @param suffix
1144: * the suffix to the temp file name
1145: * @param directory
1146: * the location to which the temp file is to be written, or null
1147: * for the default temp location
1148: * @return the temporary file
1149: *
1150: * @throws IOException
1151: * If an error occurs when writing the file
1152: */
1153: public static File createTempFile(String prefix, String suffix,
1154: File directory) throws IOException {
1155: // Force a prefix null check first
1156: if (prefix.length() < 3) {
1157: throw new IllegalArgumentException(Msg.getString("K006b")); //$NON-NLS-1$
1158: }
1159: String newSuffix = suffix == null ? ".tmp" : suffix; //$NON-NLS-1$
1160: String tmpDir = "."; //$NON-NLS-1$
1161: tmpDir = AccessController.doPrivileged(new PriviAction<String>(
1162: "java.io.tmpdir", ".")); //$NON-NLS-1$//$NON-NLS-2$
1163: File result, tmpDirFile = directory == null ? new File(tmpDir)
1164: : directory;
1165: do {
1166: result = genTempFile(prefix, newSuffix, tmpDirFile);
1167: } while (!result.createNewFile());
1168: return result;
1169: }
1170:
1171: private static File genTempFile(String prefix, String suffix,
1172: File directory) {
1173: if (counter == 0) {
1174: int newInt = new SecureRandom().nextInt();
1175: counter = ((newInt / 65535) & 0xFFFF) + 0x2710;
1176: }
1177: StringBuilder newName = new StringBuilder();
1178: newName.append(prefix);
1179: newName.append(counter++);
1180: newName.append(suffix);
1181: return new File(directory, newName.toString());
1182: }
1183:
1184: /**
1185: * Answer a String representing the proper path for the receiver. If the
1186: * receiver is absolute do not prepend the user.dir property, otherwise do.
1187: *
1188: * @param internal
1189: * is user.dir internal
1190: * @return the proper path
1191: */
1192: byte[] properPath(boolean internal) {
1193: if (properPath != null) {
1194: return properPath;
1195: }
1196: byte[] pathBytes = Util.getUTF8Bytes(path);
1197: if (isAbsoluteImpl(pathBytes)) {
1198: return properPath = pathBytes;
1199: }
1200: // Check security by getting user.dir when the path is not absolute
1201: String userdir;
1202: if (internal) {
1203: userdir = AccessController
1204: .doPrivileged(new PriviAction<String>("user.dir")); //$NON-NLS-1$
1205: } else {
1206: userdir = System.getProperty("user.dir"); //$NON-NLS-1$
1207: }
1208: if ((properPath = properPathImpl(pathBytes)) != null) {
1209: return properPath;
1210: }
1211: if (path.length() == 0) {
1212: return properPath = Util.getUTF8Bytes(userdir);
1213: }
1214: int length = userdir.length();
1215:
1216: // Handle windows-like path
1217: if (path.charAt(0) == '\\') {
1218: if (length > 1 && userdir.charAt(1) == ':') {
1219: return properPath = Util.getUTF8Bytes(userdir
1220: .substring(0, 2)
1221: + path);
1222: }
1223: path = path.substring(1);
1224: }
1225:
1226: // Handle separator
1227: String result = userdir;
1228: if (userdir.charAt(length - 1) != separatorChar) {
1229: if (path.charAt(0) != separatorChar) {
1230: result += separator;
1231: }
1232: } else if (path.charAt(0) == separatorChar) {
1233: result = result.substring(0, length - 2);
1234:
1235: }
1236: result += path;
1237: return properPath = Util.getUTF8Bytes(result);
1238: }
1239:
1240: private static native byte[] properPathImpl(byte[] path);
1241:
1242: /**
1243: * Renames this File to the name represented by the File <code>dest</code>.
1244: * This works for both normal files and directories.
1245: *
1246: * @param dest
1247: * the File containing the new name.
1248: * @return <code>true</code> if the File was renamed, <code>false</code>
1249: * otherwise.
1250: *
1251: * @see #getPath
1252: * @see java.lang.SecurityManager#checkRead(FileDescriptor)
1253: * @see java.lang.SecurityManager#checkWrite(FileDescriptor)
1254: */
1255: public boolean renameTo(java.io.File dest) {
1256: SecurityManager security = System.getSecurityManager();
1257: if (security != null) {
1258: security.checkWrite(path);
1259: security.checkWrite(dest.path);
1260: }
1261: return renameToImpl(properPath(true), dest.properPath(true));
1262: }
1263:
1264: private native boolean renameToImpl(byte[] pathExist, byte[] pathNew);
1265:
1266: /**
1267: * Answers a string containing a concise, human-readable description of the
1268: * receiver.
1269: *
1270: * @return a printable representation for the receiver.
1271: */
1272: @Override
1273: public String toString() {
1274: return path;
1275: }
1276:
1277: /**
1278: * Answers a <code>file</code> URI for this File. The URI is System
1279: * dependent and may not be transferable between different operating/file
1280: * systems.
1281: *
1282: * @return a <code>file</code> URI for this File.
1283: */
1284: @SuppressWarnings("nls")
1285: public URI toURI() {
1286: String name = getAbsoluteName();
1287: try {
1288: if (!name.startsWith("/")) {
1289: // start with sep.
1290: return new URI("file", null, new StringBuilder(name
1291: .length() + 1).append('/').append(name)
1292: .toString(), null, null);
1293: } else if (name.startsWith("//")) {
1294: return new URI("file", name, null); // UNC path
1295: }
1296: return new URI("file", null, name, null, null);
1297: } catch (URISyntaxException e) {
1298: // this should never happen
1299: return null;
1300: }
1301: }
1302:
1303: /**
1304: * Answers a <code>file</code> URL for this File. The URL is System
1305: * dependent and may not be transferable between different operating/file
1306: * systems.
1307: *
1308: * @return a <code>file</code> URL for this File.
1309: *
1310: * @throws java.net.MalformedURLException
1311: * if the path cannot be transformed into an URL
1312: */
1313: @SuppressWarnings("nls")
1314: public URL toURL() throws java.net.MalformedURLException {
1315: String name = getAbsoluteName();
1316: if (!name.startsWith("/")) {
1317: // start with sep.
1318: return new URL(
1319: "file", EMPTY_STRING, -1, new StringBuilder(name.length() + 1) //$NON-NLS-1$
1320: .append('/').append(name).toString(), null);
1321: } else if (name.startsWith("//")) {
1322: return new URL("file:" + name); // UNC path
1323: }
1324: return new URL("file", EMPTY_STRING, -1, name, null);
1325: }
1326:
1327: private String getAbsoluteName() {
1328: File f = getAbsoluteFile();
1329: String name = f.getPath();
1330:
1331: if (f.isDirectory()
1332: && name.charAt(name.length() - 1) != separatorChar) {
1333: // Directories must end with a slash
1334: name = new StringBuilder(name.length() + 1).append(name)
1335: .append('/').toString();
1336: }
1337: if (separatorChar != '/') { // Must convert slashes.
1338: name = name.replace(separatorChar, '/');
1339: }
1340: return name;
1341: }
1342:
1343: private void writeObject(ObjectOutputStream stream)
1344: throws IOException {
1345: stream.defaultWriteObject();
1346: stream.writeChar(separatorChar);
1347:
1348: }
1349:
1350: private void readObject(ObjectInputStream stream)
1351: throws IOException, ClassNotFoundException {
1352: stream.defaultReadObject();
1353: char inSeparator = stream.readChar();
1354: path = path.replace(inSeparator, separatorChar);
1355: }
1356: }
|