Home | History | Annotate | Download | only in io
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.io;
     19 
     20 import java.net.URI;
     21 import java.net.URISyntaxException;
     22 import java.net.URL;
     23 import java.util.ArrayList;
     24 import java.util.List;
     25 import java.util.Random;
     26 import libcore.io.ErrnoException;
     27 import libcore.io.IoUtils;
     28 import libcore.io.Libcore;
     29 import libcore.io.StructStat;
     30 import libcore.io.StructStatFs;
     31 import org.apache.harmony.luni.util.DeleteOnExit;
     32 import static libcore.io.OsConstants.*;
     33 
     34 /**
     35  * An "abstract" representation of a file system entity identified by a
     36  * pathname. The pathname may be absolute (relative to the root directory
     37  * of the file system) or relative to the current directory in which the program
     38  * is running.
     39  *
     40  * <p>The actual file referenced by a {@code File} may or may not exist. It may
     41  * also, despite the name {@code File}, be a directory or other non-regular
     42  * file.
     43  *
     44  * <p>This class provides limited functionality for getting/setting file
     45  * permissions, file type, and last modified time.
     46  *
     47  * <p>On Android strings are converted to UTF-8 byte sequences when sending filenames to
     48  * the operating system, and byte sequences returned by the operating system (from the
     49  * various {@code list} methods) are converted to strings by decoding them as UTF-8
     50  * byte sequences.
     51  *
     52  * @see java.io.Serializable
     53  * @see java.lang.Comparable
     54  */
     55 public class File implements Serializable, Comparable<File> {
     56 
     57     private static final long serialVersionUID = 301077366599181567L;
     58 
     59     /**
     60      * Reusing a Random makes temporary filenames slightly harder to predict.
     61      * (Random is thread-safe.)
     62      */
     63     private static final Random tempFileRandom = new Random();
     64 
     65     /**
     66      * The system-dependent character used to separate components in filenames ('/').
     67      * Use of this (rather than hard-coding '/') helps portability to other operating systems.
     68      *
     69      * <p>This field is initialized from the system property "file.separator".
     70      * Later changes to that property will have no effect on this field or this class.
     71      */
     72     public static final char separatorChar;
     73 
     74     /**
     75      * The system-dependent string used to separate components in filenames ('/').
     76      * See {@link #separatorChar}.
     77      */
     78     public static final String separator;
     79 
     80     /**
     81      * The system-dependent character used to separate components in search paths (':').
     82      * This is used to split such things as the PATH environment variable and classpath
     83      * system properties into lists of directories to be searched.
     84      *
     85      * <p>This field is initialized from the system property "path.separator".
     86      * Later changes to that property will have no effect on this field or this class.
     87      */
     88     public static final char pathSeparatorChar;
     89 
     90     /**
     91      * The system-dependent string used to separate components in search paths (":").
     92      * See {@link #pathSeparatorChar}.
     93      */
     94     public static final String pathSeparator;
     95 
     96     /**
     97      * The path we return from getPath. This is almost the path we were
     98      * given, but without duplicate adjacent slashes and without trailing
     99      * slashes (except for the special case of the root directory). This
    100      * path may be the empty string.
    101      *
    102      * This can't be final because we override readObject.
    103      */
    104     private String path;
    105 
    106     static {
    107         separatorChar = System.getProperty("file.separator", "/").charAt(0);
    108         pathSeparatorChar = System.getProperty("path.separator", ":").charAt(0);
    109         separator = String.valueOf(separatorChar);
    110         pathSeparator = String.valueOf(pathSeparatorChar);
    111     }
    112 
    113     /**
    114      * Constructs a new file using the specified directory and name.
    115      *
    116      * @param dir
    117      *            the directory where the file is stored.
    118      * @param name
    119      *            the file's name.
    120      * @throws NullPointerException
    121      *             if {@code name} is {@code null}.
    122      */
    123     public File(File dir, String name) {
    124         this(dir == null ? null : dir.getPath(), name);
    125     }
    126 
    127     /**
    128      * Constructs a new file using the specified path.
    129      *
    130      * @param path
    131      *            the path to be used for the file.
    132      */
    133     public File(String path) {
    134         this.path = fixSlashes(path);
    135     }
    136 
    137     /**
    138      * Constructs a new File using the specified directory path and file name,
    139      * placing a path separator between the two.
    140      *
    141      * @param dirPath
    142      *            the path to the directory where the file is stored.
    143      * @param name
    144      *            the file's name.
    145      * @throws NullPointerException
    146      *             if {@code name == null}.
    147      */
    148     public File(String dirPath, String name) {
    149         if (name == null) {
    150             throw new NullPointerException();
    151         }
    152         if (dirPath == null || dirPath.isEmpty()) {
    153             this.path = fixSlashes(name);
    154         } else if (name.isEmpty()) {
    155             this.path = fixSlashes(dirPath);
    156         } else {
    157             this.path = fixSlashes(join(dirPath, name));
    158         }
    159     }
    160 
    161     /**
    162      * Constructs a new File using the path of the specified URI. {@code uri}
    163      * needs to be an absolute and hierarchical Unified Resource Identifier with
    164      * file scheme and non-empty path component, but with undefined authority,
    165      * query or fragment components.
    166      *
    167      * @param uri
    168      *            the Unified Resource Identifier that is used to construct this
    169      *            file.
    170      * @throws IllegalArgumentException
    171      *             if {@code uri} does not comply with the conditions above.
    172      * @see #toURI
    173      * @see java.net.URI
    174      */
    175     public File(URI uri) {
    176         // check pre-conditions
    177         checkURI(uri);
    178         this.path = fixSlashes(uri.getPath());
    179     }
    180 
    181     // Removes duplicate adjacent slashes and any trailing slash.
    182     private static String fixSlashes(String origPath) {
    183         // Remove duplicate adjacent slashes.
    184         boolean lastWasSlash = false;
    185         char[] newPath = origPath.toCharArray();
    186         int length = newPath.length;
    187         int newLength = 0;
    188         for (int i = 0; i < length; ++i) {
    189             char ch = newPath[i];
    190             if (ch == '/') {
    191                 if (!lastWasSlash) {
    192                     newPath[newLength++] = separatorChar;
    193                     lastWasSlash = true;
    194                 }
    195             } else {
    196                 newPath[newLength++] = ch;
    197                 lastWasSlash = false;
    198             }
    199         }
    200         // Remove any trailing slash (unless this is the root of the file system).
    201         if (lastWasSlash && newLength > 1) {
    202             newLength--;
    203         }
    204         // Reuse the original string if possible.
    205         return (newLength != length) ? new String(newPath, 0, newLength) : origPath;
    206     }
    207 
    208     // Joins two path components, adding a separator only if necessary.
    209     private static String join(String prefix, String suffix) {
    210         int prefixLength = prefix.length();
    211         boolean haveSlash = (prefixLength > 0 && prefix.charAt(prefixLength - 1) == separatorChar);
    212         if (!haveSlash) {
    213             haveSlash = (suffix.length() > 0 && suffix.charAt(0) == separatorChar);
    214         }
    215         return haveSlash ? (prefix + suffix) : (prefix + separatorChar + suffix);
    216     }
    217 
    218     private static void checkURI(URI uri) {
    219         if (!uri.isAbsolute()) {
    220             throw new IllegalArgumentException("URI is not absolute: " + uri);
    221         } else if (!uri.getRawSchemeSpecificPart().startsWith("/")) {
    222             throw new IllegalArgumentException("URI is not hierarchical: " + uri);
    223         }
    224         if (!"file".equals(uri.getScheme())) {
    225             throw new IllegalArgumentException("Expected file scheme in URI: " + uri);
    226         }
    227         String rawPath = uri.getRawPath();
    228         if (rawPath == null || rawPath.isEmpty()) {
    229             throw new IllegalArgumentException("Expected non-empty path in URI: " + uri);
    230         }
    231         if (uri.getRawAuthority() != null) {
    232             throw new IllegalArgumentException("Found authority in URI: " + uri);
    233         }
    234         if (uri.getRawQuery() != null) {
    235             throw new IllegalArgumentException("Found query in URI: " + uri);
    236         }
    237         if (uri.getRawFragment() != null) {
    238             throw new IllegalArgumentException("Found fragment in URI: " + uri);
    239         }
    240     }
    241 
    242     /**
    243      * Returns the file system roots. On Android and other Unix systems, there is
    244      * a single root, {@code /}.
    245      */
    246     public static File[] listRoots() {
    247         return new File[] { new File("/") };
    248     }
    249 
    250     /**
    251      * Tests whether or not this process is allowed to execute this file.
    252      * Note that this is a best-effort result; the only way to be certain is
    253      * to actually attempt the operation.
    254      *
    255      * @return {@code true} if this file can be executed, {@code false} otherwise.
    256      * @since 1.6
    257      */
    258     public boolean canExecute() {
    259         return doAccess(X_OK);
    260     }
    261 
    262     /**
    263      * Indicates whether the current context is allowed to read from this file.
    264      *
    265      * @return {@code true} if this file can be read, {@code false} otherwise.
    266      */
    267     public boolean canRead() {
    268         return doAccess(R_OK);
    269     }
    270 
    271     /**
    272      * Indicates whether the current context is allowed to write to this file.
    273      *
    274      * @return {@code true} if this file can be written, {@code false}
    275      *         otherwise.
    276      */
    277     public boolean canWrite() {
    278         return doAccess(W_OK);
    279     }
    280 
    281     private boolean doAccess(int mode) {
    282         try {
    283             return Libcore.os.access(path, mode);
    284         } catch (ErrnoException errnoException) {
    285             return false;
    286         }
    287     }
    288 
    289     /**
    290      * Returns the relative sort ordering of the paths for this file and the
    291      * file {@code another}. The ordering is platform dependent.
    292      *
    293      * @param another
    294      *            a file to compare this file to
    295      * @return an int determined by comparing the two paths. Possible values are
    296      *         described in the Comparable interface.
    297      * @see Comparable
    298      */
    299     public int compareTo(File another) {
    300         return this.getPath().compareTo(another.getPath());
    301     }
    302 
    303     /**
    304      * Deletes this file. Directories must be empty before they will be deleted.
    305      *
    306      * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
    307      * Callers must check the return value.
    308      *
    309      * @return {@code true} if this file was deleted, {@code false} otherwise.
    310      */
    311     public boolean delete() {
    312         try {
    313             Libcore.os.remove(path);
    314             return true;
    315         } catch (ErrnoException errnoException) {
    316             return false;
    317         }
    318     }
    319 
    320     /**
    321      * Schedules this file to be automatically deleted when the VM terminates normally.
    322      *
    323      * <p><i>Note that on Android, the application lifecycle does not include VM termination,
    324      * so calling this method will not ensure that files are deleted</i>. Instead, you should
    325      * use the most appropriate out of:
    326      * <ul>
    327      * <li>Use a {@code finally} clause to manually invoke {@link #delete}.
    328      * <li>Maintain your own set of files to delete, and process it at an appropriate point
    329      * in your application's lifecycle.
    330      * <li>Use the Unix trick of deleting the file as soon as all readers and writers have
    331      * opened it. No new readers/writers will be able to access the file, but all existing
    332      * ones will still have access until the last one closes the file.
    333      * </ul>
    334      */
    335     public void deleteOnExit() {
    336         DeleteOnExit.getInstance().addFile(getAbsolutePath());
    337     }
    338 
    339     /**
    340      * Compares {@code obj} to this file and returns {@code true} if they
    341      * represent the <em>same</em> object using a path specific comparison.
    342      *
    343      * @param obj
    344      *            the object to compare this file with.
    345      * @return {@code true} if {@code obj} is the same as this object,
    346      *         {@code false} otherwise.
    347      */
    348     @Override
    349     public boolean equals(Object obj) {
    350         if (!(obj instanceof File)) {
    351             return false;
    352         }
    353         return path.equals(((File) obj).getPath());
    354     }
    355 
    356     /**
    357      * Returns a boolean indicating whether this file can be found on the
    358      * underlying file system.
    359      *
    360      * @return {@code true} if this file exists, {@code false} otherwise.
    361      */
    362     public boolean exists() {
    363         return doAccess(F_OK);
    364     }
    365 
    366     /**
    367      * Returns the absolute path of this file. An absolute path is a path that starts at a root
    368      * of the file system. On Android, there is only one root: {@code /}.
    369      *
    370      * <p>A common use for absolute paths is when passing paths to a {@code Process} as
    371      * command-line arguments, to remove the requirement implied by relative paths, that the
    372      * child must have the same working directory as its parent.
    373      */
    374     public String getAbsolutePath() {
    375         if (isAbsolute()) {
    376             return path;
    377         }
    378         String userDir = System.getProperty("user.dir");
    379         return path.isEmpty() ? userDir : join(userDir, path);
    380     }
    381 
    382     /**
    383      * Returns a new file constructed using the absolute path of this file.
    384      * Equivalent to {@code new File(this.getAbsolutePath())}.
    385      */
    386     public File getAbsoluteFile() {
    387         return new File(getAbsolutePath());
    388     }
    389 
    390     /**
    391      * Returns the canonical path of this file.
    392      * An <i>absolute</i> path is one that begins at the root of the file system.
    393      * A <i>canonical</i> path is an absolute path with symbolic links
    394      * and references to "." or ".." resolved. If a path element does not exist (or
    395      * is not searchable), there is a conflict between interpreting canonicalization
    396      * as a textual operation (where "a/../b" is "b" even if "a" does not exist) .
    397      *
    398      * <p>Most callers should use {@link #getAbsolutePath} instead. A canonical path is
    399      * significantly more expensive to compute, and not generally useful. The primary
    400      * use for canonical paths is determining whether two paths point to the same file by
    401      * comparing the canonicalized paths.
    402      *
    403      * <p>It can be actively harmful to use a canonical path, specifically because
    404      * canonicalization removes symbolic links. It's wise to assume that a symbolic link
    405      * is present for a reason, and that that reason is because the link may need to change.
    406      * Canonicalization removes this layer of indirection. Good code should generally avoid
    407      * caching canonical paths.
    408      *
    409      * @return the canonical path of this file.
    410      * @throws IOException
    411      *             if an I/O error occurs.
    412      */
    413     public String getCanonicalPath() throws IOException {
    414         return realpath(getAbsolutePath());
    415     }
    416 
    417     /**
    418      * TODO: move this stuff to libcore.os.
    419      * @hide
    420      */
    421     private static native String realpath(String path);
    422     private static native String readlink(String path);
    423 
    424     /**
    425      * Returns a new file created using the canonical path of this file.
    426      * Equivalent to {@code new File(this.getCanonicalPath())}.
    427      *
    428      * @return the new file constructed from this file's canonical path.
    429      * @throws IOException
    430      *             if an I/O error occurs.
    431      */
    432     public File getCanonicalFile() throws IOException {
    433         return new File(getCanonicalPath());
    434     }
    435 
    436     /**
    437      * Returns the name of the file or directory represented by this file.
    438      *
    439      * @return this file's name or an empty string if there is no name part in
    440      *         the file's path.
    441      */
    442     public String getName() {
    443         int separatorIndex = path.lastIndexOf(separator);
    444         return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length());
    445     }
    446 
    447     /**
    448      * Returns the pathname of the parent of this file. This is the path up to
    449      * but not including the last name. {@code null} is returned if there is no
    450      * parent.
    451      *
    452      * @return this file's parent pathname or {@code null}.
    453      */
    454     public String getParent() {
    455         int length = path.length(), firstInPath = 0;
    456         if (separatorChar == '\\' && length > 2 && path.charAt(1) == ':') {
    457             firstInPath = 2;
    458         }
    459         int index = path.lastIndexOf(separatorChar);
    460         if (index == -1 && firstInPath > 0) {
    461             index = 2;
    462         }
    463         if (index == -1 || path.charAt(length - 1) == separatorChar) {
    464             return null;
    465         }
    466         if (path.indexOf(separatorChar) == index
    467                 && path.charAt(firstInPath) == separatorChar) {
    468             return path.substring(0, index + 1);
    469         }
    470         return path.substring(0, index);
    471     }
    472 
    473     /**
    474      * Returns a new file made from the pathname of the parent of this file.
    475      * This is the path up to but not including the last name. {@code null} is
    476      * returned when there is no parent.
    477      *
    478      * @return a new file representing this file's parent or {@code null}.
    479      */
    480     public File getParentFile() {
    481         String tempParent = getParent();
    482         if (tempParent == null) {
    483             return null;
    484         }
    485         return new File(tempParent);
    486     }
    487 
    488     /**
    489      * Returns the path of this file.
    490      *
    491      * @return this file's path.
    492      */
    493     public String getPath() {
    494         return path;
    495     }
    496 
    497     /**
    498      * Returns an integer hash code for the receiver. Any two objects for which
    499      * {@code equals} returns {@code true} must return the same hash code.
    500      *
    501      * @return this files's hash value.
    502      * @see #equals
    503      */
    504     @Override
    505     public int hashCode() {
    506         return getPath().hashCode() ^ 1234321;
    507     }
    508 
    509     /**
    510      * Indicates if this file's pathname is absolute. Whether a pathname is
    511      * absolute is platform specific. On Android, absolute paths start with
    512      * the character '/'.
    513      *
    514      * @return {@code true} if this file's pathname is absolute, {@code false}
    515      *         otherwise.
    516      * @see #getPath
    517      */
    518     public boolean isAbsolute() {
    519         return path.length() > 0 && path.charAt(0) == separatorChar;
    520     }
    521 
    522     /**
    523      * Indicates if this file represents a <em>directory</em> on the
    524      * underlying file system.
    525      *
    526      * @return {@code true} if this file is a directory, {@code false}
    527      *         otherwise.
    528      */
    529     public boolean isDirectory() {
    530         try {
    531             return S_ISDIR(Libcore.os.stat(path).st_mode);
    532         } catch (ErrnoException errnoException) {
    533             // The RI returns false on error. (Even for errors like EACCES or ELOOP.)
    534             return false;
    535         }
    536     }
    537 
    538     /**
    539      * Indicates if this file represents a <em>file</em> on the underlying
    540      * file system.
    541      *
    542      * @return {@code true} if this file is a file, {@code false} otherwise.
    543      */
    544     public boolean isFile() {
    545         try {
    546             return S_ISREG(Libcore.os.stat(path).st_mode);
    547         } catch (ErrnoException errnoException) {
    548             // The RI returns false on error. (Even for errors like EACCES or ELOOP.)
    549             return false;
    550         }
    551     }
    552 
    553     /**
    554      * Returns whether or not this file is a hidden file as defined by the
    555      * operating system. The notion of "hidden" is system-dependent. For Unix
    556      * systems a file is considered hidden if its name starts with a ".". For
    557      * Windows systems there is an explicit flag in the file system for this
    558      * purpose.
    559      *
    560      * @return {@code true} if the file is hidden, {@code false} otherwise.
    561      */
    562     public boolean isHidden() {
    563         if (path.isEmpty()) {
    564             return false;
    565         }
    566         return getName().startsWith(".");
    567     }
    568 
    569     /**
    570      * Returns the time when this file was last modified, measured in
    571      * milliseconds since January 1st, 1970, midnight.
    572      * Returns 0 if the file does not exist.
    573      *
    574      * @return the time when this file was last modified.
    575      */
    576     public long lastModified() {
    577         try {
    578             return Libcore.os.stat(path).st_mtime * 1000L;
    579         } catch (ErrnoException errnoException) {
    580             // The RI returns 0 on error. (Even for errors like EACCES or ELOOP.)
    581             return 0;
    582         }
    583     }
    584 
    585     /**
    586      * Sets the time this file was last modified, measured in milliseconds since
    587      * January 1st, 1970, midnight.
    588      *
    589      * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
    590      * Callers must check the return value.
    591      *
    592      * @param time
    593      *            the last modification time for this file.
    594      * @return {@code true} if the operation is successful, {@code false}
    595      *         otherwise.
    596      * @throws IllegalArgumentException
    597      *             if {@code time < 0}.
    598      */
    599     public boolean setLastModified(long time) {
    600         if (time < 0) {
    601             throw new IllegalArgumentException("time < 0");
    602         }
    603         return setLastModifiedImpl(path, time);
    604     }
    605 
    606     private static native boolean setLastModifiedImpl(String path, long time);
    607 
    608     /**
    609      * Equivalent to setWritable(false, false).
    610      *
    611      * @see #setWritable(boolean, boolean)
    612      */
    613     public boolean setReadOnly() {
    614         return setWritable(false, false);
    615     }
    616 
    617     /**
    618      * Manipulates the execute permissions for the abstract path designated by
    619      * this file.
    620      *
    621      * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
    622      * Callers must check the return value.
    623      *
    624      * @param executable
    625      *            To allow execute permission if true, otherwise disallow
    626      * @param ownerOnly
    627      *            To manipulate execute permission only for owner if true,
    628      *            otherwise for everyone. The manipulation will apply to
    629      *            everyone regardless of this value if the underlying system
    630      *            does not distinguish owner and other users.
    631      * @return true if and only if the operation succeeded. If the user does not
    632      *         have permission to change the access permissions of this abstract
    633      *         pathname the operation will fail. If the underlying file system
    634      *         does not support execute permission and the value of executable
    635      *         is false, this operation will fail.
    636      * @since 1.6
    637      */
    638     public boolean setExecutable(boolean executable, boolean ownerOnly) {
    639         return doChmod(ownerOnly ? S_IXUSR : (S_IXUSR | S_IXGRP | S_IXOTH), executable);
    640     }
    641 
    642     /**
    643      * Equivalent to setExecutable(executable, true).
    644      * @see #setExecutable(boolean, boolean)
    645      * @since 1.6
    646      */
    647     public boolean setExecutable(boolean executable) {
    648         return setExecutable(executable, true);
    649     }
    650 
    651     /**
    652      * Manipulates the read permissions for the abstract path designated by this
    653      * file.
    654      *
    655      * @param readable
    656      *            To allow read permission if true, otherwise disallow
    657      * @param ownerOnly
    658      *            To manipulate read permission only for owner if true,
    659      *            otherwise for everyone. The manipulation will apply to
    660      *            everyone regardless of this value if the underlying system
    661      *            does not distinguish owner and other users.
    662      * @return true if and only if the operation succeeded. If the user does not
    663      *         have permission to change the access permissions of this abstract
    664      *         pathname the operation will fail. If the underlying file system
    665      *         does not support read permission and the value of readable is
    666      *         false, this operation will fail.
    667      * @since 1.6
    668      */
    669     public boolean setReadable(boolean readable, boolean ownerOnly) {
    670         return doChmod(ownerOnly ? S_IRUSR : (S_IRUSR | S_IRGRP | S_IROTH), readable);
    671     }
    672 
    673     /**
    674      * Equivalent to setReadable(readable, true).
    675      * @see #setReadable(boolean, boolean)
    676      * @since 1.6
    677      */
    678     public boolean setReadable(boolean readable) {
    679         return setReadable(readable, true);
    680     }
    681 
    682     /**
    683      * Manipulates the write permissions for the abstract path designated by this
    684      * file.
    685      *
    686      * @param writable
    687      *            To allow write permission if true, otherwise disallow
    688      * @param ownerOnly
    689      *            To manipulate write permission only for owner if true,
    690      *            otherwise for everyone. The manipulation will apply to
    691      *            everyone regardless of this value if the underlying system
    692      *            does not distinguish owner and other users.
    693      * @return true if and only if the operation succeeded. If the user does not
    694      *         have permission to change the access permissions of this abstract
    695      *         pathname the operation will fail.
    696      * @since 1.6
    697      */
    698     public boolean setWritable(boolean writable, boolean ownerOnly) {
    699         return doChmod(ownerOnly ? S_IWUSR : (S_IWUSR | S_IWGRP | S_IWOTH), writable);
    700     }
    701 
    702     /**
    703      * Equivalent to setWritable(writable, true).
    704      * @see #setWritable(boolean, boolean)
    705      * @since 1.6
    706      */
    707     public boolean setWritable(boolean writable) {
    708         return setWritable(writable, true);
    709     }
    710 
    711     private boolean doChmod(int mask, boolean set) {
    712         try {
    713             StructStat sb = Libcore.os.stat(path);
    714             int newMode = set ? (sb.st_mode | mask) : (sb.st_mode & ~mask);
    715             Libcore.os.chmod(path, newMode);
    716             return true;
    717         } catch (ErrnoException errnoException) {
    718             return false;
    719         }
    720     }
    721 
    722     /**
    723      * Returns the length of this file in bytes.
    724      * Returns 0 if the file does not exist.
    725      * The result for a directory is not defined.
    726      *
    727      * @return the number of bytes in this file.
    728      */
    729     public long length() {
    730         try {
    731             return Libcore.os.stat(path).st_size;
    732         } catch (ErrnoException errnoException) {
    733             // The RI returns 0 on error. (Even for errors like EACCES or ELOOP.)
    734             return 0;
    735         }
    736     }
    737 
    738     /**
    739      * Returns an array of strings with the file names in the directory
    740      * represented by this file. The result is {@code null} if this file is not
    741      * a directory.
    742      * <p>
    743      * The entries {@code .} and {@code ..} representing the current and parent
    744      * directory are not returned as part of the list.
    745      *
    746      * @return an array of strings with file names or {@code null}.
    747      */
    748     public String[] list() {
    749         return listImpl(path);
    750     }
    751 
    752     private static native String[] listImpl(String path);
    753 
    754     /**
    755      * Gets a list of the files in the directory represented by this file. This
    756      * list is then filtered through a FilenameFilter and the names of files
    757      * with matching names are returned as an array of strings. Returns
    758      * {@code null} if this file is not a directory. If {@code filter} is
    759      * {@code null} then all filenames match.
    760      * <p>
    761      * The entries {@code .} and {@code ..} representing the current and parent
    762      * directories are not returned as part of the list.
    763      *
    764      * @param filter
    765      *            the filter to match names against, may be {@code null}.
    766      * @return an array of files or {@code null}.
    767      */
    768     public String[] list(FilenameFilter filter) {
    769         String[] filenames = list();
    770         if (filter == null || filenames == null) {
    771             return filenames;
    772         }
    773         List<String> result = new ArrayList<String>(filenames.length);
    774         for (String filename : filenames) {
    775             if (filter.accept(this, filename)) {
    776                 result.add(filename);
    777             }
    778         }
    779         return result.toArray(new String[result.size()]);
    780     }
    781 
    782     /**
    783      * Returns an array of files contained in the directory represented by this
    784      * file. The result is {@code null} if this file is not a directory. The
    785      * paths of the files in the array are absolute if the path of this file is
    786      * absolute, they are relative otherwise.
    787      *
    788      * @return an array of files or {@code null}.
    789      */
    790     public File[] listFiles() {
    791         return filenamesToFiles(list());
    792     }
    793 
    794     /**
    795      * Gets a list of the files in the directory represented by this file. This
    796      * list is then filtered through a FilenameFilter and files with matching
    797      * names are returned as an array of files. Returns {@code null} if this
    798      * file is not a directory. If {@code filter} is {@code null} then all
    799      * filenames match.
    800      * <p>
    801      * The entries {@code .} and {@code ..} representing the current and parent
    802      * directories are not returned as part of the list.
    803      *
    804      * @param filter
    805      *            the filter to match names against, may be {@code null}.
    806      * @return an array of files or {@code null}.
    807      */
    808     public File[] listFiles(FilenameFilter filter) {
    809         return filenamesToFiles(list(filter));
    810     }
    811 
    812     /**
    813      * Gets a list of the files in the directory represented by this file. This
    814      * list is then filtered through a FileFilter and matching files are
    815      * returned as an array of files. Returns {@code null} if this file is not a
    816      * directory. If {@code filter} is {@code null} then all files match.
    817      * <p>
    818      * The entries {@code .} and {@code ..} representing the current and parent
    819      * directories are not returned as part of the list.
    820      *
    821      * @param filter
    822      *            the filter to match names against, may be {@code null}.
    823      * @return an array of files or {@code null}.
    824      */
    825     public File[] listFiles(FileFilter filter) {
    826         File[] files = listFiles();
    827         if (filter == null || files == null) {
    828             return files;
    829         }
    830         List<File> result = new ArrayList<File>(files.length);
    831         for (File file : files) {
    832             if (filter.accept(file)) {
    833                 result.add(file);
    834             }
    835         }
    836         return result.toArray(new File[result.size()]);
    837     }
    838 
    839     /**
    840      * Converts a String[] containing filenames to a File[].
    841      * Note that the filenames must not contain slashes.
    842      * This method is to remove duplication in the implementation
    843      * of File.list's overloads.
    844      */
    845     private File[] filenamesToFiles(String[] filenames) {
    846         if (filenames == null) {
    847             return null;
    848         }
    849         int count = filenames.length;
    850         File[] result = new File[count];
    851         for (int i = 0; i < count; ++i) {
    852             result[i] = new File(this, filenames[i]);
    853         }
    854         return result;
    855     }
    856 
    857     /**
    858      * Creates the directory named by the trailing filename of this file. Does
    859      * not create the complete path required to create this directory.
    860      *
    861      * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
    862      * Callers must check the return value.
    863      *
    864      * @return {@code true} if the directory has been created, {@code false}
    865      *         otherwise.
    866      * @see #mkdirs
    867      */
    868     public boolean mkdir() {
    869         try {
    870             // On Android, we don't want default permissions to allow global access.
    871             Libcore.os.mkdir(path, S_IRWXU);
    872             return true;
    873         } catch (ErrnoException errnoException) {
    874             return false;
    875         }
    876     }
    877 
    878     /**
    879      * Creates the directory named by the trailing filename of this file,
    880      * including the complete directory path required to create this directory.
    881      *
    882      * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
    883      * Callers must check the return value.
    884      *
    885      * @return {@code true} if the necessary directories have been created,
    886      *         {@code false} if the target directory already exists or one of
    887      *         the directories can not be created.
    888      * @see #mkdir
    889      */
    890     public boolean mkdirs() {
    891         /* If the terminal directory already exists, answer false */
    892         if (exists()) {
    893             return false;
    894         }
    895 
    896         /* If the receiver can be created, answer true */
    897         if (mkdir()) {
    898             return true;
    899         }
    900 
    901         String parentDir = getParent();
    902         /* If there is no parent and we were not created, answer false */
    903         if (parentDir == null) {
    904             return false;
    905         }
    906 
    907         /* Otherwise, try to create a parent directory and then this directory */
    908         return (new File(parentDir).mkdirs() && mkdir());
    909     }
    910 
    911     /**
    912      * Creates a new, empty file on the file system according to the path
    913      * information stored in this file. This method returns true if it creates
    914      * a file, false if the file already existed. Note that it returns false
    915      * even if the file is not a file (because it's a directory, say).
    916      *
    917      * <p>This method is not generally useful. For creating temporary files,
    918      * use {@link #createTempFile} instead. For reading/writing files, use {@link FileInputStream},
    919      * {@link FileOutputStream}, or {@link RandomAccessFile}, all of which can create files.
    920      *
    921      * <p>Note that this method does <i>not</i> throw {@code IOException} if the file
    922      * already exists, even if it's not a regular file. Callers should always check the
    923      * return value, and may additionally want to call {@link #isFile}.
    924      *
    925      * @return true if the file has been created, false if it
    926      *         already exists.
    927      * @throws IOException if it's not possible to create the file.
    928      */
    929     public boolean createNewFile() throws IOException {
    930         FileDescriptor fd = null;
    931         try {
    932             // On Android, we don't want default permissions to allow global access.
    933             fd = Libcore.os.open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
    934             return true;
    935         } catch (ErrnoException errnoException) {
    936             if (errnoException.errno == EEXIST) {
    937                 // The file already exists.
    938                 return false;
    939             }
    940             throw errnoException.rethrowAsIOException();
    941         } finally {
    942             IoUtils.close(fd); // TODO: should we suppress IOExceptions thrown here?
    943         }
    944     }
    945 
    946     /**
    947      * Creates an empty temporary file using the given prefix and suffix as part
    948      * of the file name. If {@code suffix} is null, {@code .tmp} is used. This
    949      * method is a convenience method that calls
    950      * {@link #createTempFile(String, String, File)} with the third argument
    951      * being {@code null}.
    952      *
    953      * @param prefix
    954      *            the prefix to the temp file name.
    955      * @param suffix
    956      *            the suffix to the temp file name.
    957      * @return the temporary file.
    958      * @throws IOException
    959      *             if an error occurs when writing the file.
    960      */
    961     public static File createTempFile(String prefix, String suffix) throws IOException {
    962         return createTempFile(prefix, suffix, null);
    963     }
    964 
    965     /**
    966      * Creates an empty temporary file in the given directory using the given
    967      * prefix and suffix as part of the file name. If {@code suffix} is null, {@code .tmp} is used.
    968      *
    969      * <p>Note that this method does <i>not</i> call {@link #deleteOnExit}, but see the
    970      * documentation for that method before you call it manually.
    971      *
    972      * @param prefix
    973      *            the prefix to the temp file name.
    974      * @param suffix
    975      *            the suffix to the temp file name.
    976      * @param directory
    977      *            the location to which the temp file is to be written, or
    978      *            {@code null} for the default location for temporary files,
    979      *            which is taken from the "java.io.tmpdir" system property. It
    980      *            may be necessary to set this property to an existing, writable
    981      *            directory for this method to work properly.
    982      * @return the temporary file.
    983      * @throws IllegalArgumentException
    984      *             if the length of {@code prefix} is less than 3.
    985      * @throws IOException
    986      *             if an error occurs when writing the file.
    987      */
    988     public static File createTempFile(String prefix, String suffix, File directory)
    989             throws IOException {
    990         // Force a prefix null check first
    991         if (prefix.length() < 3) {
    992             throw new IllegalArgumentException("prefix must be at least 3 characters");
    993         }
    994         if (suffix == null) {
    995             suffix = ".tmp";
    996         }
    997         File tmpDirFile = directory;
    998         if (tmpDirFile == null) {
    999             String tmpDir = System.getProperty("java.io.tmpdir", ".");
   1000             tmpDirFile = new File(tmpDir);
   1001         }
   1002         File result;
   1003         do {
   1004             result = new File(tmpDirFile, prefix + tempFileRandom.nextInt() + suffix);
   1005         } while (!result.createNewFile());
   1006         return result;
   1007     }
   1008 
   1009     /**
   1010      * Renames this file to {@code newPath}. This operation is supported for both
   1011      * files and directories.
   1012      *
   1013      * <p>Many failures are possible. Some of the more likely failures include:
   1014      * <ul>
   1015      * <li>Write permission is required on the directories containing both the source and
   1016      * destination paths.
   1017      * <li>Search permission is required for all parents of both paths.
   1018      * <li>Both paths be on the same mount point. On Android, applications are most likely to hit
   1019      * this restriction when attempting to copy between internal storage and an SD card.
   1020      * </ul>
   1021      *
   1022      * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
   1023      * Callers must check the return value.
   1024      *
   1025      * @param newPath the new path.
   1026      * @return true on success.
   1027      */
   1028     public boolean renameTo(File newPath) {
   1029         try {
   1030             Libcore.os.rename(path, newPath.path);
   1031             return true;
   1032         } catch (ErrnoException errnoException) {
   1033             return false;
   1034         }
   1035     }
   1036 
   1037     /**
   1038      * Returns a string containing a concise, human-readable description of this
   1039      * file.
   1040      *
   1041      * @return a printable representation of this file.
   1042      */
   1043     @Override
   1044     public String toString() {
   1045         return path;
   1046     }
   1047 
   1048     /**
   1049      * Returns a Uniform Resource Identifier for this file. The URI is system
   1050      * dependent and may not be transferable between different operating / file
   1051      * systems.
   1052      *
   1053      * @return an URI for this file.
   1054      */
   1055     public URI toURI() {
   1056         String name = getAbsoluteName();
   1057         try {
   1058             if (!name.startsWith("/")) {
   1059                 // start with sep.
   1060                 return new URI("file", null, "/" + name, null, null);
   1061             } else if (name.startsWith("//")) {
   1062                 return new URI("file", "", name, null); // UNC path
   1063             }
   1064             return new URI("file", null, name, null, null);
   1065         } catch (URISyntaxException e) {
   1066             // this should never happen
   1067             return null;
   1068         }
   1069     }
   1070 
   1071     /**
   1072      * Returns a Uniform Resource Locator for this file. The URL is system
   1073      * dependent and may not be transferable between different operating / file
   1074      * systems.
   1075      *
   1076      * @return a URL for this file.
   1077      * @throws java.net.MalformedURLException
   1078      *             if the path cannot be transformed into a URL.
   1079      * @deprecated use {@link #toURI} and {@link java.net.URI#toURL} to get
   1080      * correct escaping of illegal characters.
   1081      */
   1082     @Deprecated
   1083     public URL toURL() throws java.net.MalformedURLException {
   1084         String name = getAbsoluteName();
   1085         if (!name.startsWith("/")) {
   1086             // start with sep.
   1087             return new URL("file", "", -1, "/" + name, null);
   1088         } else if (name.startsWith("//")) {
   1089             return new URL("file:" + name); // UNC path
   1090         }
   1091         return new URL("file", "", -1, name, null);
   1092     }
   1093 
   1094     // TODO: is this really necessary, or can it be replaced with getAbsolutePath?
   1095     private String getAbsoluteName() {
   1096         File f = getAbsoluteFile();
   1097         String name = f.getPath();
   1098         if (f.isDirectory() && name.charAt(name.length() - 1) != separatorChar) {
   1099             // Directories must end with a slash
   1100             name = name + "/";
   1101         }
   1102         if (separatorChar != '/') { // Must convert slashes.
   1103             name = name.replace(separatorChar, '/');
   1104         }
   1105         return name;
   1106     }
   1107 
   1108     private void writeObject(ObjectOutputStream stream) throws IOException {
   1109         stream.defaultWriteObject();
   1110         stream.writeChar(separatorChar);
   1111     }
   1112 
   1113     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
   1114         stream.defaultReadObject();
   1115         char inSeparator = stream.readChar();
   1116         this.path = fixSlashes(path.replace(inSeparator, separatorChar));
   1117     }
   1118 
   1119     /**
   1120      * Returns the total size in bytes of the partition containing this path.
   1121      * Returns 0 if this path does not exist.
   1122      *
   1123      * @since 1.6
   1124      */
   1125     public long getTotalSpace() {
   1126         try {
   1127             StructStatFs sb = Libcore.os.statfs(path);
   1128             return sb.f_blocks * sb.f_bsize; // total block count * block size in bytes.
   1129         } catch (ErrnoException errnoException) {
   1130             return 0;
   1131         }
   1132     }
   1133 
   1134     /**
   1135      * Returns the number of usable free bytes on the partition containing this path.
   1136      * Returns 0 if this path does not exist.
   1137      *
   1138      * <p>Note that this is likely to be an optimistic over-estimate and should not
   1139      * be taken as a guarantee your application can actually write this many bytes.
   1140      * On Android (and other Unix-based systems), this method returns the number of free bytes
   1141      * available to non-root users, regardless of whether you're actually running as root,
   1142      * and regardless of any quota or other restrictions that might apply to the user.
   1143      * (The {@code getFreeSpace} method returns the number of bytes potentially available to root.)
   1144      *
   1145      * @since 1.6
   1146      */
   1147     public long getUsableSpace() {
   1148         try {
   1149             StructStatFs sb = Libcore.os.statfs(path);
   1150             return sb.f_bavail * sb.f_bsize; // non-root free block count * block size in bytes.
   1151         } catch (ErrnoException errnoException) {
   1152             return 0;
   1153         }
   1154     }
   1155 
   1156     /**
   1157      * Returns the number of free bytes on the partition containing this path.
   1158      * Returns 0 if this path does not exist.
   1159      *
   1160      * <p>Note that this is likely to be an optimistic over-estimate and should not
   1161      * be taken as a guarantee your application can actually write this many bytes.
   1162      *
   1163      * @since 1.6
   1164      */
   1165     public long getFreeSpace() {
   1166         try {
   1167             StructStatFs sb = Libcore.os.statfs(path);
   1168             return sb.f_bfree * sb.f_bsize; // free block count * block size in bytes.
   1169         } catch (ErrnoException errnoException) {
   1170             return 0;
   1171         }
   1172     }
   1173 }
   1174