From 581070715ab1ef081032b78ceb3c2cfbdbcff611 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 4 Sep 2025 21:58:08 +0000 Subject: [PATCH] 8366102: Clarification Needed: Symbolic Link Handling in File API Specifications Reviewed-by: alanb --- src/java.base/share/classes/java/io/File.java | 187 +++++++++--------- 1 file changed, 99 insertions(+), 88 deletions(-) diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index bb216366344..494dac7f51e 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -80,17 +80,22 @@ import jdk.internal.util.StaticProperty; * {@code user.dir}, and is typically the directory in which the Java * virtual machine was invoked. * - *

Unless otherwise noted, {@linkplain java.nio.file##links symbolic links} - * are automatically redirected to the target of the link, whether they - * are provided by a pathname string or via a {@code File} object. + *

Many operating systems and file systems have support for + * {@linkplain java.nio.file##links symbolic links}. + * A symbolic link is a special file that serves as a reference to another file. + * Unless otherwise specified, symbolic links are transparent to applications + * and operations on files that are symbolic links are automatically redirected + * to the target of the link. Methods that only operate on the abstract + * pathname do not access the file system and thus do not resolve symbolic + * links. * *

The parent of an abstract pathname may be obtained by invoking * the {@link #getParent} method of this class and consists of the pathname's * prefix and each name in the pathname's name sequence except for the last. * Each directory's absolute pathname is an ancestor of any {@code File} * object with an absolute abstract pathname which begins with the directory's - * absolute pathname. For example, the directory denoted by the abstract - * pathname {@code "/usr"} is an ancestor of the directory denoted by the + * absolute pathname. For example, the directory located by the abstract + * pathname {@code "/usr"} is an ancestor of the directory located by the * pathname {@code "/usr/local/bin"}. * *

The prefix concept is used to handle root directories on UNIX platforms, @@ -113,8 +118,8 @@ import jdk.internal.util.StaticProperty; * * * - *

Instances of this class may or may not denote an actual file-system - * object such as a file or a directory. If it does denote such an object + *

Instances of this class may or may not locate an actual file-system + * object such as a file or a directory. If it does locate such an object * then that object resides in a partition. A partition is an * operating system-specific portion of storage for a file system. A single * storage device (e.g. a physical disk-drive, flash memory, CD-ROM) may @@ -448,12 +453,12 @@ public class File /* -- Path-component accessors -- */ /** - * Returns the name of the file or directory denoted by this abstract + * Returns the name component of this abstract * pathname. This is just the last name in the pathname's name * sequence. If the pathname's name sequence is empty, then the empty * string is returned. * - * @return The name of the file or directory denoted by this abstract + * @return The name component of this abstract * pathname, or the empty string if this pathname's name sequence * is empty */ @@ -592,7 +597,7 @@ public class File * symbolic links, and converting drive letters to a standard case (on * Microsoft Windows platforms). * - *

Every pathname that denotes an existing file or directory has a + *

Every pathname that locates an existing file or directory has a * unique canonical form. Every pathname that denotes a nonexistent file * or directory also has a unique canonical form. The canonical form of * the pathname of a nonexistent file or directory may be different from @@ -601,7 +606,7 @@ public class File * file or directory may be different from the canonical form of the same * pathname after the file or directory is deleted. * - * @return The canonical pathname string denoting the same file or + * @return The canonical pathname string locating the same file or * directory as this abstract pathname * * @throws IOException @@ -623,7 +628,7 @@ public class File * Returns the canonical form of this abstract pathname. Equivalent to * new File(this.{@link #getCanonicalPath}). * - * @return The canonical pathname string denoting the same file or + * @return The canonical pathname string locating the same file or * directory as this abstract pathname * * @throws IOException @@ -656,7 +661,7 @@ public class File /** * Converts this abstract pathname into a {@code file:} URL. The * exact form of the URL is system-dependent. If it can be determined that - * the file denoted by this abstract pathname is a directory, then the + * the file located by this abstract pathname is a directory, then the * resulting URL will end with a slash. * * @return A URL object representing the equivalent file URL @@ -689,7 +694,7 @@ public class File * Constructs a {@code file:} URI that represents this abstract pathname. * *

The exact form of the URI is system-dependent. If it can be - * determined that the file denoted by this abstract pathname is a + * determined that the file located by this abstract pathname is a * directory, then the resulting URI will end with a slash. * *

For a given abstract pathname f, it is guaranteed that @@ -740,13 +745,13 @@ public class File /* -- Attribute accessors -- */ /** - * Tests whether the application can read the file denoted by this + * Tests whether the application can read the file located by this * abstract pathname. On some platforms it may be possible to start the * Java virtual machine with special privileges that allow it to read * files that are marked as unreadable. Consequently, this method may return * {@code true} even though the file does not have read permissions. * - * @return {@code true} if and only if the file specified by this + * @return {@code true} if and only if the file located by this * abstract pathname exists and can be read by the * application; {@code false} otherwise */ @@ -758,14 +763,14 @@ public class File } /** - * Tests whether the application can modify the file denoted by this + * Tests whether the application can modify the file located by this * abstract pathname. On some platforms it may be possible to start the * Java virtual machine with special privileges that allow it to modify * files that are marked read-only. Consequently, this method may return * {@code true} even though the file is marked read-only. * * @return {@code true} if and only if the file system actually - * contains a file denoted by this abstract pathname and + * contains a file located by this abstract pathname and * the application is allowed to write to the file; * {@code false} otherwise. */ @@ -777,10 +782,10 @@ public class File } /** - * Tests whether the file or directory denoted by this abstract pathname + * Tests whether the file or directory located by this abstract pathname * exists. * - * @return {@code true} if and only if the file or directory denoted + * @return {@code true} if and only if the file or directory located * by this abstract pathname exists; {@code false} otherwise */ public boolean exists() { @@ -791,7 +796,7 @@ public class File } /** - * Tests whether the file denoted by this abstract pathname is a + * Tests whether the file located by this abstract pathname is a * directory. * *

Where it is required to distinguish an I/O exception from the case @@ -800,7 +805,7 @@ public class File * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) * Files.readAttributes} method may be used. * - * @return {@code true} if and only if the file denoted by this + * @return {@code true} if and only if the file located by this * abstract pathname exists and is a directory; * {@code false} otherwise */ @@ -812,7 +817,7 @@ public class File } /** - * Tests whether the file denoted by this abstract pathname is a normal + * Tests whether the file located by this abstract pathname is a normal * file. A file is normal if it is not a directory and, in * addition, satisfies other system-dependent criteria. Any non-directory * file created by a Java application is guaranteed to be a normal file. @@ -823,7 +828,7 @@ public class File * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) * Files.readAttributes} method may be used. * - * @return {@code true} if and only if the file denoted by this + * @return {@code true} if and only if the file located by this * abstract pathname exists and is a normal file; * {@code false} otherwise */ @@ -835,7 +840,7 @@ public class File } /** - * Tests whether the file named by this abstract pathname is a hidden + * Tests whether the file located by this abstract pathname is a hidden * file. The exact definition of hidden is system-dependent. On * UNIX systems, a file is considered to be hidden if its name begins with * a period character ({@code '.'}). On Microsoft Windows systems, a file @@ -849,7 +854,7 @@ public class File * with a period character. On Windows systems, a symbolic link is * considered hidden if its target is so marked in the filesystem. * - * @return {@code true} if and only if the file denoted by this + * @return {@code true} if and only if the file located by this * abstract pathname is hidden according to the conventions of the * underlying platform * @@ -863,7 +868,7 @@ public class File } /** - * Returns the time that the file denoted by this abstract pathname was + * Returns the time that the file located by this abstract pathname was * last modified. * * @apiNote @@ -897,8 +902,8 @@ public class File } /** - * Returns the length of the file denoted by this abstract pathname. - * The return value is unspecified if this pathname denotes a directory. + * Returns the length of the file located by this abstract pathname. + * The return value is unspecified if this pathname locates a directory. * *

Where it is required to distinguish an I/O exception from the case * that {@code 0L} is returned, or where several attributes of the same file @@ -906,10 +911,10 @@ public class File * java.nio.file.Files#readAttributes(Path,Class,LinkOption[]) * Files.readAttributes} method may be used. * - * @return The length, in bytes, of the file denoted by this abstract + * @return The length, in bytes, of the file located by this abstract * pathname, or {@code 0L} if the file does not exist. Some * operating systems may return {@code 0L} for pathnames - * denoting system-dependent entities such as devices or pipes. + * locating system-dependent entities such as devices or pipes. */ public long length() { if (isInvalid()) { @@ -935,7 +940,7 @@ public class File * * @return {@code true} if the named file does not exist and was * successfully created; {@code false} if the named file - * already exists + * already exists, including if it is a symbolic link * * @throws IOException * If an I/O error occurred @@ -950,9 +955,9 @@ public class File } /** - * Deletes the file or directory denoted by this abstract pathname. If - * this pathname denotes a directory, then the directory must be empty in - * order to be deleted. If this pathname denotes a symbolic link, then the + * Deletes the file or directory located by this abstract pathname. If + * this pathname locates a directory, then the directory must be empty in + * order to be deleted. If this pathname locates a symbolic link, then the * link itself, not its target, will be deleted. * *

Note that the {@link java.nio.file.Files} class defines the {@link @@ -971,9 +976,9 @@ public class File } /** - * Requests that the file or directory denoted by this abstract + * Requests that the file or directory located by this abstract * pathname be deleted when the virtual machine terminates. - * If this pathname denotes a symbolic link, then the + * If this pathname locates a symbolic link, then the * link itself, not its target, will be deleted. * Files (or directories) are deleted in the reverse order that * they are registered. Invoking this method to delete a file or @@ -1003,12 +1008,12 @@ public class File /** * Returns an array of strings naming the files and directories in the - * directory denoted by this abstract pathname. + * directory located by this abstract pathname. * - *

If this abstract pathname does not denote a directory, then this + *

If this abstract pathname does not locate a directory, then this * method returns {@code null}. Otherwise an array of strings is * returned, one for each file or directory in the directory. Names - * denoting the directory itself and the directory's parent directory are + * locating the directory itself and the directory's parent directory are * not included in the result. Each string is a file name rather than a * complete path. * @@ -1023,9 +1028,9 @@ public class File * may be more responsive when working with remote directories. * * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The array will be + * directory located by this abstract pathname. The array will be * empty if the directory is empty. Returns {@code null} if - * this abstract pathname does not denote a directory, or if an + * this abstract pathname does not locate a directory, or if an * I/O error occurs. */ public String[] list() { @@ -1034,13 +1039,13 @@ public class File /** * Returns an array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The strings are + * directory located by this abstract pathname. The strings are * ensured to represent normalized paths. * * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The array will be + * directory located by this abstract pathname. The array will be * empty if the directory is empty. Returns {@code null} if - * this abstract pathname does not denote a directory, or if an + * this abstract pathname does not locate a directory, or if an * I/O error occurs. */ private final String[] normalizedList() { @@ -1060,7 +1065,7 @@ public class File /** * Returns an array of strings naming the files and directories in the - * directory denoted by this abstract pathname that satisfy the specified + * directory located by this abstract pathname that satisfy the specified * filter. The behavior of this method is the same as that of the * {@link #list()} method, except that the strings in the returned array * must satisfy the filter. If the given {@code filter} is {@code null} @@ -1068,16 +1073,16 @@ public class File * and only if the value {@code true} results when the {@link * FilenameFilter#accept FilenameFilter.accept(File, String)} method * of the filter is invoked on this abstract pathname and the name of a - * file or directory in the directory that it denotes. + * file or directory in the directory that it locates. * * @param filter * A filename filter * * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname that were accepted + * directory located by this abstract pathname that were accepted * by the given {@code filter}. The array will be empty if the * directory is empty or if no names were accepted by the filter. - * Returns {@code null} if this abstract pathname does not denote + * Returns {@code null} if this abstract pathname does not locate * a directory, or if an I/O error occurs. * * @see java.nio.file.Files#newDirectoryStream(Path,String) @@ -1097,13 +1102,13 @@ public class File } /** - * Returns an array of abstract pathnames denoting the files in the - * directory denoted by this abstract pathname. + * Returns an array of abstract pathnames locating the files in the + * directory located by this abstract pathname. * - *

If this abstract pathname does not denote a directory, then this + *

If this abstract pathname does not locate a directory, then this * method returns {@code null}. Otherwise an array of {@code File} objects * is returned, one for each file or directory in the directory. Pathnames - * denoting the directory itself and the directory's parent directory are + * locating the directory itself and the directory's parent directory are * not included in the result. Each resulting abstract pathname is * constructed from this abstract pathname using the {@link #File(File, * String) File(File, String)} constructor. Therefore if this @@ -1121,10 +1126,10 @@ public class File * directory. This may use less resources when working with very large * directories. * - * @return An array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname. + * @return An array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname. * The array will be empty if the directory is empty. Returns - * {@code null} if this abstract pathname does not denote a + * {@code null} if this abstract pathname does not locate a * directory, or if an I/O error occurs. * * @since 1.2 @@ -1141,8 +1146,8 @@ public class File } /** - * Returns an array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname that + * Returns an array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname that * satisfy the specified filter. The behavior of this method is the same * as that of the {@link #listFiles()} method, except that the pathnames in * the returned array must satisfy the filter. If the given {@code filter} @@ -1151,15 +1156,15 @@ public class File * the {@link FilenameFilter#accept * FilenameFilter.accept(File, String)} method of the filter is * invoked on this abstract pathname and the name of a file or directory in - * the directory that it denotes. + * the directory that it locates. * * @param filter * A filename filter * - * @return An array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname. + * @return An array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname. * The array will be empty if the directory is empty. Returns - * {@code null} if this abstract pathname does not denote a + * {@code null} if this abstract pathname does not locate a * directory, or if an I/O error occurs. * * @since 1.2 @@ -1177,8 +1182,8 @@ public class File } /** - * Returns an array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname that + * Returns an array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname that * satisfy the specified filter. The behavior of this method is the same * as that of the {@link #listFiles()} method, except that the pathnames in * the returned array must satisfy the filter. If the given {@code filter} @@ -1190,10 +1195,10 @@ public class File * @param filter * A file filter * - * @return An array of abstract pathnames denoting the files and - * directories in the directory denoted by this abstract pathname. + * @return An array of abstract pathnames locating the files and + * directories in the directory located by this abstract pathname. * The array will be empty if the directory is empty. Returns - * {@code null} if this abstract pathname does not denote a + * {@code null} if this abstract pathname does not locate a * directory, or if an I/O error occurs. * * @since 1.2 @@ -1255,8 +1260,8 @@ public class File } /** - * Renames the file denoted by this abstract pathname. If this pathname - * denotes a symbolic link, then the link itself, not its target, will be + * Renames the file located by this abstract pathname. If this pathname + * locates a symbolic link, then the link itself, not its target, will be * renamed. * *

Many aspects of the behavior of this method are inherently @@ -1291,7 +1296,7 @@ public class File } /** - * Sets the last-modified time of the file or directory named by this + * Sets the last-modified time of the file or directory located by this * abstract pathname. * *

All platforms support file-modification times to the nearest second, @@ -1320,7 +1325,7 @@ public class File } /** - * Marks the file or directory named by this abstract pathname so that + * Marks the file or directory located by this abstract pathname so that * only read operations are allowed. After invoking this method the file * or directory will not change until it is either deleted or marked * to allow write access. On some platforms it may be possible to start the @@ -1341,7 +1346,8 @@ public class File } /** - * Sets the owner's or everybody's write permission for this abstract + * Sets the owner's or everybody's write permission of the file or + * directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to modify files that * disallow write operations. @@ -1375,7 +1381,8 @@ public class File } /** - * A convenience method to set the owner's write permission for this abstract + * A convenience method to set the owner's write permission for the file + * or directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to modify files that * disallow write operations. @@ -1402,7 +1409,8 @@ public class File } /** - * Sets the owner's or everybody's read permission for this abstract + * Sets the owner's or everybody's read permission for the file or directory + * located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to read files that are * marked as unreadable. @@ -1442,7 +1450,8 @@ public class File } /** - * A convenience method to set the owner's read permission for this abstract + * A convenience method to set the owner's read permission for the file + * or directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to read files that are * marked as unreadable. @@ -1475,7 +1484,8 @@ public class File } /** - * Sets the owner's or everybody's execute permission for this abstract + * Sets the owner's or everybody's execute permission for the file or + * directory located by this abstract * pathname. On some platforms it may be possible to start the Java virtual * machine with special privileges that allow it to execute files that are * not marked executable. @@ -1515,7 +1525,8 @@ public class File } /** - * A convenience method to set the owner's execute permission for this + * A convenience method to set the owner's execute permission for the file + * or directory located by this * abstract pathname. On some platforms it may be possible to start the Java * virtual machine with special privileges that allow it to execute files * that are not marked executable. @@ -1548,7 +1559,7 @@ public class File } /** - * Tests whether the application can execute the file denoted by this + * Tests whether the application can execute the file located by this * abstract pathname. On some platforms it may be possible to start the * Java virtual machine with special privileges that allow it to execute * files that are not marked executable. Consequently, this method may return @@ -1794,7 +1805,7 @@ public class File * returns successfully then it is guaranteed that: * *

    - *
  1. The file denoted by the returned abstract pathname did not exist + *
  2. The file located by the returned abstract pathname did not exist * before this method was invoked, and *
  3. Neither this method nor any of its variants will return the same * abstract pathname again in the current invocation of the virtual @@ -1837,7 +1848,7 @@ public class File * to have any effect upon the temporary directory used by this method. * *

    If the {@code directory} argument is not {@code null} and its - * abstract pathname is valid and denotes an existing, writable directory, + * abstract pathname is valid and locates an existing, writable directory, * then the file will be created in that directory. Otherwise the file will * not be created and an {@code IOException} will be thrown. Under no * circumstances will a directory be created at the location specified by @@ -1854,7 +1865,7 @@ public class File * {@code null} if the default temporary-file * directory is to be used * - * @return An abstract pathname denoting a newly-created empty file + * @return An abstract pathname locating a newly-created empty file * * @throws IllegalArgumentException * If the {@code prefix} argument contains fewer than three @@ -1911,7 +1922,7 @@ public class File * name; may be {@code null}, in which case the * suffix {@code ".tmp"} will be used * - * @return An abstract pathname denoting a newly-created empty file + * @return An abstract pathname locating a newly-created empty file * * @throws IllegalArgumentException * If the {@code prefix} argument contains fewer than three @@ -1934,7 +1945,9 @@ public class File * Compares two abstract pathnames lexicographically. The ordering * defined by this method depends upon the underlying system. On UNIX * systems, alphabetic case is significant in comparing pathnames; on - * Microsoft Windows systems it is not. + * Microsoft Windows systems it is not. This method only compares the + * abstract pathnames; it does not access the file system and the file is + * not required to exist. * * @param pathname The abstract pathname to be compared to this abstract * pathname @@ -1958,11 +1971,9 @@ public class File * abstract pathname. Whether or not two abstract * pathnames are equal depends upon the underlying operating system. * On UNIX systems, alphabetic case is significant in comparing pathnames; - * on Microsoft Windows systems it is not. - * - * @apiNote This method only tests whether the abstract pathnames are equal; - * it does not access the file system and the file is not required - * to exist. + * on Microsoft Windows systems it is not. This method only tests whether + * the abstract pathnames are equal; it does not access the file system and + * the file is not required to exist. * * @param obj The object to be compared with this abstract pathname *