1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.  Oracle designates this
9 * particular file as subject to the "Classpath" exception as provided
10 * by Oracle in the LICENSE file that accompanied this code.
11 *
12 * This code is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 * version 2 for more details (a copy is included in the LICENSE file that
16 * accompanied this code).
17 *
18 * You should have received a copy of the GNU General Public License version
19 * 2 along with this work; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
26
27package java.io;
28
29import java.net.URI;
30import java.net.URL;
31import java.net.MalformedURLException;
32import java.net.URISyntaxException;
33import java.util.List;
34import java.util.ArrayList;
35
36/**
37 * An abstract representation of file and directory pathnames.
38 *
39 * <p> User interfaces and operating systems use system-dependent <em>pathname
40 * strings</em> to name files and directories.  This class presents an
41 * abstract, system-independent view of hierarchical pathnames.  An
42 * <em>abstract pathname</em> has two components:
43 *
44 * <ol>
45 * <li> An optional system-dependent <em>prefix</em> string,
46 *      such as a disk-drive specifier, <code>"/"</code>&nbsp;for the UNIX root
47 *      directory, or <code>"\\\\"</code>&nbsp;for a Microsoft Windows UNC pathname, and
48 * <li> A sequence of zero or more string <em>names</em>.
49 * </ol>
50 *
51 * The first name in an abstract pathname may be a directory name or, in the
52 * case of Microsoft Windows UNC pathnames, a hostname.  Each subsequent name
53 * in an abstract pathname denotes a directory; the last name may denote
54 * either a directory or a file.  The <em>empty</em> abstract pathname has no
55 * prefix and an empty name sequence.
56 *
57 * <p> The conversion of a pathname string to or from an abstract pathname is
58 * inherently system-dependent.  When an abstract pathname is converted into a
59 * pathname string, each name is separated from the next by a single copy of
60 * the default <em>separator character</em>.  The default name-separator
61 * character is defined by the system property <code>file.separator</code>, and
62 * is made available in the public static fields <code>{@link
63 * #separator}</code> and <code>{@link #separatorChar}</code> of this class.
64 * When a pathname string is converted into an abstract pathname, the names
65 * within it may be separated by the default name-separator character or by any
66 * other name-separator character that is supported by the underlying system.
67 *
68 * <p> A pathname, whether abstract or in string form, may be either
69 * <em>absolute</em> or <em>relative</em>.  An absolute pathname is complete in
70 * that no other information is required in order to locate the file that it
71 * denotes.  A relative pathname, in contrast, must be interpreted in terms of
72 * information taken from some other pathname.  By default the classes in the
73 * <code>java.io</code> package always resolve relative pathnames against the
74 * current user directory.  This directory is named by the system property
75 * <code>user.dir</code>, and is typically the directory in which the Java
76 * virtual machine was invoked.
77 *
78 * <p> The <em>parent</em> of an abstract pathname may be obtained by invoking
79 * the {@link #getParent} method of this class and consists of the pathname's
80 * prefix and each name in the pathname's name sequence except for the last.
81 * Each directory's absolute pathname is an ancestor of any <tt>File</tt>
82 * object with an absolute abstract pathname which begins with the directory's
83 * absolute pathname.  For example, the directory denoted by the abstract
84 * pathname <tt>"/usr"</tt> is an ancestor of the directory denoted by the
85 * pathname <tt>"/usr/local/bin"</tt>.
86 *
87 * <p> The prefix concept is used to handle root directories on UNIX platforms,
88 * and drive specifiers, root directories and UNC pathnames on Microsoft Windows platforms,
89 * as follows:
90 *
91 * <ul>
92 *
93 * <li> For UNIX platforms, the prefix of an absolute pathname is always
94 * <code>"/"</code>.  Relative pathnames have no prefix.  The abstract pathname
95 * denoting the root directory has the prefix <code>"/"</code> and an empty
96 * name sequence.
97 *
98 * <li> For Microsoft Windows platforms, the prefix of a pathname that contains a drive
99 * specifier consists of the drive letter followed by <code>":"</code> and
100 * possibly followed by <code>"\\"</code> if the pathname is absolute.  The
101 * prefix of a UNC pathname is <code>"\\\\"</code>; the hostname and the share
102 * name are the first two names in the name sequence.  A relative pathname that
103 * does not specify a drive has no prefix.
104 *
105 * </ul>
106 *
107 * <p> Instances of this class may or may not denote an actual file-system
108 * object such as a file or a directory.  If it does denote such an object
109 * then that object resides in a <i>partition</i>.  A partition is an
110 * operating system-specific portion of storage for a file system.  A single
111 * storage device (e.g. a physical disk-drive, flash memory, CD-ROM) may
112 * contain multiple partitions.  The object, if any, will reside on the
113 * partition <a name="partName">named</a> by some ancestor of the absolute
114 * form of this pathname.
115 *
116 * <p> A file system may implement restrictions to certain operations on the
117 * actual file-system object, such as reading, writing, and executing.  These
118 * restrictions are collectively known as <i>access permissions</i>.  The file
119 * system may have multiple sets of access permissions on a single object.
120 * For example, one set may apply to the object's <i>owner</i>, and another
121 * may apply to all other users.  The access permissions on an object may
122 * cause some methods in this class to fail.
123 *
124 * <p> Instances of the <code>File</code> class are immutable; that is, once
125 * created, the abstract pathname represented by a <code>File</code> object
126 * will never change.
127 *
128 * <p>On Android, the underlying filesystem encoding for filenames is always UTF-8.
129 *
130 * @author  unascribed
131 * @since   JDK1.0
132 */
133
134public class File
135    implements Serializable, Comparable<File>
136{
137
138    /**
139     * The FileSystem object representing the platform's local file system.
140     */
141    static private final FileSystem fs = FileSystem.getFileSystem();
142
143    /**
144     * This abstract pathname's normalized pathname string. A normalized
145     * pathname string uses the default name-separator character and does not
146     * contain any duplicate or redundant separators.
147     *
148     * @serial
149     */
150    private String path;
151
152    /**
153     * Enum type that indicates the status of a file path.
154     */
155    private static enum PathStatus { INVALID, CHECKED };
156
157    /**
158     * The flag indicating whether the file path is invalid.
159     */
160    private transient PathStatus status = null;
161
162    /**
163     * Check if the file has an invalid path. Currently, the inspection of
164     * a file path is very limited, and it only covers Nul character check.
165     * Returning true means the path is definitely invalid/garbage. But
166     * returning false does not guarantee that the path is valid.
167     *
168     * @return true if the file path is invalid.
169     */
170    final boolean isInvalid() {
171        if (status == null) {
172            status = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKED
173                                                       : PathStatus.INVALID;
174        }
175        return status == PathStatus.INVALID;
176    }
177
178    /**
179     * The length of this abstract pathname's prefix, or zero if it has no
180     * prefix.
181     */
182    private transient int prefixLength;
183
184    /**
185     * Returns the length of this abstract pathname's prefix.
186     * For use by FileSystem classes.
187     */
188    int getPrefixLength() {
189        return prefixLength;
190    }
191
192    /**
193     * The system-dependent default name-separator character.  This field is
194     * initialized to contain the first character of the value of the system
195     * property <code>file.separator</code>.  On UNIX systems the value of this
196     * field is <code>'/'</code>; on Microsoft Windows systems it is <code>'\\'</code>.
197     *
198     * @see     java.lang.System#getProperty(java.lang.String)
199     */
200    public static final char separatorChar = fs.getSeparator();
201
202    /**
203     * The system-dependent default name-separator character, represented as a
204     * string for convenience.  This string contains a single character, namely
205     * <code>{@link #separatorChar}</code>.
206     */
207    public static final String separator = "" + separatorChar;
208
209    /**
210     * The system-dependent path-separator character.  This field is
211     * initialized to contain the first character of the value of the system
212     * property <code>path.separator</code>.  This character is used to
213     * separate filenames in a sequence of files given as a <em>path list</em>.
214     * On UNIX systems, this character is <code>':'</code>; on Microsoft Windows systems it
215     * is <code>';'</code>.
216     *
217     * @see     java.lang.System#getProperty(java.lang.String)
218     */
219    public static final char pathSeparatorChar = fs.getPathSeparator();
220
221    /**
222     * The system-dependent path-separator character, represented as a string
223     * for convenience.  This string contains a single character, namely
224     * <code>{@link #pathSeparatorChar}</code>.
225     */
226    public static final String pathSeparator = "" + pathSeparatorChar;
227
228
229    /* -- Constructors -- */
230
231    /**
232     * Internal constructor for already-normalized pathname strings.
233     */
234    private File(String pathname, int prefixLength) {
235        this.path = pathname;
236        this.prefixLength = prefixLength;
237    }
238
239    /**
240     * Internal constructor for already-normalized pathname strings.
241     * The parameter order is used to disambiguate this method from the
242     * public(File, String) constructor.
243     */
244    private File(String child, File parent) {
245        assert parent.path != null;
246        assert (!parent.path.equals(""));
247        this.path = fs.resolve(parent.path, child);
248        this.prefixLength = parent.prefixLength;
249    }
250
251    /**
252     * Creates a new <code>File</code> instance by converting the given
253     * pathname string into an abstract pathname.  If the given string is
254     * the empty string, then the result is the empty abstract pathname.
255     *
256     * @param   pathname  A pathname string
257     * @throws  NullPointerException
258     *          If the <code>pathname</code> argument is <code>null</code>
259     */
260    public File(String pathname) {
261        if (pathname == null) {
262            throw new NullPointerException();
263        }
264        this.path = fs.normalize(pathname);
265        this.prefixLength = fs.prefixLength(this.path);
266    }
267
268    /* Note: The two-argument File constructors do not interpret an empty
269       parent abstract pathname as the current user directory.  An empty parent
270       instead causes the child to be resolved against the system-dependent
271       directory defined by the FileSystem.getDefaultParent method.  On Unix
272       this default is "/", while on Microsoft Windows it is "\\".  This is required for
273       compatibility with the original behavior of this class. */
274
275    /**
276     * Creates a new <code>File</code> instance from a parent pathname string
277     * and a child pathname string.
278     *
279     * <p> If <code>parent</code> is <code>null</code> then the new
280     * <code>File</code> instance is created as if by invoking the
281     * single-argument <code>File</code> constructor on the given
282     * <code>child</code> pathname string.
283     *
284     * <p> Otherwise the <code>parent</code> pathname string is taken to denote
285     * a directory, and the <code>child</code> pathname string is taken to
286     * denote either a directory or a file.  If the <code>child</code> pathname
287     * string is absolute then it is converted into a relative pathname in a
288     * system-dependent way.  If <code>parent</code> is the empty string then
289     * the new <code>File</code> instance is created by converting
290     * <code>child</code> into an abstract pathname and resolving the result
291     * against a system-dependent default directory.  Otherwise each pathname
292     * string is converted into an abstract pathname and the child abstract
293     * pathname is resolved against the parent.
294     *
295     * @param   parent  The parent pathname string
296     * @param   child   The child pathname string
297     * @throws  NullPointerException
298     *          If <code>child</code> is <code>null</code>
299     */
300    public File(String parent, String child) {
301        if (child == null) {
302            throw new NullPointerException();
303        }
304        if (parent != null && !parent.isEmpty()) {
305            this.path = fs.resolve(fs.normalize(parent),
306                                   fs.normalize(child));
307        } else {
308            this.path = fs.normalize(child);
309        }
310        this.prefixLength = fs.prefixLength(this.path);
311    }
312
313    /**
314     * Creates a new <code>File</code> instance from a parent abstract
315     * pathname and a child pathname string.
316     *
317     * <p> If <code>parent</code> is <code>null</code> then the new
318     * <code>File</code> instance is created as if by invoking the
319     * single-argument <code>File</code> constructor on the given
320     * <code>child</code> pathname string.
321     *
322     * <p> Otherwise the <code>parent</code> abstract pathname is taken to
323     * denote a directory, and the <code>child</code> pathname string is taken
324     * to denote either a directory or a file.  If the <code>child</code>
325     * pathname string is absolute then it is converted into a relative
326     * pathname in a system-dependent way.  If <code>parent</code> is the empty
327     * abstract pathname then the new <code>File</code> instance is created by
328     * converting <code>child</code> into an abstract pathname and resolving
329     * the result against a system-dependent default directory.  Otherwise each
330     * pathname string is converted into an abstract pathname and the child
331     * abstract pathname is resolved against the parent.
332     *
333     * @param   parent  The parent abstract pathname
334     * @param   child   The child pathname string
335     * @throws  NullPointerException
336     *          If <code>child</code> is <code>null</code>
337     */
338    public File(File parent, String child) {
339        if (child == null) {
340            throw new NullPointerException();
341        }
342        if (parent != null) {
343            if (parent.path.equals("")) {
344                this.path = fs.resolve(fs.getDefaultParent(),
345                                       fs.normalize(child));
346            } else {
347                this.path = fs.resolve(parent.path,
348                                       fs.normalize(child));
349            }
350        } else {
351            this.path = fs.normalize(child);
352        }
353        this.prefixLength = fs.prefixLength(this.path);
354    }
355
356    /**
357     * Creates a new <tt>File</tt> instance by converting the given
358     * <tt>file:</tt> URI into an abstract pathname.
359     *
360     * <p> The exact form of a <tt>file:</tt> URI is system-dependent, hence
361     * the transformation performed by this constructor is also
362     * system-dependent.
363     *
364     * <p> For a given abstract pathname <i>f</i> it is guaranteed that
365     *
366     * <blockquote><tt>
367     * new File(</tt><i>&nbsp;f</i><tt>.{@link #toURI() toURI}()).equals(</tt><i>&nbsp;f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
368     * </tt></blockquote>
369     *
370     * so long as the original abstract pathname, the URI, and the new abstract
371     * pathname are all created in (possibly different invocations of) the same
372     * Java virtual machine.  This relationship typically does not hold,
373     * however, when a <tt>file:</tt> URI that is created in a virtual machine
374     * on one operating system is converted into an abstract pathname in a
375     * virtual machine on a different operating system.
376     *
377     * @param  uri
378     *         An absolute, hierarchical URI with a scheme equal to
379     *         <tt>"file"</tt>, a non-empty path component, and undefined
380     *         authority, query, and fragment components
381     *
382     * @throws  NullPointerException
383     *          If <tt>uri</tt> is <tt>null</tt>
384     *
385     * @throws  IllegalArgumentException
386     *          If the preconditions on the parameter do not hold
387     *
388     * @see #toURI()
389     * @see java.net.URI
390     * @since 1.4
391     */
392    public File(URI uri) {
393
394        // Check our many preconditions
395        if (!uri.isAbsolute())
396            throw new IllegalArgumentException("URI is not absolute");
397        if (uri.isOpaque())
398            throw new IllegalArgumentException("URI is not hierarchical");
399        String scheme = uri.getScheme();
400        if ((scheme == null) || !scheme.equalsIgnoreCase("file"))
401            throw new IllegalArgumentException("URI scheme is not \"file\"");
402        if (uri.getAuthority() != null)
403            throw new IllegalArgumentException("URI has an authority component");
404        if (uri.getFragment() != null)
405            throw new IllegalArgumentException("URI has a fragment component");
406        if (uri.getQuery() != null)
407            throw new IllegalArgumentException("URI has a query component");
408        String p = uri.getPath();
409        if (p.equals(""))
410            throw new IllegalArgumentException("URI path component is empty");
411
412        // Okay, now initialize
413        p = fs.fromURIPath(p);
414        if (File.separatorChar != '/')
415            p = p.replace('/', File.separatorChar);
416        this.path = fs.normalize(p);
417        this.prefixLength = fs.prefixLength(this.path);
418    }
419
420
421    /* -- Path-component accessors -- */
422
423    /**
424     * Returns the name of the file or directory denoted by this abstract
425     * pathname.  This is just the last name in the pathname's name
426     * sequence.  If the pathname's name sequence is empty, then the empty
427     * string is returned.
428     *
429     * @return  The name of the file or directory denoted by this abstract
430     *          pathname, or the empty string if this pathname's name sequence
431     *          is empty
432     */
433    public String getName() {
434        int index = path.lastIndexOf(separatorChar);
435        if (index < prefixLength) return path.substring(prefixLength);
436        return path.substring(index + 1);
437    }
438
439    /**
440     * Returns the pathname string of this abstract pathname's parent, or
441     * <code>null</code> if this pathname does not name a parent directory.
442     *
443     * <p> The <em>parent</em> of an abstract pathname consists of the
444     * pathname's prefix, if any, and each name in the pathname's name
445     * sequence except for the last.  If the name sequence is empty then
446     * the pathname does not name a parent directory.
447     *
448     * @return  The pathname string of the parent directory named by this
449     *          abstract pathname, or <code>null</code> if this pathname
450     *          does not name a parent
451     */
452    public String getParent() {
453        int index = path.lastIndexOf(separatorChar);
454        if (index < prefixLength) {
455            if ((prefixLength > 0) && (path.length() > prefixLength))
456                return path.substring(0, prefixLength);
457            return null;
458        }
459        return path.substring(0, index);
460    }
461
462    /**
463     * Returns the abstract pathname of this abstract pathname's parent,
464     * or <code>null</code> if this pathname does not name a parent
465     * directory.
466     *
467     * <p> The <em>parent</em> of an abstract pathname consists of the
468     * pathname's prefix, if any, and each name in the pathname's name
469     * sequence except for the last.  If the name sequence is empty then
470     * the pathname does not name a parent directory.
471     *
472     * @return  The abstract pathname of the parent directory named by this
473     *          abstract pathname, or <code>null</code> if this pathname
474     *          does not name a parent
475     *
476     * @since 1.2
477     */
478    public File getParentFile() {
479        String p = this.getParent();
480        if (p == null) return null;
481        return new File(p, this.prefixLength);
482    }
483
484    /**
485     * Converts this abstract pathname into a pathname string.  The resulting
486     * string uses the {@link #separator default name-separator character} to
487     * separate the names in the name sequence.
488     *
489     * @return  The string form of this abstract pathname
490     */
491    public String getPath() {
492        return path;
493    }
494
495
496    /* -- Path operations -- */
497
498    /**
499     * Tests whether this abstract pathname is absolute.  The definition of
500     * absolute pathname is system dependent.  On Android, absolute paths start with
501     * the character '/'.
502     *
503     * @return  <code>true</code> if this abstract pathname is absolute,
504     *          <code>false</code> otherwise
505     */
506    public boolean isAbsolute() {
507        return fs.isAbsolute(this);
508    }
509
510    /**
511     * Returns the absolute path of this file. An absolute path is a path that starts at a root
512     * of the file system. On Android, there is only one root: {@code /}.
513     *
514     * <p>A common use for absolute paths is when passing paths to a {@code Process} as
515     * command-line arguments, to remove the requirement implied by relative paths, that the
516     * child must have the same working directory as its parent.
517     *
518     * @return  The absolute pathname string denoting the same file or
519     *          directory as this abstract pathname
520     *
521     * @see     java.io.File#isAbsolute()
522     */
523    public String getAbsolutePath() {
524        return fs.resolve(this);
525    }
526
527    /**
528     * Returns the absolute form of this abstract pathname.  Equivalent to
529     * <code>new&nbsp;File(this.{@link #getAbsolutePath})</code>.
530     *
531     * @return  The absolute abstract pathname denoting the same file or
532     *          directory as this abstract pathname
533     *
534     * @throws  SecurityException
535     *          If a required system property value cannot be accessed.
536     *
537     * @since 1.2
538     */
539    public File getAbsoluteFile() {
540        String absPath = getAbsolutePath();
541        return new File(absPath, fs.prefixLength(absPath));
542    }
543
544    /**
545     * Returns the canonical pathname string of this abstract pathname.
546     *
547     * <p> A canonical pathname is both absolute and unique.  The precise
548     * definition of canonical form is system-dependent.  This method first
549     * converts this pathname to absolute form if necessary, as if by invoking the
550     * {@link #getAbsolutePath} method, and then maps it to its unique form in a
551     * system-dependent way.  This typically involves removing redundant names
552     * such as <tt>"."</tt> and <tt>".."</tt> from the pathname, resolving
553     * symbolic links (on UNIX platforms), and converting drive letters to a
554     * standard case (on Microsoft Windows platforms).
555     *
556     * <p> Every pathname that denotes an existing file or directory has a
557     * unique canonical form.  Every pathname that denotes a nonexistent file
558     * or directory also has a unique canonical form.  The canonical form of
559     * the pathname of a nonexistent file or directory may be different from
560     * the canonical form of the same pathname after the file or directory is
561     * created.  Similarly, the canonical form of the pathname of an existing
562     * file or directory may be different from the canonical form of the same
563     * pathname after the file or directory is deleted.
564     *
565     * @return  The canonical pathname string denoting the same file or
566     *          directory as this abstract pathname
567     *
568     * @throws  IOException
569     *          If an I/O error occurs, which is possible because the
570     *          construction of the canonical pathname may require
571     *          filesystem queries
572     *
573     * @throws  SecurityException
574     *          If a required system property value cannot be accessed, or
575     *          if a security manager exists and its <code>{@link
576     *          java.lang.SecurityManager#checkRead}</code> method denies
577     *          read access to the file
578     *
579     * @since   JDK1.1
580     * @see     Path#toRealPath
581     */
582    public String getCanonicalPath() throws IOException {
583        if (isInvalid()) {
584            throw new IOException("Invalid file path");
585        }
586        return fs.canonicalize(fs.resolve(this));
587    }
588
589    /**
590     * Returns the canonical form of this abstract pathname.  Equivalent to
591     * <code>new&nbsp;File(this.{@link #getCanonicalPath})</code>.
592     *
593     * @return  The canonical pathname string denoting the same file or
594     *          directory as this abstract pathname
595     *
596     * @throws  IOException
597     *          If an I/O error occurs, which is possible because the
598     *          construction of the canonical pathname may require
599     *          filesystem queries
600     *
601     * @throws  SecurityException
602     *          If a required system property value cannot be accessed, or
603     *          if a security manager exists and its <code>{@link
604     *          java.lang.SecurityManager#checkRead}</code> method denies
605     *          read access to the file
606     *
607     * @since 1.2
608     * @see     Path#toRealPath
609     */
610    public File getCanonicalFile() throws IOException {
611        String canonPath = getCanonicalPath();
612        return new File(canonPath, fs.prefixLength(canonPath));
613    }
614
615    private static String slashify(String path, boolean isDirectory) {
616        String p = path;
617        if (File.separatorChar != '/')
618            p = p.replace(File.separatorChar, '/');
619        if (!p.startsWith("/"))
620            p = "/" + p;
621        if (!p.endsWith("/") && isDirectory)
622            p = p + "/";
623        return p;
624    }
625
626    /**
627     * Converts this abstract pathname into a <code>file:</code> URL.  The
628     * exact form of the URL is system-dependent.  If it can be determined that
629     * the file denoted by this abstract pathname is a directory, then the
630     * resulting URL will end with a slash.
631     *
632     * @return  A URL object representing the equivalent file URL
633     *
634     * @throws  MalformedURLException
635     *          If the path cannot be parsed as a URL
636     *
637     * @see     #toURI()
638     * @see     java.net.URI
639     * @see     java.net.URI#toURL()
640     * @see     java.net.URL
641     * @since   1.2
642     *
643     * @deprecated This method does not automatically escape characters that
644     * are illegal in URLs.  It is recommended that new code convert an
645     * abstract pathname into a URL by first converting it into a URI, via the
646     * {@link #toURI() toURI} method, and then converting the URI into a URL
647     * via the {@link java.net.URI#toURL() URI.toURL} method.
648     */
649    @Deprecated
650    public URL toURL() throws MalformedURLException {
651        if (isInvalid()) {
652            throw new MalformedURLException("Invalid file path");
653        }
654        return new URL("file", "", slashify(getAbsolutePath(),
655                getAbsoluteFile().isDirectory()));
656    }
657
658    /**
659     * Constructs a <tt>file:</tt> URI that represents this abstract pathname.
660     *
661     * <p> The exact form of the URI is system-dependent.  If it can be
662     * determined that the file denoted by this abstract pathname is a
663     * directory, then the resulting URI will end with a slash.
664     *
665     * <p> For a given abstract pathname <i>f</i>, it is guaranteed that
666     *
667     * <blockquote><tt>
668     * new {@link #File(java.net.URI) File}(</tt><i>&nbsp;f</i><tt>.toURI()).equals(</tt><i>&nbsp;f</i><tt>.{@link #getAbsoluteFile() getAbsoluteFile}())
669     * </tt></blockquote>
670     *
671     * so long as the original abstract pathname, the URI, and the new abstract
672     * pathname are all created in (possibly different invocations of) the same
673     * Java virtual machine.  Due to the system-dependent nature of abstract
674     * pathnames, however, this relationship typically does not hold when a
675     * <tt>file:</tt> URI that is created in a virtual machine on one operating
676     * system is converted into an abstract pathname in a virtual machine on a
677     * different operating system.
678     *
679     * <p> Note that when this abstract pathname represents a UNC pathname then
680     * all components of the UNC (including the server name component) are encoded
681     * in the {@code URI} path. The authority component is undefined, meaning
682     * that it is represented as {@code null}.
683     *
684     * @return  An absolute, hierarchical URI with a scheme equal to
685     *          <tt>"file"</tt>, a path representing this abstract pathname,
686     *          and undefined authority, query, and fragment components
687     * @throws SecurityException If a required system property value cannot
688     * be accessed.
689     *
690     * @see #File(java.net.URI)
691     * @see java.net.URI
692     * @see java.net.URI#toURL()
693     * @since 1.4
694     */
695    public URI toURI() {
696        try {
697            File f = getAbsoluteFile();
698            String sp = slashify(f.getPath(), f.isDirectory());
699            if (sp.startsWith("//"))
700                sp = "//" + sp;
701            return new URI("file", null, sp, null);
702        } catch (URISyntaxException x) {
703            throw new Error(x);         // Can't happen
704        }
705    }
706
707
708    /* -- Attribute accessors -- */
709
710    /**
711     * Tests whether the application can read the file denoted by this
712     * abstract pathname.
713     *
714     * @return  <code>true</code> if and only if the file specified by this
715     *          abstract pathname exists <em>and</em> can be read by the
716     *          application; <code>false</code> otherwise
717     *
718     * @throws  SecurityException
719     *          If a security manager exists and its <code>{@link
720     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
721     *          method denies read access to the file
722     */
723    public boolean canRead() {
724        SecurityManager security = System.getSecurityManager();
725        if (security != null) {
726            security.checkRead(path);
727        }
728        if (isInvalid()) {
729            return false;
730        }
731        return fs.checkAccess(this, FileSystem.ACCESS_READ);
732    }
733
734    /**
735     * Tests whether the application can modify the file denoted by this
736     * abstract pathname.
737     *
738     * @return  <code>true</code> if and only if the file system actually
739     *          contains a file denoted by this abstract pathname <em>and</em>
740     *          the application is allowed to write to the file;
741     *          <code>false</code> otherwise.
742     *
743     * @throws  SecurityException
744     *          If a security manager exists and its <code>{@link
745     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
746     *          method denies write access to the file
747     */
748    public boolean canWrite() {
749        SecurityManager security = System.getSecurityManager();
750        if (security != null) {
751            security.checkWrite(path);
752        }
753        if (isInvalid()) {
754            return false;
755        }
756        return fs.checkAccess(this, FileSystem.ACCESS_WRITE);
757    }
758
759    /**
760     * Tests whether the file or directory denoted by this abstract pathname
761     * exists.
762     *
763     * @return  <code>true</code> if and only if the file or directory denoted
764     *          by this abstract pathname exists; <code>false</code> otherwise
765     *
766     * @throws  SecurityException
767     *          If a security manager exists and its <code>{@link
768     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
769     *          method denies read access to the file or directory
770     */
771    public boolean exists() {
772        SecurityManager security = System.getSecurityManager();
773        if (security != null) {
774            security.checkRead(path);
775        }
776        if (isInvalid()) {
777            return false;
778        }
779
780        return fs.checkAccess(this, FileSystem.ACCESS_OK);
781    }
782
783    /**
784     * Tests whether the file denoted by this abstract pathname is a
785     * directory.
786     *
787     * @return <code>true</code> if and only if the file denoted by this
788     *          abstract pathname exists <em>and</em> is a directory;
789     *          <code>false</code> otherwise
790     *
791     * @throws  SecurityException
792     *          If a security manager exists and its <code>{@link
793     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
794     *          method denies read access to the file
795     */
796    public boolean isDirectory() {
797        SecurityManager security = System.getSecurityManager();
798        if (security != null) {
799            security.checkRead(path);
800        }
801        if (isInvalid()) {
802            return false;
803        }
804        return ((fs.getBooleanAttributes(this) & FileSystem.BA_DIRECTORY)
805                != 0);
806    }
807
808    /**
809     * Tests whether the file denoted by this abstract pathname is a normal
810     * file.  A file is <em>normal</em> if it is not a directory and, in
811     * addition, satisfies other system-dependent criteria.  Any non-directory
812     * file created by a Java application is guaranteed to be a normal file.
813     *
814     * @return  <code>true</code> if and only if the file denoted by this
815     *          abstract pathname exists <em>and</em> is a normal file;
816     *          <code>false</code> otherwise
817     *
818     * @throws  SecurityException
819     *          If a security manager exists and its <code>{@link
820     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
821     *          method denies read access to the file
822     */
823    public boolean isFile() {
824        SecurityManager security = System.getSecurityManager();
825        if (security != null) {
826            security.checkRead(path);
827        }
828        if (isInvalid()) {
829            return false;
830        }
831        return ((fs.getBooleanAttributes(this) & FileSystem.BA_REGULAR) != 0);
832    }
833
834    /**
835     * Tests whether the file named by this abstract pathname is a hidden
836     * file.  The exact definition of <em>hidden</em> is system-dependent.  On
837     * UNIX systems, a file is considered to be hidden if its name begins with
838     * a period character (<code>'.'</code>).  On Microsoft Windows systems, a file is
839     * considered to be hidden if it has been marked as such in the filesystem.
840     *
841     * @return  <code>true</code> if and only if the file denoted by this
842     *          abstract pathname is hidden according to the conventions of the
843     *          underlying platform
844     *
845     * @throws  SecurityException
846     *          If a security manager exists and its <code>{@link
847     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
848     *          method denies read access to the file
849     *
850     * @since 1.2
851     */
852    public boolean isHidden() {
853        SecurityManager security = System.getSecurityManager();
854        if (security != null) {
855            security.checkRead(path);
856        }
857        if (isInvalid()) {
858            return false;
859        }
860        return ((fs.getBooleanAttributes(this) & FileSystem.BA_HIDDEN) != 0);
861    }
862
863    /**
864     * Returns the time that the file denoted by this abstract pathname was
865     * last modified.
866     *
867     * @return  A <code>long</code> value representing the time the file was
868     *          last modified, measured in milliseconds since the epoch
869     *          (00:00:00 GMT, January 1, 1970), or <code>0L</code> if the
870     *          file does not exist or if an I/O error occurs
871     *
872     * @throws  SecurityException
873     *          If a security manager exists and its <code>{@link
874     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
875     *          method denies read access to the file
876     */
877    public long lastModified() {
878        SecurityManager security = System.getSecurityManager();
879        if (security != null) {
880            security.checkRead(path);
881        }
882        if (isInvalid()) {
883            return 0L;
884        }
885        return fs.getLastModifiedTime(this);
886    }
887
888    /**
889     * Returns the length of the file denoted by this abstract pathname.
890     * The return value is unspecified if this pathname denotes a directory.
891     *
892     * @return  The length, in bytes, of the file denoted by this abstract
893     *          pathname, or <code>0L</code> if the file does not exist.  Some
894     *          operating systems may return <code>0L</code> for pathnames
895     *          denoting system-dependent entities such as devices or pipes.
896     *
897     * @throws  SecurityException
898     *          If a security manager exists and its <code>{@link
899     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
900     *          method denies read access to the file
901     */
902    public long length() {
903        SecurityManager security = System.getSecurityManager();
904        if (security != null) {
905            security.checkRead(path);
906        }
907        if (isInvalid()) {
908            return 0L;
909        }
910        return fs.getLength(this);
911    }
912
913
914    /* -- File operations -- */
915
916    /**
917     * Atomically creates a new, empty file named by this abstract pathname if
918     * and only if a file with this name does not yet exist.  The check for the
919     * existence of the file and the creation of the file if it does not exist
920     * are a single operation that is atomic with respect to all other
921     * filesystem activities that might affect the file.
922     * <P>
923     * Note: this method should <i>not</i> be used for file-locking, as
924     * the resulting protocol cannot be made to work reliably. The
925     * {@link java.nio.channels.FileLock FileLock}
926     * facility should be used instead.
927     *
928     * @return  <code>true</code> if the named file does not exist and was
929     *          successfully created; <code>false</code> if the named file
930     *          already exists
931     *
932     * @throws  IOException
933     *          If an I/O error occurred
934     *
935     * @throws  SecurityException
936     *          If a security manager exists and its <code>{@link
937     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
938     *          method denies write access to the file
939     *
940     * @since 1.2
941     */
942    public boolean createNewFile() throws IOException {
943        SecurityManager security = System.getSecurityManager();
944        if (security != null) security.checkWrite(path);
945        if (isInvalid()) {
946            throw new IOException("Invalid file path");
947        }
948        return fs.createFileExclusively(path);
949    }
950
951    /**
952     * Deletes the file or directory denoted by this abstract pathname.  If
953     * this pathname denotes a directory, then the directory must be empty in
954     * order to be deleted.
955     *
956     * @return  <code>true</code> if and only if the file or directory is
957     *          successfully deleted; <code>false</code> otherwise
958     *
959     * @throws  SecurityException
960     *          If a security manager exists and its <code>{@link
961     *          java.lang.SecurityManager#checkDelete}</code> method denies
962     *          delete access to the file
963     */
964    public boolean delete() {
965        SecurityManager security = System.getSecurityManager();
966        if (security != null) {
967            security.checkDelete(path);
968        }
969        if (isInvalid()) {
970            return false;
971        }
972        return fs.delete(this);
973    }
974
975    /**
976     * Requests that the file or directory denoted by this abstract
977     * pathname be deleted when the virtual machine terminates.
978     * Files (or directories) are deleted in the reverse order that
979     * they are registered. Invoking this method to delete a file or
980     * directory that is already registered for deletion has no effect.
981     * Deletion will be attempted only for normal termination of the
982     * virtual machine, as defined by the Java Language Specification.
983     *
984     * <p> Once deletion has been requested, it is not possible to cancel the
985     * request.  This method should therefore be used with care.
986     *
987     * <P>
988     * Note: this method should <i>not</i> be used for file-locking, as
989     * the resulting protocol cannot be made to work reliably. The
990     * {@link java.nio.channels.FileLock FileLock}
991     * facility should be used instead.
992     *
993     * <p><i>Note that on Android, the application lifecycle does not include VM termination,
994     * so calling this method will not ensure that files are deleted</i>. Instead, you should
995     * use the most appropriate out of:
996     * <ul>
997     * <li>Use a {@code finally} clause to manually invoke {@link #delete}.
998     * <li>Maintain your own set of files to delete, and process it at an appropriate point
999     * in your application's lifecycle.
1000     * <li>Use the Unix trick of deleting the file as soon as all readers and writers have
1001     * opened it. No new readers/writers will be able to access the file, but all existing
1002     * ones will still have access until the last one closes the file.
1003     * </ul>
1004     *
1005     * @throws  SecurityException
1006     *          If a security manager exists and its <code>{@link
1007     *          java.lang.SecurityManager#checkDelete}</code> method denies
1008     *          delete access to the file
1009     *
1010     * @see #delete
1011     *
1012     * @since 1.2
1013     */
1014    public void deleteOnExit() {
1015        SecurityManager security = System.getSecurityManager();
1016        if (security != null) {
1017            security.checkDelete(path);
1018        }
1019        if (isInvalid()) {
1020            return;
1021        }
1022        DeleteOnExitHook.add(path);
1023    }
1024
1025    /**
1026     * Returns an array of strings naming the files and directories in the
1027     * directory denoted by this abstract pathname.
1028     *
1029     * <p> If this abstract pathname does not denote a directory, then this
1030     * method returns {@code null}.  Otherwise an array of strings is
1031     * returned, one for each file or directory in the directory.  Names
1032     * denoting the directory itself and the directory's parent directory are
1033     * not included in the result.  Each string is a file name rather than a
1034     * complete path.
1035     *
1036     * <p> There is no guarantee that the name strings in the resulting array
1037     * will appear in any specific order; they are not, in particular,
1038     * guaranteed to appear in alphabetical order.
1039     *
1040     * @return  An array of strings naming the files and directories in the
1041     *          directory denoted by this abstract pathname.  The array will be
1042     *          empty if the directory is empty.  Returns {@code null} if
1043     *          this abstract pathname does not denote a directory, or if an
1044     *          I/O error occurs.
1045     *
1046     * @throws  SecurityException
1047     *          If a security manager exists and its {@link
1048     *          SecurityManager#checkRead(String)} method denies read access to
1049     *          the directory
1050     */
1051    public String[] list() {
1052        SecurityManager security = System.getSecurityManager();
1053        if (security != null) {
1054            security.checkRead(path);
1055        }
1056        if (isInvalid()) {
1057            return null;
1058        }
1059        return fs.list(this);
1060    }
1061
1062    /**
1063     * Returns an array of strings naming the files and directories in the
1064     * directory denoted by this abstract pathname that satisfy the specified
1065     * filter.  The behavior of this method is the same as that of the
1066     * {@link #list()} method, except that the strings in the returned array
1067     * must satisfy the filter.  If the given {@code filter} is {@code null}
1068     * then all names are accepted.  Otherwise, a name satisfies the filter if
1069     * and only if the value {@code true} results when the {@link
1070     * FilenameFilter#accept FilenameFilter.accept(File,&nbsp;String)} method
1071     * of the filter is invoked on this abstract pathname and the name of a
1072     * file or directory in the directory that it denotes.
1073     *
1074     * @param  filter
1075     *         A filename filter
1076     *
1077     * @return  An array of strings naming the files and directories in the
1078     *          directory denoted by this abstract pathname that were accepted
1079     *          by the given {@code filter}.  The array will be empty if the
1080     *          directory is empty or if no names were accepted by the filter.
1081     *          Returns {@code null} if this abstract pathname does not denote
1082     *          a directory, or if an I/O error occurs.
1083     *
1084     * @throws  SecurityException
1085     *          If a security manager exists and its {@link
1086     *          SecurityManager#checkRead(String)} method denies read access to
1087     *          the directory
1088     *
1089     */
1090    public String[] list(FilenameFilter filter) {
1091        String names[] = list();
1092        if ((names == null) || (filter == null)) {
1093            return names;
1094        }
1095        List<String> v = new ArrayList<>();
1096        for (int i = 0 ; i < names.length ; i++) {
1097            if (filter.accept(this, names[i])) {
1098                v.add(names[i]);
1099            }
1100        }
1101        return v.toArray(new String[v.size()]);
1102    }
1103
1104    /**
1105     * Returns an array of abstract pathnames denoting the files in the
1106     * directory denoted by this abstract pathname.
1107     *
1108     * <p> If this abstract pathname does not denote a directory, then this
1109     * method returns {@code null}.  Otherwise an array of {@code File} objects
1110     * is returned, one for each file or directory in the directory.  Pathnames
1111     * denoting the directory itself and the directory's parent directory are
1112     * not included in the result.  Each resulting abstract pathname is
1113     * constructed from this abstract pathname using the {@link #File(File,
1114     * String) File(File,&nbsp;String)} constructor.  Therefore if this
1115     * pathname is absolute then each resulting pathname is absolute; if this
1116     * pathname is relative then each resulting pathname will be relative to
1117     * the same directory.
1118     *
1119     * <p> There is no guarantee that the name strings in the resulting array
1120     * will appear in any specific order; they are not, in particular,
1121     * guaranteed to appear in alphabetical order.
1122     *
1123     * @return  An array of abstract pathnames denoting the files and
1124     *          directories in the directory denoted by this abstract pathname.
1125     *          The array will be empty if the directory is empty.  Returns
1126     *          {@code null} if this abstract pathname does not denote a
1127     *          directory, or if an I/O error occurs.
1128     *
1129     * @throws  SecurityException
1130     *          If a security manager exists and its {@link
1131     *          SecurityManager#checkRead(String)} method denies read access to
1132     *          the directory
1133     *
1134     * @since  1.2
1135     */
1136    public File[] listFiles() {
1137        String[] ss = list();
1138        if (ss == null) return null;
1139        int n = ss.length;
1140        File[] fs = new File[n];
1141        for (int i = 0; i < n; i++) {
1142            fs[i] = new File(ss[i], this);
1143        }
1144        return fs;
1145    }
1146
1147    /**
1148     * Returns an array of abstract pathnames denoting the files and
1149     * directories in the directory denoted by this abstract pathname that
1150     * satisfy the specified filter.  The behavior of this method is the same
1151     * as that of the {@link #listFiles()} method, except that the pathnames in
1152     * the returned array must satisfy the filter.  If the given {@code filter}
1153     * is {@code null} then all pathnames are accepted.  Otherwise, a pathname
1154     * satisfies the filter if and only if the value {@code true} results when
1155     * the {@link FilenameFilter#accept
1156     * FilenameFilter.accept(File,&nbsp;String)} method of the filter is
1157     * invoked on this abstract pathname and the name of a file or directory in
1158     * the directory that it denotes.
1159     *
1160     * @param  filter
1161     *         A filename filter
1162     *
1163     * @return  An array of abstract pathnames denoting the files and
1164     *          directories in the directory denoted by this abstract pathname.
1165     *          The array will be empty if the directory is empty.  Returns
1166     *          {@code null} if this abstract pathname does not denote a
1167     *          directory, or if an I/O error occurs.
1168     *
1169     * @throws  SecurityException
1170     *          If a security manager exists and its {@link
1171     *          SecurityManager#checkRead(String)} method denies read access to
1172     *          the directory
1173     *
1174     * @since  1.2
1175     */
1176    public File[] listFiles(FilenameFilter filter) {
1177        String ss[] = list();
1178        if (ss == null) return null;
1179        ArrayList<File> files = new ArrayList<>();
1180        for (String s : ss)
1181            if ((filter == null) || filter.accept(this, s))
1182                files.add(new File(s, this));
1183        return files.toArray(new File[files.size()]);
1184    }
1185
1186    /**
1187     * Returns an array of abstract pathnames denoting the files and
1188     * directories in the directory denoted by this abstract pathname that
1189     * satisfy the specified filter.  The behavior of this method is the same
1190     * as that of the {@link #listFiles()} method, except that the pathnames in
1191     * the returned array must satisfy the filter.  If the given {@code filter}
1192     * is {@code null} then all pathnames are accepted.  Otherwise, a pathname
1193     * satisfies the filter if and only if the value {@code true} results when
1194     * the {@link FileFilter#accept FileFilter.accept(File)} method of the
1195     * filter is invoked on the pathname.
1196     *
1197     * @param  filter
1198     *         A file filter
1199     *
1200     * @return  An array of abstract pathnames denoting the files and
1201     *          directories in the directory denoted by this abstract pathname.
1202     *          The array will be empty if the directory is empty.  Returns
1203     *          {@code null} if this abstract pathname does not denote a
1204     *          directory, or if an I/O error occurs.
1205     *
1206     * @throws  SecurityException
1207     *          If a security manager exists and its {@link
1208     *          SecurityManager#checkRead(String)} method denies read access to
1209     *          the directory
1210     *
1211     * @since  1.2
1212     */
1213    public File[] listFiles(FileFilter filter) {
1214        String ss[] = list();
1215        if (ss == null) return null;
1216        ArrayList<File> files = new ArrayList<>();
1217        for (String s : ss) {
1218            File f = new File(s, this);
1219            if ((filter == null) || filter.accept(f))
1220                files.add(f);
1221        }
1222        return files.toArray(new File[files.size()]);
1223    }
1224
1225    /**
1226     * Creates the directory named by this abstract pathname.
1227     *
1228     * @return  <code>true</code> if and only if the directory was
1229     *          created; <code>false</code> otherwise
1230     *
1231     * @throws  SecurityException
1232     *          If a security manager exists and its <code>{@link
1233     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1234     *          method does not permit the named directory to be created
1235     */
1236    public boolean mkdir() {
1237        SecurityManager security = System.getSecurityManager();
1238        if (security != null) {
1239            security.checkWrite(path);
1240        }
1241        if (isInvalid()) {
1242            return false;
1243        }
1244        return fs.createDirectory(this);
1245    }
1246
1247    /**
1248     * Creates the directory named by this abstract pathname, including any
1249     * necessary but nonexistent parent directories.  Note that if this
1250     * operation fails it may have succeeded in creating some of the necessary
1251     * parent directories.
1252     *
1253     * @return  <code>true</code> if and only if the directory was created,
1254     *          along with all necessary parent directories; <code>false</code>
1255     *          otherwise
1256     *
1257     * @throws  SecurityException
1258     *          If a security manager exists and its <code>{@link
1259     *          java.lang.SecurityManager#checkRead(java.lang.String)}</code>
1260     *          method does not permit verification of the existence of the
1261     *          named directory and all necessary parent directories; or if
1262     *          the <code>{@link
1263     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1264     *          method does not permit the named directory and all necessary
1265     *          parent directories to be created
1266     */
1267    public boolean mkdirs() {
1268        if (exists()) {
1269            return false;
1270        }
1271        if (mkdir()) {
1272            return true;
1273        }
1274        File canonFile = null;
1275        try {
1276            canonFile = getCanonicalFile();
1277        } catch (IOException e) {
1278            return false;
1279        }
1280
1281        File parent = canonFile.getParentFile();
1282        return (parent != null && (parent.mkdirs() || parent.exists()) &&
1283                canonFile.mkdir());
1284    }
1285
1286    /**
1287     * Renames the file denoted by this abstract pathname.
1288     *
1289     * <p>Many failures are possible. Some of the more likely failures include:
1290     * <ul>
1291     * <li>Write permission is required on the directories containing both the source and
1292     * destination paths.
1293     * <li>Search permission is required for all parents of both paths.
1294     * <li>Both paths be on the same mount point. On Android, applications are most likely to hit
1295     * this restriction when attempting to copy between internal storage and an SD card.
1296     * </ul>
1297     *
1298     * <p>The return value should always be checked to make sure
1299     * that the rename operation was successful.
1300     *
1301     * @param  dest  The new abstract pathname for the named file
1302     *
1303     * @return  <code>true</code> if and only if the renaming succeeded;
1304     *          <code>false</code> otherwise
1305     *
1306     * @throws  SecurityException
1307     *          If a security manager exists and its <code>{@link
1308     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1309     *          method denies write access to either the old or new pathnames
1310     *
1311     * @throws  NullPointerException
1312     *          If parameter <code>dest</code> is <code>null</code>
1313     */
1314    public boolean renameTo(File dest) {
1315        SecurityManager security = System.getSecurityManager();
1316        if (security != null) {
1317            security.checkWrite(path);
1318            security.checkWrite(dest.path);
1319        }
1320        if (dest == null) {
1321            throw new NullPointerException();
1322        }
1323        if (this.isInvalid() || dest.isInvalid()) {
1324            return false;
1325        }
1326        return fs.rename(this, dest);
1327    }
1328
1329    /**
1330     * Sets the last-modified time of the file or directory named by this
1331     * abstract pathname.
1332     *
1333     * <p> All platforms support file-modification times to the nearest second,
1334     * but some provide more precision.  The argument will be truncated to fit
1335     * the supported precision.  If the operation succeeds and no intervening
1336     * operations on the file take place, then the next invocation of the
1337     * <code>{@link #lastModified}</code> method will return the (possibly
1338     * truncated) <code>time</code> argument that was passed to this method.
1339     *
1340     * @param  time  The new last-modified time, measured in milliseconds since
1341     *               the epoch (00:00:00 GMT, January 1, 1970)
1342     *
1343     * @return <code>true</code> if and only if the operation succeeded;
1344     *          <code>false</code> otherwise
1345     *
1346     * @throws  IllegalArgumentException  If the argument is negative
1347     *
1348     * @throws  SecurityException
1349     *          If a security manager exists and its <code>{@link
1350     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1351     *          method denies write access to the named file
1352     *
1353     * @since 1.2
1354     */
1355    public boolean setLastModified(long time) {
1356        if (time < 0) throw new IllegalArgumentException("Negative time");
1357        SecurityManager security = System.getSecurityManager();
1358        if (security != null) {
1359            security.checkWrite(path);
1360        }
1361        if (isInvalid()) {
1362            return false;
1363        }
1364        return fs.setLastModifiedTime(this, time);
1365    }
1366
1367    /**
1368     * Marks the file or directory named by this abstract pathname so that
1369     * only read operations are allowed.  After invoking this method the file
1370     * or directory is guaranteed not to change until it is either deleted or
1371     * marked to allow write access.  Whether or not a read-only file or
1372     * directory may be deleted depends upon the underlying system.
1373     *
1374     * @return <code>true</code> if and only if the operation succeeded;
1375     *          <code>false</code> otherwise
1376     *
1377     * @throws  SecurityException
1378     *          If a security manager exists and its <code>{@link
1379     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1380     *          method denies write access to the named file
1381     *
1382     * @since 1.2
1383     */
1384    public boolean setReadOnly() {
1385        SecurityManager security = System.getSecurityManager();
1386        if (security != null) {
1387            security.checkWrite(path);
1388        }
1389        if (isInvalid()) {
1390            return false;
1391        }
1392        return fs.setReadOnly(this);
1393    }
1394
1395    /**
1396     * Sets the owner's or everybody's write permission for this abstract
1397     * pathname.
1398     *
1399     * @param   writable
1400     *          If <code>true</code>, sets the access permission to allow write
1401     *          operations; if <code>false</code> to disallow write operations
1402     *
1403     * @param   ownerOnly
1404     *          If <code>true</code>, the write permission applies only to the
1405     *          owner's write permission; otherwise, it applies to everybody.  If
1406     *          the underlying file system can not distinguish the owner's write
1407     *          permission from that of others, then the permission will apply to
1408     *          everybody, regardless of this value.
1409     *
1410     * @return  <code>true</code> if and only if the operation succeeded. The
1411     *          operation will fail if the user does not have permission to change
1412     *          the access permissions of this abstract pathname.
1413     *
1414     * @throws  SecurityException
1415     *          If a security manager exists and its <code>{@link
1416     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1417     *          method denies write access to the named file
1418     *
1419     * @since 1.6
1420     */
1421    public boolean setWritable(boolean writable, boolean ownerOnly) {
1422        SecurityManager security = System.getSecurityManager();
1423        if (security != null) {
1424            security.checkWrite(path);
1425        }
1426        if (isInvalid()) {
1427            return false;
1428        }
1429        return fs.setPermission(this, FileSystem.ACCESS_WRITE, writable, ownerOnly);
1430    }
1431
1432    /**
1433     * A convenience method to set the owner's write permission for this abstract
1434     * pathname.
1435     *
1436     * <p> An invocation of this method of the form <tt>file.setWritable(arg)</tt>
1437     * behaves in exactly the same way as the invocation
1438     *
1439     * <pre>
1440     *     file.setWritable(arg, true) </pre>
1441     *
1442     * @param   writable
1443     *          If <code>true</code>, sets the access permission to allow write
1444     *          operations; if <code>false</code> to disallow write operations
1445     *
1446     * @return  <code>true</code> if and only if the operation succeeded.  The
1447     *          operation will fail if the user does not have permission to
1448     *          change the access permissions of this abstract pathname.
1449     *
1450     * @throws  SecurityException
1451     *          If a security manager exists and its <code>{@link
1452     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1453     *          method denies write access to the file
1454     *
1455     * @since 1.6
1456     */
1457    public boolean setWritable(boolean writable) {
1458        return setWritable(writable, true);
1459    }
1460
1461    /**
1462     * Sets the owner's or everybody's read permission for this abstract
1463     * pathname.
1464     *
1465     * @param   readable
1466     *          If <code>true</code>, sets the access permission to allow read
1467     *          operations; if <code>false</code> to disallow read operations
1468     *
1469     * @param   ownerOnly
1470     *          If <code>true</code>, the read permission applies only to the
1471     *          owner's read permission; otherwise, it applies to everybody.  If
1472     *          the underlying file system can not distinguish the owner's read
1473     *          permission from that of others, then the permission will apply to
1474     *          everybody, regardless of this value.
1475     *
1476     * @return  <code>true</code> if and only if the operation succeeded.  The
1477     *          operation will fail if the user does not have permission to
1478     *          change the access permissions of this abstract pathname.  If
1479     *          <code>readable</code> is <code>false</code> and the underlying
1480     *          file system does not implement a read permission, then the
1481     *          operation will fail.
1482     *
1483     * @throws  SecurityException
1484     *          If a security manager exists and its <code>{@link
1485     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1486     *          method denies write access to the file
1487     *
1488     * @since 1.6
1489     */
1490    public boolean setReadable(boolean readable, boolean ownerOnly) {
1491        SecurityManager security = System.getSecurityManager();
1492        if (security != null) {
1493            security.checkWrite(path);
1494        }
1495        if (isInvalid()) {
1496            return false;
1497        }
1498        return fs.setPermission(this, FileSystem.ACCESS_READ, readable, ownerOnly);
1499    }
1500
1501    /**
1502     * A convenience method to set the owner's read permission for this abstract
1503     * pathname.
1504     *
1505     * <p>An invocation of this method of the form <tt>file.setReadable(arg)</tt>
1506     * behaves in exactly the same way as the invocation
1507     *
1508     * <pre>
1509     *     file.setReadable(arg, true) </pre>
1510     *
1511     * @param  readable
1512     *          If <code>true</code>, sets the access permission to allow read
1513     *          operations; if <code>false</code> to disallow read operations
1514     *
1515     * @return  <code>true</code> if and only if the operation succeeded.  The
1516     *          operation will fail if the user does not have permission to
1517     *          change the access permissions of this abstract pathname.  If
1518     *          <code>readable</code> is <code>false</code> and the underlying
1519     *          file system does not implement a read permission, then the
1520     *          operation will fail.
1521     *
1522     * @throws  SecurityException
1523     *          If a security manager exists and its <code>{@link
1524     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1525     *          method denies write access to the file
1526     *
1527     * @since 1.6
1528     */
1529    public boolean setReadable(boolean readable) {
1530        return setReadable(readable, true);
1531    }
1532
1533    /**
1534     * Sets the owner's or everybody's execute permission for this abstract
1535     * pathname.
1536     *
1537     * @param   executable
1538     *          If <code>true</code>, sets the access permission to allow execute
1539     *          operations; if <code>false</code> to disallow execute operations
1540     *
1541     * @param   ownerOnly
1542     *          If <code>true</code>, the execute permission applies only to the
1543     *          owner's execute permission; otherwise, it applies to everybody.
1544     *          If the underlying file system can not distinguish the owner's
1545     *          execute permission from that of others, then the permission will
1546     *          apply to everybody, regardless of this value.
1547     *
1548     * @return  <code>true</code> if and only if the operation succeeded.  The
1549     *          operation will fail if the user does not have permission to
1550     *          change the access permissions of this abstract pathname.  If
1551     *          <code>executable</code> is <code>false</code> and the underlying
1552     *          file system does not implement an execute permission, then the
1553     *          operation will fail.
1554     *
1555     * @throws  SecurityException
1556     *          If a security manager exists and its <code>{@link
1557     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1558     *          method denies write access to the file
1559     *
1560     * @since 1.6
1561     */
1562    public boolean setExecutable(boolean executable, boolean ownerOnly) {
1563        SecurityManager security = System.getSecurityManager();
1564        if (security != null) {
1565            security.checkWrite(path);
1566        }
1567        if (isInvalid()) {
1568            return false;
1569        }
1570        return fs.setPermission(this, FileSystem.ACCESS_EXECUTE, executable, ownerOnly);
1571    }
1572
1573    /**
1574     * A convenience method to set the owner's execute permission for this abstract
1575     * pathname.
1576     *
1577     * <p>An invocation of this method of the form <tt>file.setExcutable(arg)</tt>
1578     * behaves in exactly the same way as the invocation
1579     *
1580     * <pre>
1581     *     file.setExecutable(arg, true) </pre>
1582     *
1583     * @param   executable
1584     *          If <code>true</code>, sets the access permission to allow execute
1585     *          operations; if <code>false</code> to disallow execute operations
1586     *
1587     * @return   <code>true</code> if and only if the operation succeeded.  The
1588     *           operation will fail if the user does not have permission to
1589     *           change the access permissions of this abstract pathname.  If
1590     *           <code>executable</code> is <code>false</code> and the underlying
1591     *           file system does not implement an excute permission, then the
1592     *           operation will fail.
1593     *
1594     * @throws  SecurityException
1595     *          If a security manager exists and its <code>{@link
1596     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1597     *          method denies write access to the file
1598     *
1599     * @since 1.6
1600     */
1601    public boolean setExecutable(boolean executable) {
1602        return setExecutable(executable, true);
1603    }
1604
1605    /**
1606     * Tests whether the application can execute the file denoted by this
1607     * abstract pathname.
1608     *
1609     * @return  <code>true</code> if and only if the abstract pathname exists
1610     *          <em>and</em> the application is allowed to execute the file
1611     *
1612     * @throws  SecurityException
1613     *          If a security manager exists and its <code>{@link
1614     *          java.lang.SecurityManager#checkExec(java.lang.String)}</code>
1615     *          method denies execute access to the file
1616     *
1617     * @since 1.6
1618     */
1619    public boolean canExecute() {
1620        SecurityManager security = System.getSecurityManager();
1621        if (security != null) {
1622            security.checkExec(path);
1623        }
1624        if (isInvalid()) {
1625            return false;
1626        }
1627        return fs.checkAccess(this, FileSystem.ACCESS_EXECUTE);
1628    }
1629
1630
1631    /* -- Filesystem interface -- */
1632
1633
1634    /**
1635     * Returns the file system roots. On Android and other Unix systems, there is
1636     * a single root, {@code /}.
1637     */
1638    public static File[] listRoots() {
1639        return fs.listRoots();
1640    }
1641
1642
1643    /* -- Disk usage -- */
1644
1645    /**
1646     * Returns the size of the partition <a href="#partName">named</a> by this
1647     * abstract pathname.
1648     *
1649     * @return  The size, in bytes, of the partition or <tt>0L</tt> if this
1650     *          abstract pathname does not name a partition
1651     *
1652     * @throws  SecurityException
1653     *          If a security manager has been installed and it denies
1654     *          {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
1655     *          or its {@link SecurityManager#checkRead(String)} method denies
1656     *          read access to the file named by this abstract pathname
1657     *
1658     * @since  1.6
1659     */
1660    public long getTotalSpace() {
1661        SecurityManager sm = System.getSecurityManager();
1662        if (sm != null) {
1663            sm.checkPermission(new RuntimePermission("getFileSystemAttributes"));
1664            sm.checkRead(path);
1665        }
1666        if (isInvalid()) {
1667            return 0L;
1668        }
1669        return fs.getSpace(this, FileSystem.SPACE_TOTAL);
1670    }
1671
1672    /**
1673     * Returns the number of unallocated bytes in the partition <a
1674     * href="#partName">named</a> by this abstract path name.
1675     *
1676     * <p> The returned number of unallocated bytes is a hint, but not
1677     * a guarantee, that it is possible to use most or any of these
1678     * bytes.  The number of unallocated bytes is most likely to be
1679     * accurate immediately after this call.  It is likely to be made
1680     * inaccurate by any external I/O operations including those made
1681     * on the system outside of this virtual machine.  This method
1682     * makes no guarantee that write operations to this file system
1683     * will succeed.
1684     *
1685     * @return  The number of unallocated bytes on the partition or <tt>0L</tt>
1686     *          if the abstract pathname does not name a partition.  This
1687     *          value will be less than or equal to the total file system size
1688     *          returned by {@link #getTotalSpace}.
1689     *
1690     * @throws  SecurityException
1691     *          If a security manager has been installed and it denies
1692     *          {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
1693     *          or its {@link SecurityManager#checkRead(String)} method denies
1694     *          read access to the file named by this abstract pathname
1695     *
1696     * @since  1.6
1697     */
1698    public long getFreeSpace() {
1699        SecurityManager sm = System.getSecurityManager();
1700        if (sm != null) {
1701            sm.checkPermission(new RuntimePermission("getFileSystemAttributes"));
1702            sm.checkRead(path);
1703        }
1704        if (isInvalid()) {
1705            return 0L;
1706        }
1707        return fs.getSpace(this, FileSystem.SPACE_FREE);
1708    }
1709
1710    /**
1711     * Returns the number of bytes available to this virtual machine on the
1712     * partition <a href="#partName">named</a> by this abstract pathname.  When
1713     * possible, this method checks for write permissions and other operating
1714     * system restrictions and will therefore usually provide a more accurate
1715     * estimate of how much new data can actually be written than {@link
1716     * #getFreeSpace}.
1717     *
1718     * <p> The returned number of available bytes is a hint, but not a
1719     * guarantee, that it is possible to use most or any of these bytes.  The
1720     * number of unallocated bytes is most likely to be accurate immediately
1721     * after this call.  It is likely to be made inaccurate by any external
1722     * I/O operations including those made on the system outside of this
1723     * virtual machine.  This method makes no guarantee that write operations
1724     * to this file system will succeed.
1725     *
1726     * <p> On Android (and other Unix-based systems), this method returns the number of free bytes
1727     * available to non-root users, regardless of whether you're actually running as root,
1728     * and regardless of any quota or other restrictions that might apply to the user.
1729     * (The {@code getFreeSpace} method returns the number of bytes potentially available to root.)
1730     *
1731     * @return  The number of available bytes on the partition or <tt>0L</tt>
1732     *          if the abstract pathname does not name a partition.  On
1733     *          systems where this information is not available, this method
1734     *          will be equivalent to a call to {@link #getFreeSpace}.
1735     *
1736     * @throws  SecurityException
1737     *          If a security manager has been installed and it denies
1738     *          {@link RuntimePermission}<tt>("getFileSystemAttributes")</tt>
1739     *          or its {@link SecurityManager#checkRead(String)} method denies
1740     *          read access to the file named by this abstract pathname
1741     *
1742     * @since  1.6
1743     */
1744    public long getUsableSpace() {
1745        SecurityManager sm = System.getSecurityManager();
1746        if (sm != null) {
1747            sm.checkPermission(new RuntimePermission("getFileSystemAttributes"));
1748            sm.checkRead(path);
1749        }
1750        if (isInvalid()) {
1751            return 0L;
1752        }
1753        return fs.getSpace(this, FileSystem.SPACE_USABLE);
1754    }
1755
1756    /* -- Temporary files -- */
1757
1758    // file name generation
1759    private static File generateTempFile(String prefix, String suffix, File dir)
1760            throws IOException
1761    {
1762        // Android-changed: Use Math.randomIntInternal. This (pseudo) random number
1763        // is initialized post-fork
1764        int n = Math.randomIntInternal();
1765        if (n == Integer.MIN_VALUE) {
1766            n = 0;      // corner case
1767        } else {
1768            n = Math.abs(n);
1769        }
1770        String name = prefix + Integer.toString(n) + suffix;
1771        File f = new File(dir, name);
1772        if (!name.equals(f.getName()))
1773            throw new IOException("Unable to create temporary file");
1774        return f;
1775    }
1776
1777    /**
1778     * <p> Creates a new empty file in the specified directory, using the
1779     * given prefix and suffix strings to generate its name.  If this method
1780     * returns successfully then it is guaranteed that:
1781     *
1782     * <ol>
1783     * <li> The file denoted by the returned abstract pathname did not exist
1784     *      before this method was invoked, and
1785     * <li> Neither this method nor any of its variants will return the same
1786     *      abstract pathname again in the current invocation of the virtual
1787     *      machine.
1788     * </ol>
1789     *
1790     * This method provides only part of a temporary-file facility.  To arrange
1791     * for a file created by this method to be deleted automatically, use the
1792     * <code>{@link #deleteOnExit}</code> method.
1793     *
1794     * <p> The <code>prefix</code> argument must be at least three characters
1795     * long.  It is recommended that the prefix be a short, meaningful string
1796     * such as <code>"hjb"</code> or <code>"mail"</code>.  The
1797     * <code>suffix</code> argument may be <code>null</code>, in which case the
1798     * suffix <code>".tmp"</code> will be used.
1799     *
1800     * <p> To create the new file, the prefix and the suffix may first be
1801     * adjusted to fit the limitations of the underlying platform.  If the
1802     * prefix is too long then it will be truncated, but its first three
1803     * characters will always be preserved.  If the suffix is too long then it
1804     * too will be truncated, but if it begins with a period character
1805     * (<code>'.'</code>) then the period and the first three characters
1806     * following it will always be preserved.  Once these adjustments have been
1807     * made the name of the new file will be generated by concatenating the
1808     * prefix, five or more internally-generated characters, and the suffix.
1809     *
1810     * <p> If the <code>directory</code> argument is <code>null</code> then the
1811     * system-dependent default temporary-file directory will be used.  The
1812     * default temporary-file directory is specified by the system property
1813     * <code>java.io.tmpdir</code>.  On UNIX systems the default value of this
1814     * property is typically <code>"/tmp"</code> or <code>"/var/tmp"</code>; on
1815     * Microsoft Windows systems it is typically <code>"C:\\WINNT\\TEMP"</code>.  A different
1816     * value may be given to this system property when the Java virtual machine
1817     * is invoked, but programmatic changes to this property are not guaranteed
1818     * to have any effect upon the temporary directory used by this method.
1819     *
1820     * @param  prefix     The prefix string to be used in generating the file's
1821     *                    name; must be at least three characters long
1822     *
1823     * @param  suffix     The suffix string to be used in generating the file's
1824     *                    name; may be <code>null</code>, in which case the
1825     *                    suffix <code>".tmp"</code> will be used
1826     *
1827     * @param  directory  The directory in which the file is to be created, or
1828     *                    <code>null</code> if the default temporary-file
1829     *                    directory is to be used
1830     *
1831     * @return  An abstract pathname denoting a newly-created empty file
1832     *
1833     * @throws  IllegalArgumentException
1834     *          If the <code>prefix</code> argument contains fewer than three
1835     *          characters
1836     *
1837     * @throws  IOException  If a file could not be created
1838     *
1839     * @throws  SecurityException
1840     *          If a security manager exists and its <code>{@link
1841     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1842     *          method does not allow a file to be created
1843     *
1844     * @since 1.2
1845     */
1846    public static File createTempFile(String prefix, String suffix,
1847                                      File directory)
1848        throws IOException
1849    {
1850        if (prefix.length() < 3)
1851            throw new IllegalArgumentException("Prefix string too short");
1852        if (suffix == null)
1853            suffix = ".tmp";
1854
1855        File tmpdir = (directory != null) ? directory
1856                                          : new File(System.getProperty("java.io.tmpdir", "."));
1857        File f;
1858        try {
1859            do {
1860                f = generateTempFile(prefix, suffix, tmpdir);
1861            } while (f.exists());
1862            if (!f.createNewFile())
1863                throw new IOException("Unable to create temporary file");
1864        } catch (SecurityException se) {
1865            // don't reveal temporary directory location
1866            if (directory == null)
1867                throw new SecurityException("Unable to create temporary file");
1868            throw se;
1869        }
1870        return f;
1871    }
1872
1873    /**
1874     * Creates an empty file in the default temporary-file directory, using
1875     * the given prefix and suffix to generate its name. Invoking this method
1876     * is equivalent to invoking <code>{@link #createTempFile(java.lang.String,
1877     * java.lang.String, java.io.File)
1878     * createTempFile(prefix,&nbsp;suffix,&nbsp;null)}</code>.
1879     *
1880     * @param  prefix     The prefix string to be used in generating the file's
1881     *                    name; must be at least three characters long
1882     *
1883     * @param  suffix     The suffix string to be used in generating the file's
1884     *                    name; may be <code>null</code>, in which case the
1885     *                    suffix <code>".tmp"</code> will be used
1886     *
1887     * @return  An abstract pathname denoting a newly-created empty file
1888     *
1889     * @throws  IllegalArgumentException
1890     *          If the <code>prefix</code> argument contains fewer than three
1891     *          characters
1892     *
1893     * @throws  IOException  If a file could not be created
1894     *
1895     * @throws  SecurityException
1896     *          If a security manager exists and its <code>{@link
1897     *          java.lang.SecurityManager#checkWrite(java.lang.String)}</code>
1898     *          method does not allow a file to be created
1899     *
1900     * @since 1.2
1901     */
1902    public static File createTempFile(String prefix, String suffix)
1903        throws IOException
1904    {
1905        return createTempFile(prefix, suffix, null);
1906    }
1907
1908    /* -- Basic infrastructure -- */
1909
1910    /**
1911     * Compares two abstract pathnames lexicographically.  The ordering
1912     * defined by this method depends upon the underlying system.  On UNIX
1913     * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
1914     * systems it is not.
1915     *
1916     * @param   pathname  The abstract pathname to be compared to this abstract
1917     *                    pathname
1918     *
1919     * @return  Zero if the argument is equal to this abstract pathname, a
1920     *          value less than zero if this abstract pathname is
1921     *          lexicographically less than the argument, or a value greater
1922     *          than zero if this abstract pathname is lexicographically
1923     *          greater than the argument
1924     *
1925     * @since   1.2
1926     */
1927    public int compareTo(File pathname) {
1928        return fs.compare(this, pathname);
1929    }
1930
1931    /**
1932     * Tests this abstract pathname for equality with the given object.
1933     * Returns <code>true</code> if and only if the argument is not
1934     * <code>null</code> and is an abstract pathname that denotes the same file
1935     * or directory as this abstract pathname.  Whether or not two abstract
1936     * pathnames are equal depends upon the underlying system.  On UNIX
1937     * systems, alphabetic case is significant in comparing pathnames; on Microsoft Windows
1938     * systems it is not.
1939     *
1940     * @param   obj   The object to be compared with this abstract pathname
1941     *
1942     * @return  <code>true</code> if and only if the objects are the same;
1943     *          <code>false</code> otherwise
1944     */
1945    public boolean equals(Object obj) {
1946        if ((obj != null) && (obj instanceof File)) {
1947            return compareTo((File)obj) == 0;
1948        }
1949        return false;
1950    }
1951
1952    /**
1953     * Computes a hash code for this abstract pathname.  Because equality of
1954     * abstract pathnames is inherently system-dependent, so is the computation
1955     * of their hash codes.  On UNIX systems, the hash code of an abstract
1956     * pathname is equal to the exclusive <em>or</em> of the hash code
1957     * of its pathname string and the decimal value
1958     * <code>1234321</code>.  On Microsoft Windows systems, the hash
1959     * code is equal to the exclusive <em>or</em> of the hash code of
1960     * its pathname string converted to lower case and the decimal
1961     * value <code>1234321</code>.  Locale is not taken into account on
1962     * lowercasing the pathname string.
1963     *
1964     * @return  A hash code for this abstract pathname
1965     */
1966    public int hashCode() {
1967        return fs.hashCode(this);
1968    }
1969
1970    /**
1971     * Returns the pathname string of this abstract pathname.  This is just the
1972     * string returned by the <code>{@link #getPath}</code> method.
1973     *
1974     * @return  The string form of this abstract pathname
1975     */
1976    public String toString() {
1977        return getPath();
1978    }
1979
1980    /**
1981     * WriteObject is called to save this filename.
1982     * The separator character is saved also so it can be replaced
1983     * in case the path is reconstituted on a different host type.
1984     * <p>
1985     * @serialData  Default fields followed by separator character.
1986     */
1987    private synchronized void writeObject(java.io.ObjectOutputStream s)
1988        throws IOException
1989    {
1990        s.defaultWriteObject();
1991        s.writeChar(this.separatorChar); // Add the separator character
1992    }
1993
1994    /**
1995     * readObject is called to restore this filename.
1996     * The original separator character is read.  If it is different
1997     * than the separator character on this system, then the old separator
1998     * is replaced by the local separator.
1999     */
2000    private synchronized void readObject(java.io.ObjectInputStream s)
2001         throws IOException, ClassNotFoundException
2002    {
2003        ObjectInputStream.GetField fields = s.readFields();
2004        String pathField = (String)fields.get("path", null);
2005        char sep = s.readChar(); // read the previous separator char
2006        if (sep != separatorChar)
2007            pathField = pathField.replace(sep, separatorChar);
2008        this.path = fs.normalize(pathField);
2009        this.prefixLength = fs.prefixLength(this.path);
2010    }
2011
2012    /** use serialVersionUID from JDK 1.0.2 for interoperability */
2013    private static final long serialVersionUID = 301077366599181567L;
2014}
2015