1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  the License.  You may obtain a copy of the License at
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *  limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.io;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
205d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.ErrnoException;
215d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructStat;
225d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructStatVfs;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.URI;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.URISyntaxException;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.net.URL;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.List;
285d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughesimport java.util.Random;
293a134c58302d6acf59336a4d7d0a70d574ffd493Narayan Kamathimport libcore.io.DeleteOnExit;
302ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughesimport libcore.io.IoUtils;
31ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughesimport libcore.io.Libcore;
325d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport static android.system.OsConstants.*;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * An "abstract" representation of a file system entity identified by a
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * pathname. The pathname may be absolute (relative to the root directory
37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * of the file system) or relative to the current directory in which the program
38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * is running.
39344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes *
40344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes * <p>The actual file referenced by a {@code File} may or may not exist. It may
410af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes * also, despite the name {@code File}, be a directory or other non-regular
420af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes * file.
43344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes *
44344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes * <p>This class provides limited functionality for getting/setting file
450af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes * permissions, file type, and last modified time.
46344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes *
47344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes * <p>On Android strings are converted to UTF-8 byte sequences when sending filenames to
48344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes * the operating system, and byte sequences returned by the operating system (from the
49344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes * various {@code list} methods) are converted to strings by decoding them as UTF-8
50344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes * byte sequences.
51f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson *
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.io.Serializable
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see java.lang.Comparable
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class File implements Serializable, Comparable<File> {
56f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static final long serialVersionUID = 301077366599181567L;
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
59adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
600e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * The system-dependent character used to separate components in filenames ('/').
610e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * Use of this (rather than hard-coding '/') helps portability to other operating systems.
620e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     *
630e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * <p>This field is initialized from the system property "file.separator".
64070f14c41b2494fd008afc4d96b873873692945fElliott Hughes     * Later changes to that property will have no effect on this field or this class.
65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static final char separatorChar;
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
690e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * The system-dependent string used to separate components in filenames ('/').
700e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * See {@link #separatorChar}.
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static final String separator;
73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
750e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * The system-dependent character used to separate components in search paths (':').
760e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * This is used to split such things as the PATH environment variable and classpath
770e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * system properties into lists of directories to be searched.
780e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     *
790e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * <p>This field is initialized from the system property "path.separator".
80070f14c41b2494fd008afc4d96b873873692945fElliott Hughes     * Later changes to that property will have no effect on this field or this class.
81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static final char pathSeparatorChar;
83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
850e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * The system-dependent string used to separate components in search paths (":").
860e8cadc6caf397fdfca97505978defdc6953a714Elliott Hughes     * See {@link #pathSeparatorChar}.
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static final String pathSeparator;
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
90070f14c41b2494fd008afc4d96b873873692945fElliott Hughes    /**
91070f14c41b2494fd008afc4d96b873873692945fElliott Hughes     * The path we return from getPath. This is almost the path we were
92070f14c41b2494fd008afc4d96b873873692945fElliott Hughes     * given, but without duplicate adjacent slashes and without trailing
93070f14c41b2494fd008afc4d96b873873692945fElliott Hughes     * slashes (except for the special case of the root directory). This
94070f14c41b2494fd008afc4d96b873873692945fElliott Hughes     * path may be the empty string.
956c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes     *
966c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes     * This can't be final because we override readObject.
97070f14c41b2494fd008afc4d96b873873692945fElliott Hughes     */
98070f14c41b2494fd008afc4d96b873873692945fElliott Hughes    private String path;
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    static {
101f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        separatorChar = System.getProperty("file.separator", "/").charAt(0);
102f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        pathSeparatorChar = System.getProperty("path.separator", ":").charAt(0);
103070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        separator = String.valueOf(separatorChar);
104070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        pathSeparator = String.valueOf(pathSeparatorChar);
105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new file using the specified directory and name.
109f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param dir
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the directory where the file is stored.
112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the file's name.
114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
115f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *             if {@code name} is {@code null}.
116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File(File dir, String name) {
11893a4b2a6cc35a72aa5a58027025f3e18c0ec2e64Elliott Hughes        this(dir == null ? null : dir.getPath(), name);
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new file using the specified path.
123f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param path
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the path to be used for the file.
12658967d946493826848ff23fa3e27635a29ea6f2bElliott Hughes     * @throws NullPointerException
12758967d946493826848ff23fa3e27635a29ea6f2bElliott Hughes     *             if {@code path} is {@code null}.
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File(String path) {
1306c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        this.path = fixSlashes(path);
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new File using the specified directory path and file name,
135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * placing a path separator between the two.
136f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param dirPath
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the path to the directory where the file is stored.
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param name
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the file's name.
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws NullPointerException
1426c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes     *             if {@code name == null}.
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File(String dirPath, String name) {
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (name == null) {
14686acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("name == null");
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
148ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes        if (dirPath == null || dirPath.isEmpty()) {
1496c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes            this.path = fixSlashes(name);
150ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes        } else if (name.isEmpty()) {
1516c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes            this.path = fixSlashes(dirPath);
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } else {
1536c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes            this.path = fixSlashes(join(dirPath, name));
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Constructs a new File using the path of the specified URI. {@code uri}
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * needs to be an absolute and hierarchical Unified Resource Identifier with
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * file scheme and non-empty path component, but with undefined authority,
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * query or fragment components.
162f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param uri
164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the Unified Resource Identifier that is used to construct this
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            file.
16658967d946493826848ff23fa3e27635a29ea6f2bElliott Hughes     * @throws NullPointerException
16758967d946493826848ff23fa3e27635a29ea6f2bElliott Hughes     *             if {@code uri == null}.
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code uri} does not comply with the conditions above.
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #toURI
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see java.net.URI
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File(URI uri) {
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // check pre-conditions
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        checkURI(uri);
1766c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        this.path = fixSlashes(uri.getPath());
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
179070f14c41b2494fd008afc4d96b873873692945fElliott Hughes    // Removes duplicate adjacent slashes and any trailing slash.
1806c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes    private static String fixSlashes(String origPath) {
181070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        // Remove duplicate adjacent slashes.
182070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        boolean lastWasSlash = false;
183070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        char[] newPath = origPath.toCharArray();
184070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        int length = newPath.length;
185070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        int newLength = 0;
186070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        for (int i = 0; i < length; ++i) {
187070f14c41b2494fd008afc4d96b873873692945fElliott Hughes            char ch = newPath[i];
188070f14c41b2494fd008afc4d96b873873692945fElliott Hughes            if (ch == '/') {
189070f14c41b2494fd008afc4d96b873873692945fElliott Hughes                if (!lastWasSlash) {
190070f14c41b2494fd008afc4d96b873873692945fElliott Hughes                    newPath[newLength++] = separatorChar;
191070f14c41b2494fd008afc4d96b873873692945fElliott Hughes                    lastWasSlash = true;
192070f14c41b2494fd008afc4d96b873873692945fElliott Hughes                }
193070f14c41b2494fd008afc4d96b873873692945fElliott Hughes            } else {
194070f14c41b2494fd008afc4d96b873873692945fElliott Hughes                newPath[newLength++] = ch;
195070f14c41b2494fd008afc4d96b873873692945fElliott Hughes                lastWasSlash = false;
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
198070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        // Remove any trailing slash (unless this is the root of the file system).
199070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        if (lastWasSlash && newLength > 1) {
200070f14c41b2494fd008afc4d96b873873692945fElliott Hughes            newLength--;
201070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        }
202070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        // Reuse the original string if possible.
203070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        return (newLength != length) ? new String(newPath, 0, newLength) : origPath;
204070f14c41b2494fd008afc4d96b873873692945fElliott Hughes    }
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
206070f14c41b2494fd008afc4d96b873873692945fElliott Hughes    // Joins two path components, adding a separator only if necessary.
2076c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes    private static String join(String prefix, String suffix) {
208070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        int prefixLength = prefix.length();
209070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        boolean haveSlash = (prefixLength > 0 && prefix.charAt(prefixLength - 1) == separatorChar);
210070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        if (!haveSlash) {
211070f14c41b2494fd008afc4d96b873873692945fElliott Hughes            haveSlash = (suffix.length() > 0 && suffix.charAt(0) == separatorChar);
212070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        }
213070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        return haveSlash ? (prefix + suffix) : (prefix + separatorChar + suffix);
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2166c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes    private static void checkURI(URI uri) {
217adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!uri.isAbsolute()) {
218b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("URI is not absolute: " + uri);
219f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        } else if (!uri.getRawSchemeSpecificPart().startsWith("/")) {
220b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("URI is not hierarchical: " + uri);
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
222e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilson        if (!"file".equals(uri.getScheme())) {
223b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("Expected file scheme in URI: " + uri);
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
225e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilson        String rawPath = uri.getRawPath();
226e32b21f14d52bac429a9c54fe031f9e92c911d64Jesse Wilson        if (rawPath == null || rawPath.isEmpty()) {
227b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("Expected non-empty path in URI: " + uri);
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (uri.getRawAuthority() != null) {
230b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("Found authority in URI: " + uri);
231adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
232adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (uri.getRawQuery() != null) {
233b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("Found query in URI: " + uri);
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
235adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (uri.getRawFragment() != null) {
236b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("Found fragment in URI: " + uri);
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
240adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
241344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes     * Returns the file system roots. On Android and other Unix systems, there is
242344110141de805108972f0ad24f16de59ba2aa32Elliott Hughes     * a single root, {@code /}.
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public static File[] listRoots() {
24587415b1521402398d4470aecbef7c126a6948290Elliott Hughes        return new File[] { new File("/") };
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
24908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Tests whether or not this process is allowed to execute this file.
25008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Note that this is a best-effort result; the only way to be certain is
25108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * to actually attempt the operation.
25208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
25308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @return {@code true} if this file can be executed, {@code false} otherwise.
25408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
25508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
25608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public boolean canExecute() {
2576c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        return doAccess(X_OK);
25808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
25908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
26008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates whether the current context is allowed to read from this file.
262f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this file can be read, {@code false} otherwise.
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canRead() {
2666c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        return doAccess(R_OK);
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
2680af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
270adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates whether the current context is allowed to write to this file.
271f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this file can be written, {@code false}
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         otherwise.
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean canWrite() {
2766c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        return doAccess(W_OK);
277ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes    }
278ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes
2796c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes    private boolean doAccess(int mode) {
280ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes        try {
281b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            return Libcore.os.access(path, mode);
2826c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        } catch (ErrnoException errnoException) {
283ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes            return false;
284ddfdbb9d172fe9b72e08e8d7deab0aa3b8acf044Elliott Hughes        }
285adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
2860af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the relative sort ordering of the paths for this file and the
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * file {@code another}. The ordering is platform dependent.
290f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
291adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param another
292adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            a file to compare this file to
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an int determined by comparing the two paths. Possible values are
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         described in the Comparable interface.
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see Comparable
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int compareTo(File another) {
298070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        return this.getPath().compareTo(another.getPath());
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
300adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
302adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Deletes this file. Directories must be empty before they will be deleted.
303f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
304ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
305ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * Callers must check the return value.
306ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     *
307adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this file was deleted, {@code false} otherwise.
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean delete() {
310c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes        try {
311c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes            Libcore.os.remove(path);
312c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes            return true;
313c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes        } catch (ErrnoException errnoException) {
314c5c9c667028146ab5f5e446c44f911c2fdd7dd30Elliott Hughes            return false;
315c5c9c667028146ab5f5e446c44f911c2fdd7dd30Elliott Hughes        }
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
31916b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * Schedules this file to be automatically deleted when the VM terminates normally.
32016b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     *
32116b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * <p><i>Note that on Android, the application lifecycle does not include VM termination,
32216b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * so calling this method will not ensure that files are deleted</i>. Instead, you should
32316b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * use the most appropriate out of:
32416b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * <ul>
32516b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * <li>Use a {@code finally} clause to manually invoke {@link #delete}.
32616b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * <li>Maintain your own set of files to delete, and process it at an appropriate point
32716b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * in your application's lifecycle.
32816b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * <li>Use the Unix trick of deleting the file as soon as all readers and writers have
32916b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * opened it. No new readers/writers will be able to access the file, but all existing
33016b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * ones will still have access until the last one closes the file.
33116b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * </ul>
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public void deleteOnExit() {
3346c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        DeleteOnExit.getInstance().addFile(getAbsolutePath());
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Compares {@code obj} to this file and returns {@code true} if they
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * represent the <em>same</em> object using a path specific comparison.
340f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param obj
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the object to compare this file with.
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if {@code obj} is the same as this object,
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         {@code false} otherwise.
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean equals(Object obj) {
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!(obj instanceof File)) {
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return path.equals(((File) obj).getPath());
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a boolean indicating whether this file can be found on the
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * underlying file system.
357f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this file exists, {@code false} otherwise.
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean exists() {
3616c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        return doAccess(F_OK);
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
36595101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * Returns the absolute path of this file. An absolute path is a path that starts at a root
36695101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * of the file system. On Android, there is only one root: {@code /}.
367f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
36895101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * <p>A common use for absolute paths is when passing paths to a {@code Process} as
36995101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * command-line arguments, to remove the requirement implied by relative paths, that the
37095101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * child must have the same working directory as its parent.
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getAbsolutePath() {
3736c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        if (isAbsolute()) {
3746c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes            return path;
3756c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        }
3766c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        String userDir = System.getProperty("user.dir");
3776c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        return path.isEmpty() ? userDir : join(userDir, path);
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a new file constructed using the absolute path of this file.
38295101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * Equivalent to {@code new File(this.getAbsolutePath())}.
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File getAbsoluteFile() {
3856c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        return new File(getAbsolutePath());
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
38995101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * Returns the canonical path of this file.
39095101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * An <i>absolute</i> path is one that begins at the root of the file system.
39195101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * A <i>canonical</i> path is an absolute path with symbolic links
39295101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * and references to "." or ".." resolved. If a path element does not exist (or
39395101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * is not searchable), there is a conflict between interpreting canonicalization
39495101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * as a textual operation (where "a/../b" is "b" even if "a" does not exist) .
39595101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     *
39695101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * <p>Most callers should use {@link #getAbsolutePath} instead. A canonical path is
39795101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * significantly more expensive to compute, and not generally useful. The primary
39895101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * use for canonical paths is determining whether two paths point to the same file by
39995101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * comparing the canonicalized paths.
40095101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     *
40195101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * <p>It can be actively harmful to use a canonical path, specifically because
40295101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * canonicalization removes symbolic links. It's wise to assume that a symbolic link
40395101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * is present for a reason, and that that reason is because the link may need to change.
40495101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * Canonicalization removes this layer of indirection. Good code should generally avoid
40595101d3d5a3417755c88fded1600e039fb363019Elliott Hughes     * caching canonical paths.
406f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
407adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the canonical path of this file.
408adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
409adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an I/O error occurs.
410adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
411adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getCanonicalPath() throws IOException {
412081c0de9231d6fc2aa5e24bdcc21b5cde8a30f2bElliott Hughes        return canonicalizePath(getAbsolutePath());
413f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson    }
414f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson
415081c0de9231d6fc2aa5e24bdcc21b5cde8a30f2bElliott Hughes    private static native String canonicalizePath(String path);
416081c0de9231d6fc2aa5e24bdcc21b5cde8a30f2bElliott Hughes
41795101d3d5a3417755c88fded1600e039fb363019Elliott Hughes    /**
418adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a new file created using the canonical path of this file.
419adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Equivalent to {@code new File(this.getCanonicalPath())}.
420f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
421adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the new file constructed from this file's canonical path.
422adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
423adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an I/O error occurs.
424adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
425adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File getCanonicalFile() throws IOException {
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new File(getCanonicalPath());
427adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
429adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
430adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the name of the file or directory represented by this file.
431f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
432adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this file's name or an empty string if there is no name part in
433adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         the file's path.
434adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
435adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getName() {
436adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int separatorIndex = path.lastIndexOf(separator);
437aaacdb095b10293286adbfd94af2fd83b8dae3a8Elliott Hughes        return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length());
438adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
439adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
440adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
441adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the pathname of the parent of this file. This is the path up to
442adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * but not including the last name. {@code null} is returned if there is no
443adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * parent.
444f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
445adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this file's parent pathname or {@code null}.
446adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
447adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getParent() {
448adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int length = path.length(), firstInPath = 0;
449adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (separatorChar == '\\' && length > 2 && path.charAt(1) == ':') {
450adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            firstInPath = 2;
451adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
452adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        int index = path.lastIndexOf(separatorChar);
453adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (index == -1 && firstInPath > 0) {
454adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            index = 2;
455adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
456adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (index == -1 || path.charAt(length - 1) == separatorChar) {
457adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
458adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
459adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (path.indexOf(separatorChar) == index
460adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                && path.charAt(firstInPath) == separatorChar) {
461adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return path.substring(0, index + 1);
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
463adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return path.substring(0, index);
464adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
465adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
466adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
467adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a new file made from the pathname of the parent of this file.
468adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This is the path up to but not including the last name. {@code null} is
469adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * returned when there is no parent.
470f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
471adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a new file representing this file's parent or {@code null}.
472adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
473adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File getParentFile() {
474adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String tempParent = getParent();
475adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (tempParent == null) {
476adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
477adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
478adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return new File(tempParent);
479adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
480adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
481adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
482adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the path of this file.
483adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
484adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String getPath() {
485adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return path;
486adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
487adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
488adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
489adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an integer hash code for the receiver. Any two objects for which
490adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * {@code equals} returns {@code true} must return the same hash code.
491f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
492adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return this files's hash value.
493adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #equals
494adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
495adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
496adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int hashCode() {
497070f14c41b2494fd008afc4d96b873873692945fElliott Hughes        return getPath().hashCode() ^ 1234321;
498adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
499adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
500adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
501adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates if this file's pathname is absolute. Whether a pathname is
5020af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * absolute is platform specific. On Android, absolute paths start with
5030af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * the character '/'.
50408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
505adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this file's pathname is absolute, {@code false}
506adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         otherwise.
507adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @see #getPath
508adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
509adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean isAbsolute() {
510adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return path.length() > 0 && path.charAt(0) == separatorChar;
511adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
512adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
513adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
514adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates if this file represents a <em>directory</em> on the
515adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * underlying file system.
516f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
517adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this file is a directory, {@code false}
518adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         otherwise.
519adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
520adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean isDirectory() {
52147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        try {
522b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            return S_ISDIR(Libcore.os.stat(path).st_mode);
5236c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        } catch (ErrnoException errnoException) {
52447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes            // The RI returns false on error. (Even for errors like EACCES or ELOOP.)
52547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes            return false;
52647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        }
527adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
528adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
529adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
530adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates if this file represents a <em>file</em> on the underlying
531adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * file system.
532f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if this file is a file, {@code false} otherwise.
534adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
535adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean isFile() {
53647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        try {
537b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            return S_ISREG(Libcore.os.stat(path).st_mode);
5386c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        } catch (ErrnoException errnoException) {
53947cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes            // The RI returns false on error. (Even for errors like EACCES or ELOOP.)
54047cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes            return false;
54147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        }
542adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
543adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
544adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
545adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns whether or not this file is a hidden file as defined by the
546f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * operating system. The notion of "hidden" is system-dependent. For Unix
547f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * systems a file is considered hidden if its name starts with a ".". For
548f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * Windows systems there is an explicit flag in the file system for this
549f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * purpose.
550f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
551adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if the file is hidden, {@code false} otherwise.
552adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
553adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean isHidden() {
554ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes        if (path.isEmpty()) {
555adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
556adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
55787415b1521402398d4470aecbef7c126a6948290Elliott Hughes        return getName().startsWith(".");
558adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
561adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the time when this file was last modified, measured in
562adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * milliseconds since January 1st, 1970, midnight.
5631326cfc6f105f6c8fd5ffd83793223e1a797409dElliott Hughes     * Returns 0 if the file does not exist.
564f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
565adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the time when this file was last modified.
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public long lastModified() {
56847cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        try {
569b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            return Libcore.os.stat(path).st_mtime * 1000L;
5706c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        } catch (ErrnoException errnoException) {
57147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes            // The RI returns 0 on error. (Even for errors like EACCES or ELOOP.)
57247cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes            return 0;
57347cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        }
574adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
575adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
576adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
577adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Sets the time this file was last modified, measured in milliseconds since
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * January 1st, 1970, midnight.
579f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
580ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
581ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * Callers must check the return value.
582ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     *
583adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param time
584adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the last modification time for this file.
585adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if the operation is successful, {@code false}
586adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         otherwise.
587adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
588adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if {@code time < 0}.
589adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
590adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean setLastModified(long time) {
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (time < 0) {
592b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("time < 0");
593adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
594b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes        return setLastModifiedImpl(path, time);
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
596adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
597aaacdb095b10293286adbfd94af2fd83b8dae3a8Elliott Hughes    private static native boolean setLastModifiedImpl(String path, long time);
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
60008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Equivalent to setWritable(false, false).
601f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
60208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @see #setWritable(boolean, boolean)
603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean setReadOnly() {
60508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes        return setWritable(false, false);
60608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
60708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
60808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
60908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Manipulates the execute permissions for the abstract path designated by
61008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * this file.
61108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
612ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
613ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * Callers must check the return value.
614ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     *
61508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @param executable
61608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            To allow execute permission if true, otherwise disallow
61708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @param ownerOnly
61808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            To manipulate execute permission only for owner if true,
61908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            otherwise for everyone. The manipulation will apply to
62008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            everyone regardless of this value if the underlying system
62108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            does not distinguish owner and other users.
62208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @return true if and only if the operation succeeded. If the user does not
62308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         have permission to change the access permissions of this abstract
62408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         pathname the operation will fail. If the underlying file system
62508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         does not support execute permission and the value of executable
62608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         is false, this operation will fail.
62708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
62808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
62908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public boolean setExecutable(boolean executable, boolean ownerOnly) {
630b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes        return doChmod(ownerOnly ? S_IXUSR : (S_IXUSR | S_IXGRP | S_IXOTH), executable);
63108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
63208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
63308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
63408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Equivalent to setExecutable(executable, true).
635ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * @see #setExecutable(boolean, boolean)
63608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
63708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
63808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public boolean setExecutable(boolean executable) {
63908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes        return setExecutable(executable, true);
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
64208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
64308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Manipulates the read permissions for the abstract path designated by this
64408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * file.
64508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
64608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @param readable
64708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            To allow read permission if true, otherwise disallow
64808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @param ownerOnly
64908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            To manipulate read permission only for owner if true,
65008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            otherwise for everyone. The manipulation will apply to
65108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            everyone regardless of this value if the underlying system
65208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            does not distinguish owner and other users.
65308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @return true if and only if the operation succeeded. If the user does not
65408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         have permission to change the access permissions of this abstract
65508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         pathname the operation will fail. If the underlying file system
65608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         does not support read permission and the value of readable is
65708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         false, this operation will fail.
65808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
65908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
66008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public boolean setReadable(boolean readable, boolean ownerOnly) {
661b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes        return doChmod(ownerOnly ? S_IRUSR : (S_IRUSR | S_IRGRP | S_IROTH), readable);
66208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
66308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
66408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
66508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Equivalent to setReadable(readable, true).
666ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * @see #setReadable(boolean, boolean)
66708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
66808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
66908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public boolean setReadable(boolean readable) {
67008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes        return setReadable(readable, true);
67108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
67208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
67308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
67408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Manipulates the write permissions for the abstract path designated by this
67508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * file.
67608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
67708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @param writable
67808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            To allow write permission if true, otherwise disallow
67908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @param ownerOnly
68008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            To manipulate write permission only for owner if true,
68108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            otherwise for everyone. The manipulation will apply to
68208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            everyone regardless of this value if the underlying system
68308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *            does not distinguish owner and other users.
68408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @return true if and only if the operation succeeded. If the user does not
68508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         have permission to change the access permissions of this abstract
68608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *         pathname the operation will fail.
68708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
68808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
68908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public boolean setWritable(boolean writable, boolean ownerOnly) {
690b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes        return doChmod(ownerOnly ? S_IWUSR : (S_IWUSR | S_IWGRP | S_IWOTH), writable);
69108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
69208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
69308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
69408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Equivalent to setWritable(writable, true).
695ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * @see #setWritable(boolean, boolean)
69608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
69708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
69808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public boolean setWritable(boolean writable) {
69908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes        return setWritable(writable, true);
70008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
70108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
702b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    private boolean doChmod(int mask, boolean set) {
703b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes        try {
704b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            StructStat sb = Libcore.os.stat(path);
705b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            int newMode = set ? (sb.st_mode | mask) : (sb.st_mode & ~mask);
706b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            Libcore.os.chmod(path, newMode);
707b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            return true;
708b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes        } catch (ErrnoException errnoException) {
709b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            return false;
710b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes        }
711b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes    }
712adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns the length of this file in bytes.
7151326cfc6f105f6c8fd5ffd83793223e1a797409dElliott Hughes     * Returns 0 if the file does not exist.
7161326cfc6f105f6c8fd5ffd83793223e1a797409dElliott Hughes     * The result for a directory is not defined.
717f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the number of bytes in this file.
719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public long length() {
72147cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        try {
722b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            return Libcore.os.stat(path).st_size;
7236c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        } catch (ErrnoException errnoException) {
72447cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes            // The RI returns 0 on error. (Even for errors like EACCES or ELOOP.)
72547cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes            return 0;
72647cb338d43f75dd998b29caaaa9446c5705217d1Elliott Hughes        }
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
730adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an array of strings with the file names in the directory
731f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * represented by this file. The result is {@code null} if this file is not
732f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * a directory.
733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The entries {@code .} and {@code ..} representing the current and parent
735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * directory are not returned as part of the list.
736f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an array of strings with file names or {@code null}.
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
7390af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes    public String[] list() {
7406c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        return listImpl(path);
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
743aaacdb095b10293286adbfd94af2fd83b8dae3a8Elliott Hughes    private static native String[] listImpl(String path);
7440af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes
7450af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes    /**
7460af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * Gets a list of the files in the directory represented by this file. This
7470af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * list is then filtered through a FilenameFilter and the names of files
7480af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * with matching names are returned as an array of strings. Returns
7490af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * {@code null} if this file is not a directory. If {@code filter} is
7500af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * {@code null} then all filenames match.
7510af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * <p>
7520af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * The entries {@code .} and {@code ..} representing the current and parent
7530af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * directories are not returned as part of the list.
7540af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     *
7550af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * @param filter
7560af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     *            the filter to match names against, may be {@code null}.
7570af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * @return an array of files or {@code null}.
7580af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     */
7590af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes    public String[] list(FilenameFilter filter) {
7600af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        String[] filenames = list();
7610af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        if (filter == null || filenames == null) {
7620af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes            return filenames;
7630af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        }
7640af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        List<String> result = new ArrayList<String>(filenames.length);
7650af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        for (String filename : filenames) {
7660af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes            if (filter.accept(this, filename)) {
7670af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes                result.add(filename);
7680af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes            }
7690af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        }
7700af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        return result.toArray(new String[result.size()]);
7710af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes    }
7720af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes
773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns an array of files contained in the directory represented by this
775adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * file. The result is {@code null} if this file is not a directory. The
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * paths of the files in the array are absolute if the path of this file is
777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * absolute, they are relative otherwise.
778f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
779adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an array of files or {@code null}.
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File[] listFiles() {
7820af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        return filenamesToFiles(list());
783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
785adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a list of the files in the directory represented by this file. This
787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * list is then filtered through a FilenameFilter and files with matching
788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * names are returned as an array of files. Returns {@code null} if this
789adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * file is not a directory. If {@code filter} is {@code null} then all
790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * filenames match.
791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The entries {@code .} and {@code ..} representing the current and parent
793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * directories are not returned as part of the list.
794f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
795adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param filter
796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the filter to match names against, may be {@code null}.
797adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an array of files or {@code null}.
798adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File[] listFiles(FilenameFilter filter) {
8000af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        return filenamesToFiles(list(filter));
801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets a list of the files in the directory represented by this file. This
805adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * list is then filtered through a FileFilter and matching files are
806adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * returned as an array of files. Returns {@code null} if this file is not a
807adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * directory. If {@code filter} is {@code null} then all files match.
808adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * <p>
809adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * The entries {@code .} and {@code ..} representing the current and parent
810adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * directories are not returned as part of the list.
811f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
812adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param filter
813adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the filter to match names against, may be {@code null}.
814adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an array of files or {@code null}.
815adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
816adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public File[] listFiles(FileFilter filter) {
8170af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        File[] files = listFiles();
8180af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        if (filter == null || files == null) {
8190af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes            return files;
8200af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        }
8210af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        List<File> result = new ArrayList<File>(files.length);
8220af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        for (File file : files) {
8230af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes            if (filter.accept(file)) {
8240af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes                result.add(file);
825adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
826adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
8270af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        return result.toArray(new File[result.size()]);
828adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
829adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
830adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
8310af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * Converts a String[] containing filenames to a File[].
8320af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * Note that the filenames must not contain slashes.
8330af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * This method is to remove duplication in the implementation
8340af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes     * of File.list's overloads.
835adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
8360af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes    private File[] filenamesToFiles(String[] filenames) {
8370af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        if (filenames == null) {
838adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
839adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
8400af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        int count = filenames.length;
8410af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        File[] result = new File[count];
8420af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        for (int i = 0; i < count; ++i) {
8430af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes            result[i] = new File(this, filenames[i]);
844adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
8450af4ef265f1e67edfcc5e34bcb68ee42a791beefElliott Hughes        return result;
846adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
847adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
848adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
849fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * Creates the directory named by this file, assuming its parents exist.
850fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * Use {@link #mkdirs} if you also want to create missing parents.
851f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
852ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
853fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * Callers must check the return value. Note also that this method returns
854fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * false if the directory already existed. If you want to know whether the
855fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * directory exists on return, either use {@code (f.mkdir() || f.isDirectory())}
856fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * or simply ignore the return value from this method and simply call {@link #isDirectory}.
857ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     *
858fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * @return {@code true} if the directory was created,
859fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     *         {@code false} on failure or if the directory already existed.
860adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
861adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean mkdir() {
862c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes        try {
863fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes            mkdirErrno();
864c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes            return true;
865c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes        } catch (ErrnoException errnoException) {
866c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes            return false;
867c7fa20701d5e9398c38f4615ed293acfce1c0cf6Elliott Hughes        }
868adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
869adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
870fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes    private void mkdirErrno() throws ErrnoException {
871fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes        // On Android, we don't want default permissions to allow global access.
872fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes        Libcore.os.mkdir(path, S_IRWXU);
873fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes    }
874fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes
875adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
876fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * Creates the directory named by this file, creating missing parent
877fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * directories if necessary.
878fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * Use {@link #mkdir} if you don't want to create missing parents.
879f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
880ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
881fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * Callers must check the return value. Note also that this method returns
882fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * false if the directory already existed. If you want to know whether the
883fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * directory exists on return, either use {@code (f.mkdirs() || f.isDirectory())}
884fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * or simply ignore the return value from this method and simply call {@link #isDirectory}.
885ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     *
886fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     * @return {@code true} if the directory was created,
887fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes     *         {@code false} on failure or if the directory already existed.
888adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
889adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean mkdirs() {
890fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes        return mkdirs(false);
891fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes    }
892adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
893fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes    private boolean mkdirs(boolean resultIfExists) {
894fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes        try {
895fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes            // Try to create the directory directly.
896fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes            mkdirErrno();
897adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return true;
898fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes        } catch (ErrnoException errnoException) {
899fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes            if (errnoException.errno == ENOENT) {
900fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes                // If the parent was missing, try to create it and then try again.
901fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes                File parent = getParentFile();
902fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes                return parent != null && parent.mkdirs(true) && mkdir();
903fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes            } else if (errnoException.errno == EEXIST) {
904fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes                return resultIfExists;
905fec51846c02116a6ac02fac8ecf8ffb705a74b36Elliott Hughes            }
906adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return false;
907adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
908adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
909adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
910adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
911adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates a new, empty file on the file system according to the path
9122ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * information stored in this file. This method returns true if it creates
9132ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * a file, false if the file already existed. Note that it returns false
9142ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * even if the file is not a file (because it's a directory, say).
915f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
9162ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * <p>This method is not generally useful. For creating temporary files,
9172ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * use {@link #createTempFile} instead. For reading/writing files, use {@link FileInputStream},
9182ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * {@link FileOutputStream}, or {@link RandomAccessFile}, all of which can create files.
9192ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     *
9202ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * <p>Note that this method does <i>not</i> throw {@code IOException} if the file
9212ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * already exists, even if it's not a regular file. Callers should always check the
9222ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * return value, and may additionally want to call {@link #isFile}.
923ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     *
9242ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes     * @return true if the file has been created, false if it
925adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         already exists.
92693a4b2a6cc35a72aa5a58027025f3e18c0ec2e64Elliott Hughes     * @throws IOException if it's not possible to create the file.
927adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
928adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public boolean createNewFile() throws IOException {
9292ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes        FileDescriptor fd = null;
9302ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes        try {
9312ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes            // On Android, we don't want default permissions to allow global access.
9322ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes            fd = Libcore.os.open(path, O_RDWR | O_CREAT | O_EXCL, 0600);
9332ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes            return true;
9342ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes        } catch (ErrnoException errnoException) {
9352ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes            if (errnoException.errno == EEXIST) {
9362ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes                // The file already exists.
9372ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes                return false;
9382ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes            }
9392ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes            throw errnoException.rethrowAsIOException();
9402ffce92141c0b2a5f0543229f3ded34b0ee79ba1Elliott Hughes        } finally {
941462bdac45c10f43d88d8f07f6994e272a27c14a2Elliott Hughes            IoUtils.close(fd); // TODO: should we suppress IOExceptions thrown here?
942adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
943adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
944adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
945adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
946adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates an empty temporary file using the given prefix and suffix as part
9475d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughes     * of the file name. If {@code suffix} is null, {@code .tmp} is used. This
948f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * method is a convenience method that calls
949f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * {@link #createTempFile(String, String, File)} with the third argument
950f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * being {@code null}.
951f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
952adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param prefix
953adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the prefix to the temp file name.
954adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param suffix
955adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the suffix to the temp file name.
956adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the temporary file.
957adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
958adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs when writing the file.
959adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
9605d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughes    public static File createTempFile(String prefix, String suffix) throws IOException {
961adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return createTempFile(prefix, suffix, null);
962adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
963adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
964adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
965adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Creates an empty temporary file in the given directory using the given
9665d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughes     * prefix and suffix as part of the file name. If {@code suffix} is null, {@code .tmp} is used.
9675d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughes     *
96816b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * <p>Note that this method does <i>not</i> call {@link #deleteOnExit}, but see the
96916b52d1f3e66cfadf3e245de27358b590e201d72Elliott Hughes     * documentation for that method before you call it manually.
970f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
971adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param prefix
972adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the prefix to the temp file name.
973adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param suffix
974adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the suffix to the temp file name.
975adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param directory
976adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the location to which the temp file is to be written, or
977adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            {@code null} for the default location for temporary files,
978adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            which is taken from the "java.io.tmpdir" system property. It
979adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            may be necessary to set this property to an existing, writable
980f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *            directory for this method to work properly.
981adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the temporary file.
982adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IllegalArgumentException
983adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the length of {@code prefix} is less than 3.
984adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws IOException
985adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if an error occurs when writing the file.
986adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
9871c4b8eb0aebfe7f99c10fb1d01716946e8e74ad7Elliott Hughes    public static File createTempFile(String prefix, String suffix, File directory)
9881c4b8eb0aebfe7f99c10fb1d01716946e8e74ad7Elliott Hughes            throws IOException {
989adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // Force a prefix null check first
990adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (prefix.length() < 3) {
991b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes            throw new IllegalArgumentException("prefix must be at least 3 characters");
992f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
9935d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughes        if (suffix == null) {
9945d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughes            suffix = ".tmp";
9955d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughes        }
9965d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughes        File tmpDirFile = directory;
9975d40b59c6bba79dc978f173ad64cdfbd8a937018Elliott Hughes        if (tmpDirFile == null) {
998ad41624e761bcf1af9c8008eb45187fc13983717Elliott Hughes            String tmpDir = System.getProperty("java.io.tmpdir", ".");
999f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            tmpDirFile = new File(tmpDir);
1000f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        }
1001f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        File result;
1002adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        do {
10037c22337691326a03386e42a32becbeb2c2dc7f06Narayan Kamath            result = new File(tmpDirFile, prefix + Math.randomIntInternal() + suffix);
1004adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } while (!result.createNewFile());
1005adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return result;
1006adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1007adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1008adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1009ccbe3404e0691dab506d017550658e8e5974c83eElliott Hughes     * Renames this file to {@code newPath}. This operation is supported for both
1010ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * files and directories.
1011ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     *
1012ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <p>Many failures are possible. Some of the more likely failures include:
1013ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <ul>
1014ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <li>Write permission is required on the directories containing both the source and
1015ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * destination paths.
1016ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <li>Search permission is required for all parents of both paths.
1017ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <li>Both paths be on the same mount point. On Android, applications are most likely to hit
1018ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * this restriction when attempting to copy between internal storage and an SD card.
1019ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * </ul>
1020ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     *
1021ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * <p>Note that this method does <i>not</i> throw {@code IOException} on failure.
1022ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * Callers must check the return value.
1023f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
1024ccbe3404e0691dab506d017550658e8e5974c83eElliott Hughes     * @param newPath the new path.
1025ab3683bce6e370c946598bfad54387fa38ce69dfElliott Hughes     * @return true on success.
1026adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1027ccbe3404e0691dab506d017550658e8e5974c83eElliott Hughes    public boolean renameTo(File newPath) {
1028a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        try {
1029b7190190e0ef8de883c952efb319ce7748831faaElliott Hughes            Libcore.os.rename(path, newPath.path);
1030a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes            return true;
1031a20cc6fca30d18e05db67ceeb0403b7b58ffd364Elliott Hughes        } catch (ErrnoException errnoException) {
1032c5c9c667028146ab5f5e446c44f911c2fdd7dd30Elliott Hughes            return false;
1033c5c9c667028146ab5f5e446c44f911c2fdd7dd30Elliott Hughes        }
1034adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1035adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1036adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1037adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a string containing a concise, human-readable description of this
1038adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * file.
1039f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
1040adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return a printable representation of this file.
1041adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1042adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    @Override
1043adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public String toString() {
1044adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return path;
1045adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1046adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1047adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1048adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a Uniform Resource Identifier for this file. The URI is system
1049adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * dependent and may not be transferable between different operating / file
1050adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * systems.
1051f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
1052adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return an URI for this file.
1053adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
1054adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URI toURI() {
1055adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String name = getAbsoluteName();
1056adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
1057f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            if (!name.startsWith("/")) {
1058adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                // start with sep.
10596c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes                return new URI("file", null, "/" + name, null, null);
1060f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            } else if (name.startsWith("//")) {
1061f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson                return new URI("file", "", name, null); // UNC path
1062adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
1063f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return new URI("file", null, name, null, null);
1064adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        } catch (URISyntaxException e) {
1065adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // this should never happen
1066adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
1067adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1068adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1069adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1070adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1071adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Returns a Uniform Resource Locator for this file. The URL is system
1072adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * dependent and may not be transferable between different operating / file
1073adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * systems.
1074f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *
1075f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     * @return a URL for this file.
1076adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws java.net.MalformedURLException
1077f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson     *             if the path cannot be transformed into a URL.
107899b4489d0555c6e0e5df941cbfad4cf250c8f0b8Elliott Hughes     * @deprecated Use {@link #toURI} and {@link java.net.URI#toURL} to
107999b4489d0555c6e0e5df941cbfad4cf250c8f0b8Elliott Hughes     * correctly escape illegal characters.
1080adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
108108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    @Deprecated
1082adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public URL toURL() throws java.net.MalformedURLException {
1083adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String name = getAbsoluteName();
1084f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        if (!name.startsWith("/")) {
1085adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // start with sep.
10866c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes            return new URL("file", "", -1, "/" + name, null);
1087f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson        } else if (name.startsWith("//")) {
1088f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson            return new URL("file:" + name); // UNC path
1089adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1090c903e6720bbbf6540c29f141bd2fa559813ea20aElliott Hughes        return new URL("file", "", -1, name, null);
1091adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1092adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
10936c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes    // TODO: is this really necessary, or can it be replaced with getAbsolutePath?
1094adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private String getAbsoluteName() {
1095adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        File f = getAbsoluteFile();
1096adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        String name = f.getPath();
1097adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (f.isDirectory() && name.charAt(name.length() - 1) != separatorChar) {
1098adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            // Directories must end with a slash
10996c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes            name = name + "/";
1100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (separatorChar != '/') { // Must convert slashes.
1102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            name = name.replace(separatorChar, '/');
1103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
1104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return name;
1105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private void writeObject(ObjectOutputStream stream) throws IOException {
1108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        stream.defaultWriteObject();
1109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        stream.writeChar(separatorChar);
1110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
1111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
111208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
1113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        stream.defaultReadObject();
1114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        char inSeparator = stream.readChar();
11156c937923e20679d0752cea1ee5e2e969a094acdbElliott Hughes        this.path = fixSlashes(path.replace(inSeparator, separatorChar));
1116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
111708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
111808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
111908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Returns the total size in bytes of the partition containing this path.
112008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Returns 0 if this path does not exist.
112108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
112208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
112308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
112408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public long getTotalSpace() {
112559fa7163774d6930a174bc038414a4b780581957Elliott Hughes        try {
1126721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes            StructStatVfs sb = Libcore.os.statvfs(path);
112759fa7163774d6930a174bc038414a4b780581957Elliott Hughes            return sb.f_blocks * sb.f_bsize; // total block count * block size in bytes.
112859fa7163774d6930a174bc038414a4b780581957Elliott Hughes        } catch (ErrnoException errnoException) {
112959fa7163774d6930a174bc038414a4b780581957Elliott Hughes            return 0;
113059fa7163774d6930a174bc038414a4b780581957Elliott Hughes        }
113108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
113208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
113308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
113408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Returns the number of usable free bytes on the partition containing this path.
113508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Returns 0 if this path does not exist.
113608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
113708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * <p>Note that this is likely to be an optimistic over-estimate and should not
113808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * be taken as a guarantee your application can actually write this many bytes.
113908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * On Android (and other Unix-based systems), this method returns the number of free bytes
114008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * available to non-root users, regardless of whether you're actually running as root,
114108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * and regardless of any quota or other restrictions that might apply to the user.
114208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * (The {@code getFreeSpace} method returns the number of bytes potentially available to root.)
114308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
114408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
114508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
114608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public long getUsableSpace() {
114759fa7163774d6930a174bc038414a4b780581957Elliott Hughes        try {
1148721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes            StructStatVfs sb = Libcore.os.statvfs(path);
114959fa7163774d6930a174bc038414a4b780581957Elliott Hughes            return sb.f_bavail * sb.f_bsize; // non-root free block count * block size in bytes.
115059fa7163774d6930a174bc038414a4b780581957Elliott Hughes        } catch (ErrnoException errnoException) {
115159fa7163774d6930a174bc038414a4b780581957Elliott Hughes            return 0;
115259fa7163774d6930a174bc038414a4b780581957Elliott Hughes        }
115308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
115408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes
115508ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    /**
115608ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Returns the number of free bytes on the partition containing this path.
115708ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * Returns 0 if this path does not exist.
115808ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
115908ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * <p>Note that this is likely to be an optimistic over-estimate and should not
116008ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * be taken as a guarantee your application can actually write this many bytes.
116108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     *
116208ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     * @since 1.6
116308ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes     */
116408ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    public long getFreeSpace() {
116559fa7163774d6930a174bc038414a4b780581957Elliott Hughes        try {
1166721ceca2a52a3c27aa751476c8562e1e68088e15Elliott Hughes            StructStatVfs sb = Libcore.os.statvfs(path);
116759fa7163774d6930a174bc038414a4b780581957Elliott Hughes            return sb.f_bfree * sb.f_bsize; // free block count * block size in bytes.
116859fa7163774d6930a174bc038414a4b780581957Elliott Hughes        } catch (ErrnoException errnoException) {
116959fa7163774d6930a174bc038414a4b780581957Elliott Hughes            return 0;
117059fa7163774d6930a174bc038414a4b780581957Elliott Hughes        }
117108ec8fd5c950cb94e12aefa08c89d78762acf18aElliott Hughes    }
1172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
1173