Skip to content

Commit d48694d

Browse files
author
Lance Andersen
committed
8283335: Add exists and readAttributesIfExists methods to FileSystemProvider
Reviewed-by: alanb
1 parent c45d613 commit d48694d

File tree

13 files changed

+577
-175
lines changed

13 files changed

+577
-175
lines changed

src/java.base/share/classes/java/nio/file/Files.java

+9-38
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
import jdk.internal.util.ArraysSupport;
8181
import sun.nio.ch.FileChannelImpl;
8282
import sun.nio.cs.UTF_8;
83-
import sun.nio.fs.AbstractFileSystemProvider;
8483

8584
/**
8685
* This class consists exclusively of static methods that operate on files,
@@ -1594,7 +1593,7 @@ public static long mismatch(Path path, Path path2) throws IOException {
15941593
byte[] buffer1 = new byte[BUFFER_SIZE];
15951594
byte[] buffer2 = new byte[BUFFER_SIZE];
15961595
try (InputStream in1 = Files.newInputStream(path);
1597-
InputStream in2 = Files.newInputStream(path2);) {
1596+
InputStream in2 = Files.newInputStream(path2)) {
15981597
long totalRead = 0;
15991598
while (true) {
16001599
int nRead1 = in1.readNBytes(buffer1, 0, BUFFER_SIZE);
@@ -2310,14 +2309,10 @@ public static boolean isSymbolicLink(Path path) {
23102309
* method denies read access to the file.
23112310
*/
23122311
public static boolean isDirectory(Path path, LinkOption... options) {
2313-
if (options.length == 0) {
2314-
FileSystemProvider provider = provider(path);
2315-
if (provider instanceof AbstractFileSystemProvider)
2316-
return ((AbstractFileSystemProvider)provider).isDirectory(path);
2317-
}
2318-
23192312
try {
2320-
return readAttributes(path, BasicFileAttributes.class, options).isDirectory();
2313+
var attrs = provider(path)
2314+
.readAttributesIfExists(path, BasicFileAttributes.class, options);
2315+
return (attrs != null) && attrs.isDirectory();
23212316
} catch (IOException ioe) {
23222317
return false;
23232318
}
@@ -2353,14 +2348,10 @@ public static boolean isDirectory(Path path, LinkOption... options) {
23532348
* method denies read access to the file.
23542349
*/
23552350
public static boolean isRegularFile(Path path, LinkOption... options) {
2356-
if (options.length == 0) {
2357-
FileSystemProvider provider = provider(path);
2358-
if (provider instanceof AbstractFileSystemProvider)
2359-
return ((AbstractFileSystemProvider)provider).isRegularFile(path);
2360-
}
2361-
23622351
try {
2363-
return readAttributes(path, BasicFileAttributes.class, options).isRegularFile();
2352+
var attrs = provider(path)
2353+
.readAttributesIfExists(path, BasicFileAttributes.class, options);
2354+
return (attrs != null) && attrs.isRegularFile();
23642355
} catch (IOException ioe) {
23652356
return false;
23662357
}
@@ -2502,7 +2493,7 @@ private static boolean followLinks(LinkOption... options) {
25022493
* the path to the file to test
25032494
* @param options
25042495
* options indicating how symbolic links are handled
2505-
* .
2496+
*
25062497
* @return {@code true} if the file exists; {@code false} if the file does
25072498
* not exist or its existence cannot be determined.
25082499
*
@@ -2515,27 +2506,7 @@ private static boolean followLinks(LinkOption... options) {
25152506
* @see FileSystemProvider#checkAccess
25162507
*/
25172508
public static boolean exists(Path path, LinkOption... options) {
2518-
if (options.length == 0) {
2519-
FileSystemProvider provider = provider(path);
2520-
if (provider instanceof AbstractFileSystemProvider)
2521-
return ((AbstractFileSystemProvider)provider).exists(path);
2522-
}
2523-
2524-
try {
2525-
if (followLinks(options)) {
2526-
provider(path).checkAccess(path);
2527-
} else {
2528-
// attempt to read attributes without following links
2529-
readAttributes(path, BasicFileAttributes.class,
2530-
LinkOption.NOFOLLOW_LINKS);
2531-
}
2532-
// file exists
2533-
return true;
2534-
} catch (IOException x) {
2535-
// does not exist or unable to determine if file exists
2536-
return false;
2537-
}
2538-
2509+
return provider(path).exists(path, options);
25392510
}
25402511

25412512
/**

src/java.base/share/classes/java/nio/file/spi/FileSystemProvider.java

+119-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1170,4 +1170,122 @@ public abstract Map<String,Object> readAttributes(Path path, String attributes,
11701170
public abstract void setAttribute(Path path, String attribute,
11711171
Object value, LinkOption... options)
11721172
throws IOException;
1173+
1174+
/**
1175+
* Tests whether a file exists. This method works in exactly the
1176+
* manner specified by the {@link Files#exists(Path, LinkOption...)} method.
1177+
*
1178+
* @implSpec
1179+
* The default implementation of this method invokes the
1180+
* {@link #checkAccess(Path, AccessMode...)} method when symbolic links
1181+
* are followed. If the option {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS}
1182+
* is present then symbolic links are not followed and the method
1183+
* {@link #readAttributes(Path, Class, LinkOption...)} is called
1184+
* to determine whether a file exists.
1185+
*
1186+
* @param path
1187+
* the path to the file to test
1188+
* @param options
1189+
* options indicating how symbolic links are handled
1190+
*
1191+
* @return {@code true} if the file exists; {@code false} if the file does
1192+
* not exist or its existence cannot be determined.
1193+
*
1194+
* @throws SecurityException
1195+
* In the case of the default provider, the {@link
1196+
* SecurityManager#checkRead(String)} is invoked to check
1197+
* read access to the file.
1198+
*
1199+
* @since 20
1200+
*/
1201+
public boolean exists(Path path, LinkOption... options) {
1202+
try {
1203+
if (followLinks(options)) {
1204+
this.checkAccess(path);
1205+
} else {
1206+
// attempt to read attributes without following links
1207+
readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
1208+
}
1209+
// file exists
1210+
return true;
1211+
} catch (IOException x) {
1212+
// does not exist or unable to determine if file exists
1213+
return false;
1214+
}
1215+
}
1216+
1217+
/**
1218+
* Reads a file's attributes as a bulk operation if it exists.
1219+
*
1220+
* <p> The {@code type} parameter is the type of the attributes required
1221+
* and this method returns an instance of that type if supported. All
1222+
* implementations support a basic set of file attributes and so invoking
1223+
* this method with a {@code type} parameter of {@code
1224+
* BasicFileAttributes.class} will not throw {@code
1225+
* UnsupportedOperationException}.
1226+
*
1227+
* <p> The {@code options} array may be used to indicate how symbolic links
1228+
* are handled for the case that the file is a symbolic link. By default,
1229+
* symbolic links are followed and the file attribute of the final target
1230+
* of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
1231+
* NOFOLLOW_LINKS} is present then symbolic links are not followed.
1232+
*
1233+
* <p> It is implementation specific if all file attributes are read as an
1234+
* atomic operation with respect to other file system operations.
1235+
*
1236+
* @implSpec
1237+
* The default implementation of this method invokes the
1238+
* {@link #readAttributes(Path, Class, LinkOption...)} method
1239+
* to read the file's attributes.
1240+
*
1241+
* @param <A>
1242+
* The {@code BasicFileAttributes} type
1243+
* @param path
1244+
* the path to the file
1245+
* @param type
1246+
* the {@code Class} of the file attributes required
1247+
* to read
1248+
* @param options
1249+
* options indicating how symbolic links are handled
1250+
*
1251+
* @return the file attributes or null if the file does not exist
1252+
*
1253+
* @throws UnsupportedOperationException
1254+
* if an attributes of the given type are not supported
1255+
* @throws IOException
1256+
* if an I/O error occurs
1257+
* @throws SecurityException
1258+
* In the case of the default provider, a security manager is
1259+
* installed, its {@link SecurityManager#checkRead(String) checkRead}
1260+
* method is invoked to check read access to the file. If this
1261+
* method is invoked to read security sensitive attributes then the
1262+
* security manager may be invoked to check for additional permissions.
1263+
*
1264+
* @since 20
1265+
*/
1266+
public <A extends BasicFileAttributes> A readAttributesIfExists(Path path,
1267+
Class<A> type,
1268+
LinkOption... options)
1269+
throws IOException
1270+
{
1271+
try {
1272+
return readAttributes(path, type, options);
1273+
} catch (NoSuchFileException ignore) {
1274+
return null;
1275+
}
1276+
}
1277+
1278+
private static boolean followLinks(LinkOption... options) {
1279+
boolean followLinks = true;
1280+
for (LinkOption opt: options) {
1281+
if (opt == LinkOption.NOFOLLOW_LINKS) {
1282+
followLinks = false;
1283+
continue;
1284+
}
1285+
if (opt == null)
1286+
throw new NullPointerException();
1287+
throw new AssertionError("Should not get here");
1288+
}
1289+
return followLinks;
1290+
}
11731291
}

src/java.base/share/classes/sun/nio/fs/AbstractFileSystemProvider.java

+1-47
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@
2727

2828
import java.nio.file.Path;
2929
import java.nio.file.LinkOption;
30-
import java.nio.file.attribute.BasicFileAttributes;
3130
import java.nio.file.spi.FileSystemProvider;
3231
import java.io.IOException;
3332
import java.util.Map;
@@ -110,51 +109,6 @@ public final boolean deleteIfExists(Path file) throws IOException {
110109
return implDelete(file, false);
111110
}
112111

113-
/**
114-
* Tests whether a file is a directory.
115-
*
116-
* @return {@code true} if the file is a directory; {@code false} if
117-
* the file does not exist, is not a directory, or it cannot
118-
* be determined if the file is a directory or not.
119-
*/
120-
public boolean isDirectory(Path file) {
121-
try {
122-
return readAttributes(file, BasicFileAttributes.class).isDirectory();
123-
} catch (IOException ioe) {
124-
return false;
125-
}
126-
}
127-
128-
/**
129-
* Tests whether a file is a regular file with opaque content.
130-
*
131-
* @return {@code true} if the file is a regular file; {@code false} if
132-
* the file does not exist, is not a regular file, or it
133-
* cannot be determined if the file is a regular file or not.
134-
*/
135-
public boolean isRegularFile(Path file) {
136-
try {
137-
return readAttributes(file, BasicFileAttributes.class).isRegularFile();
138-
} catch (IOException ioe) {
139-
return false;
140-
}
141-
}
142-
143-
/**
144-
* Checks the existence of a file.
145-
*
146-
* @return {@code true} if the file exists; {@code false} if the file does
147-
* not exist or its existence cannot be determined.
148-
*/
149-
public boolean exists(Path file) {
150-
try {
151-
checkAccess(file);
152-
return true;
153-
} catch (IOException ioe) {
154-
return false;
155-
}
156-
}
157-
158112
/**
159113
* Returns a path name as bytes for a Unix domain socket.
160114
* Different encodings may be used for these names on some platforms.

src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -74,6 +74,19 @@ static UnixFileAttributes get(UnixPath path, boolean followLinks)
7474
return attrs;
7575
}
7676

77+
// get the UnixFileAttributes for a given file. Returns null if the file does not exist.
78+
static UnixFileAttributes getIfExists(UnixPath path) throws UnixException {
79+
UnixFileAttributes attrs = new UnixFileAttributes();
80+
int errno = UnixNativeDispatcher.stat2(path, attrs);
81+
if (errno == 0) {
82+
return attrs;
83+
} else if (errno == UnixConstants.ENOENT) {
84+
return null;
85+
} else {
86+
throw new UnixException(errno);
87+
}
88+
}
89+
7790
// get the UnixFileAttributes for an open file
7891
static UnixFileAttributes get(int fd) throws UnixException {
7992
UnixFileAttributes attrs = new UnixFileAttributes();
@@ -251,16 +264,6 @@ BasicFileAttributes asBasicFileAttributes() {
251264
return UnixAsBasicFileAttributes.wrap(this);
252265
}
253266

254-
// unwrap BasicFileAttributes to get the underlying UnixFileAttributes
255-
// object. Returns null is not wrapped.
256-
static UnixFileAttributes toUnixFileAttributes(BasicFileAttributes attrs) {
257-
if (attrs instanceof UnixFileAttributes)
258-
return (UnixFileAttributes)attrs;
259-
if (attrs instanceof UnixAsBasicFileAttributes) {
260-
return ((UnixAsBasicFileAttributes)attrs).unwrap();
261-
}
262-
return null;
263-
}
264267

265268
// wrap a UnixFileAttributes object as a BasicFileAttributes
266269
private static class UnixAsBasicFileAttributes implements BasicFileAttributes {
@@ -274,9 +277,6 @@ static UnixAsBasicFileAttributes wrap(UnixFileAttributes attrs) {
274277
return new UnixAsBasicFileAttributes(attrs);
275278
}
276279

277-
UnixFileAttributes unwrap() {
278-
return attrs;
279-
}
280280

281281
@Override
282282
public FileTime lastModifiedTime() {

0 commit comments

Comments
 (0)