8283335: Add exists and readAttributesIfExists methods to FileSystemProvider
Reviewed-by: alanb
This commit is contained in:
parent
c45d613faa
commit
d48694d0f3
@ -80,7 +80,6 @@ import java.util.stream.StreamSupport;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import sun.nio.ch.FileChannelImpl;
|
||||
import sun.nio.cs.UTF_8;
|
||||
import sun.nio.fs.AbstractFileSystemProvider;
|
||||
|
||||
/**
|
||||
* This class consists exclusively of static methods that operate on files,
|
||||
@ -1594,7 +1593,7 @@ public final class Files {
|
||||
byte[] buffer1 = new byte[BUFFER_SIZE];
|
||||
byte[] buffer2 = new byte[BUFFER_SIZE];
|
||||
try (InputStream in1 = Files.newInputStream(path);
|
||||
InputStream in2 = Files.newInputStream(path2);) {
|
||||
InputStream in2 = Files.newInputStream(path2)) {
|
||||
long totalRead = 0;
|
||||
while (true) {
|
||||
int nRead1 = in1.readNBytes(buffer1, 0, BUFFER_SIZE);
|
||||
@ -2310,14 +2309,10 @@ public final class Files {
|
||||
* method denies read access to the file.
|
||||
*/
|
||||
public static boolean isDirectory(Path path, LinkOption... options) {
|
||||
if (options.length == 0) {
|
||||
FileSystemProvider provider = provider(path);
|
||||
if (provider instanceof AbstractFileSystemProvider)
|
||||
return ((AbstractFileSystemProvider)provider).isDirectory(path);
|
||||
}
|
||||
|
||||
try {
|
||||
return readAttributes(path, BasicFileAttributes.class, options).isDirectory();
|
||||
var attrs = provider(path)
|
||||
.readAttributesIfExists(path, BasicFileAttributes.class, options);
|
||||
return (attrs != null) && attrs.isDirectory();
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
@ -2353,14 +2348,10 @@ public final class Files {
|
||||
* method denies read access to the file.
|
||||
*/
|
||||
public static boolean isRegularFile(Path path, LinkOption... options) {
|
||||
if (options.length == 0) {
|
||||
FileSystemProvider provider = provider(path);
|
||||
if (provider instanceof AbstractFileSystemProvider)
|
||||
return ((AbstractFileSystemProvider)provider).isRegularFile(path);
|
||||
}
|
||||
|
||||
try {
|
||||
return readAttributes(path, BasicFileAttributes.class, options).isRegularFile();
|
||||
var attrs = provider(path)
|
||||
.readAttributesIfExists(path, BasicFileAttributes.class, options);
|
||||
return (attrs != null) && attrs.isRegularFile();
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
@ -2502,7 +2493,7 @@ public final class Files {
|
||||
* the path to the file to test
|
||||
* @param options
|
||||
* options indicating how symbolic links are handled
|
||||
* .
|
||||
*
|
||||
* @return {@code true} if the file exists; {@code false} if the file does
|
||||
* not exist or its existence cannot be determined.
|
||||
*
|
||||
@ -2515,27 +2506,7 @@ public final class Files {
|
||||
* @see FileSystemProvider#checkAccess
|
||||
*/
|
||||
public static boolean exists(Path path, LinkOption... options) {
|
||||
if (options.length == 0) {
|
||||
FileSystemProvider provider = provider(path);
|
||||
if (provider instanceof AbstractFileSystemProvider)
|
||||
return ((AbstractFileSystemProvider)provider).exists(path);
|
||||
}
|
||||
|
||||
try {
|
||||
if (followLinks(options)) {
|
||||
provider(path).checkAccess(path);
|
||||
} else {
|
||||
// attempt to read attributes without following links
|
||||
readAttributes(path, BasicFileAttributes.class,
|
||||
LinkOption.NOFOLLOW_LINKS);
|
||||
}
|
||||
// file exists
|
||||
return true;
|
||||
} catch (IOException x) {
|
||||
// does not exist or unable to determine if file exists
|
||||
return false;
|
||||
}
|
||||
|
||||
return provider(path).exists(path, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1170,4 +1170,122 @@ public abstract class FileSystemProvider {
|
||||
public abstract void setAttribute(Path path, String attribute,
|
||||
Object value, LinkOption... options)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Tests whether a file exists. This method works in exactly the
|
||||
* manner specified by the {@link Files#exists(Path, LinkOption...)} method.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation of this method invokes the
|
||||
* {@link #checkAccess(Path, AccessMode...)} method when symbolic links
|
||||
* are followed. If the option {@link LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS}
|
||||
* is present then symbolic links are not followed and the method
|
||||
* {@link #readAttributes(Path, Class, LinkOption...)} is called
|
||||
* to determine whether a file exists.
|
||||
*
|
||||
* @param path
|
||||
* the path to the file to test
|
||||
* @param options
|
||||
* options indicating how symbolic links are handled
|
||||
*
|
||||
* @return {@code true} if the file exists; {@code false} if the file does
|
||||
* not exist or its existence cannot be determined.
|
||||
*
|
||||
* @throws SecurityException
|
||||
* In the case of the default provider, the {@link
|
||||
* SecurityManager#checkRead(String)} is invoked to check
|
||||
* read access to the file.
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
public boolean exists(Path path, LinkOption... options) {
|
||||
try {
|
||||
if (followLinks(options)) {
|
||||
this.checkAccess(path);
|
||||
} else {
|
||||
// attempt to read attributes without following links
|
||||
readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
|
||||
}
|
||||
// file exists
|
||||
return true;
|
||||
} catch (IOException x) {
|
||||
// does not exist or unable to determine if file exists
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a file's attributes as a bulk operation if it exists.
|
||||
*
|
||||
* <p> The {@code type} parameter is the type of the attributes required
|
||||
* and this method returns an instance of that type if supported. All
|
||||
* implementations support a basic set of file attributes and so invoking
|
||||
* this method with a {@code type} parameter of {@code
|
||||
* BasicFileAttributes.class} will not throw {@code
|
||||
* UnsupportedOperationException}.
|
||||
*
|
||||
* <p> The {@code options} array may be used to indicate how symbolic links
|
||||
* are handled for the case that the file is a symbolic link. By default,
|
||||
* symbolic links are followed and the file attribute of the final target
|
||||
* of the link is read. If the option {@link LinkOption#NOFOLLOW_LINKS
|
||||
* NOFOLLOW_LINKS} is present then symbolic links are not followed.
|
||||
*
|
||||
* <p> It is implementation specific if all file attributes are read as an
|
||||
* atomic operation with respect to other file system operations.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation of this method invokes the
|
||||
* {@link #readAttributes(Path, Class, LinkOption...)} method
|
||||
* to read the file's attributes.
|
||||
*
|
||||
* @param <A>
|
||||
* The {@code BasicFileAttributes} type
|
||||
* @param path
|
||||
* the path to the file
|
||||
* @param type
|
||||
* the {@code Class} of the file attributes required
|
||||
* to read
|
||||
* @param options
|
||||
* options indicating how symbolic links are handled
|
||||
*
|
||||
* @return the file attributes or null if the file does not exist
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* if an attributes of the given type are not supported
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
* @throws SecurityException
|
||||
* In the case of the default provider, a security manager is
|
||||
* installed, its {@link SecurityManager#checkRead(String) checkRead}
|
||||
* method is invoked to check read access to the file. If this
|
||||
* method is invoked to read security sensitive attributes then the
|
||||
* security manager may be invoked to check for additional permissions.
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
public <A extends BasicFileAttributes> A readAttributesIfExists(Path path,
|
||||
Class<A> type,
|
||||
LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
try {
|
||||
return readAttributes(path, type, options);
|
||||
} catch (NoSuchFileException ignore) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean followLinks(LinkOption... options) {
|
||||
boolean followLinks = true;
|
||||
for (LinkOption opt: options) {
|
||||
if (opt == LinkOption.NOFOLLOW_LINKS) {
|
||||
followLinks = false;
|
||||
continue;
|
||||
}
|
||||
if (opt == null)
|
||||
throw new NullPointerException();
|
||||
throw new AssertionError("Should not get here");
|
||||
}
|
||||
return followLinks;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,7 +27,6 @@ package sun.nio.fs;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.spi.FileSystemProvider;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
@ -110,51 +109,6 @@ public abstract class AbstractFileSystemProvider extends FileSystemProvider {
|
||||
return implDelete(file, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a file is a directory.
|
||||
*
|
||||
* @return {@code true} if the file is a directory; {@code false} if
|
||||
* the file does not exist, is not a directory, or it cannot
|
||||
* be determined if the file is a directory or not.
|
||||
*/
|
||||
public boolean isDirectory(Path file) {
|
||||
try {
|
||||
return readAttributes(file, BasicFileAttributes.class).isDirectory();
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a file is a regular file with opaque content.
|
||||
*
|
||||
* @return {@code true} if the file is a regular file; {@code false} if
|
||||
* the file does not exist, is not a regular file, or it
|
||||
* cannot be determined if the file is a regular file or not.
|
||||
*/
|
||||
public boolean isRegularFile(Path file) {
|
||||
try {
|
||||
return readAttributes(file, BasicFileAttributes.class).isRegularFile();
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the existence of a file.
|
||||
*
|
||||
* @return {@code true} if the file exists; {@code false} if the file does
|
||||
* not exist or its existence cannot be determined.
|
||||
*/
|
||||
public boolean exists(Path file) {
|
||||
try {
|
||||
checkAccess(file);
|
||||
return true;
|
||||
} catch (IOException ioe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a path name as bytes for a Unix domain socket.
|
||||
* Different encodings may be used for these names on some platforms.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -74,6 +74,19 @@ class UnixFileAttributes
|
||||
return attrs;
|
||||
}
|
||||
|
||||
// get the UnixFileAttributes for a given file. Returns null if the file does not exist.
|
||||
static UnixFileAttributes getIfExists(UnixPath path) throws UnixException {
|
||||
UnixFileAttributes attrs = new UnixFileAttributes();
|
||||
int errno = UnixNativeDispatcher.stat2(path, attrs);
|
||||
if (errno == 0) {
|
||||
return attrs;
|
||||
} else if (errno == UnixConstants.ENOENT) {
|
||||
return null;
|
||||
} else {
|
||||
throw new UnixException(errno);
|
||||
}
|
||||
}
|
||||
|
||||
// get the UnixFileAttributes for an open file
|
||||
static UnixFileAttributes get(int fd) throws UnixException {
|
||||
UnixFileAttributes attrs = new UnixFileAttributes();
|
||||
@ -251,16 +264,6 @@ class UnixFileAttributes
|
||||
return UnixAsBasicFileAttributes.wrap(this);
|
||||
}
|
||||
|
||||
// unwrap BasicFileAttributes to get the underlying UnixFileAttributes
|
||||
// object. Returns null is not wrapped.
|
||||
static UnixFileAttributes toUnixFileAttributes(BasicFileAttributes attrs) {
|
||||
if (attrs instanceof UnixFileAttributes)
|
||||
return (UnixFileAttributes)attrs;
|
||||
if (attrs instanceof UnixAsBasicFileAttributes) {
|
||||
return ((UnixAsBasicFileAttributes)attrs).unwrap();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// wrap a UnixFileAttributes object as a BasicFileAttributes
|
||||
private static class UnixAsBasicFileAttributes implements BasicFileAttributes {
|
||||
@ -274,9 +277,6 @@ class UnixFileAttributes
|
||||
return new UnixAsBasicFileAttributes(attrs);
|
||||
}
|
||||
|
||||
UnixFileAttributes unwrap() {
|
||||
return attrs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastModifiedTime() {
|
||||
|
@ -126,7 +126,7 @@ public abstract class UnixFileSystemProvider
|
||||
return (V) UnixFileAttributeViews.createOwnerView(file, followLinks);
|
||||
if (type == null)
|
||||
throw new NullPointerException();
|
||||
return (V) null;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -148,6 +148,25 @@ public abstract class UnixFileSystemProvider
|
||||
return (A) getFileAttributeView(file, view, options).readAttributes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends BasicFileAttributes> A readAttributesIfExists(Path path,
|
||||
Class<A> type,
|
||||
LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
if (type == BasicFileAttributes.class && Util.followLinks(options)) {
|
||||
UnixPath file = UnixPath.toUnixPath(path);
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
A attrs = (A) UnixFileAttributes.getIfExists(file);
|
||||
return attrs;
|
||||
} catch (UnixException e) {
|
||||
e.rethrowAsIOException(file);
|
||||
}
|
||||
}
|
||||
return super.readAttributesIfExists(path, type, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DynamicFileAttributeView getFileAttributeView(Path obj,
|
||||
String name,
|
||||
@ -281,10 +300,9 @@ public abstract class UnixFileSystemProvider
|
||||
} else {
|
||||
for (AccessMode mode: modes) {
|
||||
switch (mode) {
|
||||
case READ : r = true; break;
|
||||
case WRITE : w = true; break;
|
||||
case EXECUTE : x = true; break;
|
||||
default: throw new AssertionError("Should not get here");
|
||||
case READ -> r = true;
|
||||
case WRITE -> w = true;
|
||||
case EXECUTE -> x = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -321,9 +339,8 @@ public abstract class UnixFileSystemProvider
|
||||
return true;
|
||||
if (obj2 == null)
|
||||
throw new NullPointerException();
|
||||
if (!(obj2 instanceof UnixPath))
|
||||
if (!(obj2 instanceof UnixPath file2))
|
||||
return false;
|
||||
UnixPath file2 = (UnixPath)obj2;
|
||||
|
||||
// check security manager access to both files
|
||||
file1.checkRead();
|
||||
@ -516,28 +533,16 @@ public abstract class UnixFileSystemProvider
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isDirectory(Path obj) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
file.checkRead();
|
||||
int mode = UnixNativeDispatcher.stat(file);
|
||||
return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR);
|
||||
}
|
||||
public boolean exists(Path path, LinkOption... options) {
|
||||
if (Util.followLinks(options)) {
|
||||
UnixPath file = UnixPath.toUnixPath(path);
|
||||
file.checkRead();
|
||||
return UnixNativeDispatcher.exists(file);
|
||||
} else {
|
||||
return super.exists(path, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isRegularFile(Path obj) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
file.checkRead();
|
||||
int mode = UnixNativeDispatcher.stat(file);
|
||||
return ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFREG);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean exists(Path obj) {
|
||||
UnixPath file = UnixPath.toUnixPath(obj);
|
||||
file.checkRead();
|
||||
return UnixNativeDispatcher.exists(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code FileTypeDetector} for this platform.
|
||||
*/
|
||||
|
@ -318,33 +318,28 @@ class UnixNativeDispatcher {
|
||||
try (NativeBuffer buffer = copyToNativeBuffer(path)) {
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
stat0(buffer.address(), attrs);
|
||||
int errno = stat0(buffer.address(), attrs);
|
||||
if (errno != 0) {
|
||||
throw new UnixException(errno);
|
||||
}
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static native void stat0(long pathAddress, UnixFileAttributes attrs)
|
||||
throws UnixException;
|
||||
|
||||
|
||||
/**
|
||||
* stat(const char* path, struct stat* buf)
|
||||
*
|
||||
* @return st_mode (file type and mode) or 0 if an error occurs.
|
||||
*/
|
||||
static int stat(UnixPath path) {
|
||||
static int stat2(UnixPath path, UnixFileAttributes attrs) {
|
||||
try (NativeBuffer buffer = copyToNativeBuffer(path)) {
|
||||
long comp = Blocker.begin();
|
||||
try {
|
||||
return stat1(buffer.address());
|
||||
return stat0(buffer.address(), attrs);
|
||||
} finally {
|
||||
Blocker.end(comp);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static native int stat1(long pathAddress);
|
||||
|
||||
private static native int stat0(long pathAddress, UnixFileAttributes attrs);
|
||||
|
||||
/**
|
||||
* lstat(const char* path, struct stat* buf)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -118,10 +118,11 @@ class UnixUriUtils {
|
||||
if (sb.charAt(sb.length()-1) != '/') {
|
||||
try {
|
||||
up.checkRead();
|
||||
int mode = UnixNativeDispatcher.stat(up);
|
||||
if ((mode & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR)
|
||||
UnixFileAttributes attrs = UnixFileAttributes.getIfExists(up);
|
||||
if (attrs != null
|
||||
&& ((attrs.mode() & UnixConstants.S_IFMT) == UnixConstants.S_IFDIR))
|
||||
sb.append('/');
|
||||
} catch (SecurityException ignore) { }
|
||||
} catch (UnixException | SecurityException ignore) { }
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -521,7 +521,7 @@ static void prepAttributes(JNIEnv* env, struct stat64* buf, jobject attrs) {
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this,
|
||||
jlong pathAddress, jobject attrs)
|
||||
{
|
||||
@ -530,24 +530,11 @@ Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this,
|
||||
const char* path = (const char*)jlong_to_ptr(pathAddress);
|
||||
|
||||
RESTARTABLE(stat64(path, &buf), err);
|
||||
if (err == -1) {
|
||||
throwUnixException(env, errno);
|
||||
} else {
|
||||
if (err == 0) {
|
||||
prepAttributes(env, &buf, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_nio_fs_UnixNativeDispatcher_stat1(JNIEnv* env, jclass this, jlong pathAddress) {
|
||||
int err;
|
||||
struct stat64 buf;
|
||||
const char* path = (const char*)jlong_to_ptr(pathAddress);
|
||||
|
||||
RESTARTABLE(stat64(path, &buf), err);
|
||||
if (err == -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return (jint)buf.st_mode;
|
||||
return errno;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,6 +191,15 @@ public class ZipFileSystemProvider extends FileSystemProvider {
|
||||
toZipPath(path).delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(Path path, LinkOption... options) {
|
||||
if (options.length == 0) {
|
||||
return toZipPath(path).exists();
|
||||
} else {
|
||||
return super.exists(path, options);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends FileAttributeView> V
|
||||
getFileAttributeView(Path path, Class<V> type, LinkOption... options)
|
||||
@ -284,6 +293,16 @@ public class ZipFileSystemProvider extends FileSystemProvider {
|
||||
return toZipPath(path).readAttributes(attributes, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // Cast to A
|
||||
public <A extends BasicFileAttributes> A readAttributesIfExists(Path path,
|
||||
Class<A> type,
|
||||
LinkOption... options)
|
||||
throws IOException
|
||||
{
|
||||
return (A) toZipPath(path).readAttributesIfExists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path readSymbolicLink(Path link) {
|
||||
throw new UnsupportedOperationException("Not supported.");
|
||||
|
@ -329,9 +329,8 @@ final class ZipPath implements Path {
|
||||
@Override
|
||||
public boolean startsWith(Path other) {
|
||||
Objects.requireNonNull(other, "other");
|
||||
if (!(other instanceof ZipPath))
|
||||
if (!(other instanceof final ZipPath o))
|
||||
return false;
|
||||
final ZipPath o = (ZipPath)other;
|
||||
if (o.isAbsolute() != this.isAbsolute() ||
|
||||
o.path.length > this.path.length)
|
||||
return false;
|
||||
@ -349,9 +348,8 @@ final class ZipPath implements Path {
|
||||
@Override
|
||||
public boolean endsWith(Path other) {
|
||||
Objects.requireNonNull(other, "other");
|
||||
if (!(other instanceof ZipPath))
|
||||
if (!(other instanceof final ZipPath o))
|
||||
return false;
|
||||
final ZipPath o = (ZipPath)other;
|
||||
int olast = o.path.length - 1;
|
||||
if (olast > 0 && o.path[olast] == '/')
|
||||
olast--;
|
||||
@ -382,17 +380,17 @@ final class ZipPath implements Path {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Path resolveSibling(String other) {
|
||||
public Path resolveSibling(String other) {
|
||||
return resolveSibling(zfs.getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean startsWith(String other) {
|
||||
public boolean startsWith(String other) {
|
||||
return startsWith(zfs.getPath(other));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean endsWith(String other) {
|
||||
public boolean endsWith(String other) {
|
||||
return endsWith(zfs.getPath(other));
|
||||
}
|
||||
|
||||
@ -671,7 +669,7 @@ final class ZipPath implements Path {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final File toFile() {
|
||||
public File toFile() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@ -844,6 +842,10 @@ final class ZipPath implements Path {
|
||||
return getFileAttributeView(view).readAttributes(attrs);
|
||||
}
|
||||
|
||||
ZipFileAttributes readAttributesIfExists() throws IOException {
|
||||
return zfs.getFileAttributes(getResolvedPath());
|
||||
}
|
||||
|
||||
FileStore getFileStore() throws IOException {
|
||||
// each ZipFileSystem only has one root (as requested for now)
|
||||
if (exists())
|
||||
@ -901,7 +903,7 @@ final class ZipPath implements Path {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean exists() {
|
||||
boolean exists() {
|
||||
return zfs.exists(getResolvedPath());
|
||||
}
|
||||
|
||||
|
220
test/jdk/java/nio/file/spi/TestDelegation.java
Normal file
220
test/jdk/java/nio/file/spi/TestDelegation.java
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.testng.AssertJUnit.assertEquals;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Verifies that a FileSystemProvider's implementation of the exists
|
||||
* and readAttributesIfExists methods are invoked
|
||||
* @build TestDelegation TestProvider
|
||||
* @run testng/othervm TestDelegation
|
||||
*/
|
||||
public class TestDelegation {
|
||||
|
||||
// Non-existent Path to be used by the test
|
||||
private Path nonExistentFile;
|
||||
// Path to Temp directory used by the test
|
||||
private Path tempDirectory;
|
||||
// Valid file Path used by the test
|
||||
private Path fileThatExists;
|
||||
// The FileSystemProvider used by the test
|
||||
private MyProvider myProvider;
|
||||
|
||||
|
||||
/**
|
||||
* Create the FileSystemProvider, the FileSystem and
|
||||
* Path's used by the test.
|
||||
*
|
||||
* @throws IOException if an error occurs
|
||||
*/
|
||||
@BeforeClass
|
||||
public void setup() throws IOException {
|
||||
myProvider = new MyProvider();
|
||||
FileSystem fs = myProvider.getFileSystem(URI.create("/"));
|
||||
// Path to Current Working Directory
|
||||
Path cwd = fs.getPath(".");
|
||||
tempDirectory = Files.createTempDirectory(cwd, "tmp");
|
||||
fileThatExists = Files.createFile(tempDirectory.resolve("file"));
|
||||
nonExistentFile = tempDirectory.resolve("doesNotExist");
|
||||
}
|
||||
|
||||
/**
|
||||
* DataProvider that is used to test Files::exists. The DataProvider's
|
||||
* elements are:
|
||||
* <UL>
|
||||
* <li>Path to validate</li>
|
||||
* <li>Does the Path Exist</li>
|
||||
* </UL>
|
||||
* @return The test parameter data
|
||||
*/
|
||||
@DataProvider
|
||||
private Object[][] testExists() {
|
||||
return new Object[][]{
|
||||
{tempDirectory, true},
|
||||
{fileThatExists, true},
|
||||
{nonExistentFile, false}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* DataProvider that is used to test Files::isDirectory. The DataProvider's
|
||||
* elements are:
|
||||
* <UL>
|
||||
* <li>Path to validate</li>
|
||||
* <li>Is the Path a Directory</li>
|
||||
* </UL>
|
||||
* @return The test parameter data
|
||||
*/
|
||||
@DataProvider
|
||||
private Object[][] testIsDirectory() {
|
||||
return new Object[][]{
|
||||
{tempDirectory, true},
|
||||
{fileThatExists, false},
|
||||
{nonExistentFile, false}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* DataProvider that is used to test Files::isRegularFile. The DataProvider's
|
||||
* elements are:
|
||||
* <UL>
|
||||
* <li>Path to validate</li>
|
||||
* <li>Is the Path a regular file</li>
|
||||
* </UL>
|
||||
* @return The test parameter data
|
||||
*/
|
||||
@DataProvider
|
||||
private Object[][] testIsRegularFile() {
|
||||
return new Object[][]{
|
||||
{tempDirectory, false},
|
||||
{fileThatExists, true},
|
||||
{nonExistentFile, false}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear our Map prior to each test run
|
||||
*/
|
||||
@BeforeMethod
|
||||
public void resetParams() {
|
||||
myProvider.resetCalls();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that Files::exists delegates to the FileSystemProvider's
|
||||
* implementation of exists.
|
||||
*
|
||||
* @param p the path to the file to test
|
||||
* @param exists does the path exist
|
||||
*/
|
||||
@Test(dataProvider = "testExists")
|
||||
public void testExists(Path p, boolean exists) {
|
||||
assertEquals(Files.exists(p), exists);
|
||||
// We should only have called exists once
|
||||
assertEquals(1, myProvider.findCall("exists").size());
|
||||
assertEquals(0, myProvider.findCall("readAttributesIfExists").size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that Files::isDirectory delegates to the FileSystemProvider's
|
||||
* implementation readAttributesIfExists.
|
||||
*
|
||||
* @param p the path to the file to test
|
||||
* @param isDir is the path a directory
|
||||
*/
|
||||
@Test(dataProvider = "testIsDirectory")
|
||||
public void testIsDirectory(Path p, boolean isDir) {
|
||||
assertEquals(Files.isDirectory(p), isDir);
|
||||
// We should only have called readAttributesIfExists once
|
||||
assertEquals(0, myProvider.findCall("exists").size());
|
||||
assertEquals(1, myProvider.findCall("readAttributesIfExists").size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that Files::isRegularFile delegates to the FileSystemProvider's
|
||||
* implementation readAttributesIfExists.
|
||||
*
|
||||
* @param p the path to the file to test
|
||||
* @param isFile is the path a regular file
|
||||
*/
|
||||
@Test(dataProvider = "testIsRegularFile")
|
||||
public void testIsRegularFile(Path p, boolean isFile) {
|
||||
assertEquals(Files.isRegularFile(p), isFile);
|
||||
// We should only have called readAttributesIfExists once
|
||||
assertEquals(0, myProvider.findCall("exists").size());
|
||||
assertEquals(1, myProvider.findCall("readAttributesIfExists").size());
|
||||
}
|
||||
|
||||
/**
|
||||
* The FileSystemProvider implementation used by the test
|
||||
*/
|
||||
static class MyProvider extends TestProvider {
|
||||
private final Map<String, List<Path>> calls = new HashMap<>();
|
||||
|
||||
private MyProvider() {
|
||||
super(FileSystems.getDefault().provider());
|
||||
}
|
||||
|
||||
private void recordCall(String op, Path path) {
|
||||
calls.computeIfAbsent(op, k -> new ArrayList<>()).add(path);
|
||||
}
|
||||
|
||||
List<Path> findCall(String op) {
|
||||
return calls.getOrDefault(op, List.of());
|
||||
}
|
||||
|
||||
void resetCalls() {
|
||||
calls.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(Path path, LinkOption... options) {
|
||||
recordCall("exists", path);
|
||||
return super.exists(path, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends BasicFileAttributes> A readAttributesIfExists(Path path,
|
||||
Class<A> type,
|
||||
LinkOption... options)
|
||||
throws IOException {
|
||||
recordCall("readAttributesIfExists", path);
|
||||
return super.readAttributesIfExists(path, type, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,7 +32,6 @@ import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.net.URI;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -48,10 +47,6 @@ public class TestProvider extends FileSystemProvider {
|
||||
this.theFileSystem = new TestFileSystem(fs, this);
|
||||
}
|
||||
|
||||
FileSystemProvider defaultProvider() {
|
||||
return defaultProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScheme() {
|
||||
return "file";
|
||||
@ -203,7 +198,8 @@ public class TestProvider extends FileSystemProvider {
|
||||
public void checkAccess(Path file, AccessMode... modes)
|
||||
throws IOException
|
||||
{
|
||||
throw new RuntimeException("not implemented");
|
||||
Path delegate = theFileSystem.unwrap(file);
|
||||
defaultProvider.checkAccess(delegate, modes);
|
||||
}
|
||||
|
||||
static class TestFileSystem extends FileSystem {
|
||||
@ -469,4 +465,5 @@ public class TestProvider extends FileSystemProvider {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.openjdk.bench.jdk.nio.zipfs;
|
||||
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Simple benchmark measuring cost of Files::exist, Files::isDirectory and
|
||||
* Files::isRegularFile with ZipFileSystem.
|
||||
*/
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@State(Scope.Thread)
|
||||
@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Measurement(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Fork(3)
|
||||
public class ZipfileSystemProviderDelegation {
|
||||
|
||||
public static final String ZIP_FILE = "zipfsprovider-delegation-benchmark.zip";
|
||||
public static final String NON_EXISTENT_SUFFIX = "-nope";
|
||||
@Param({"256", "512"})
|
||||
private int entriesToTest;
|
||||
public String[] entries;
|
||||
private FileSystem zipfs;
|
||||
|
||||
private int index = 0;
|
||||
|
||||
@Setup
|
||||
public void setup() throws IOException {
|
||||
Path zip = Paths.get(ZIP_FILE);
|
||||
Files.deleteIfExists(zip);
|
||||
Random random = new Random(4711);
|
||||
entries = new String[entriesToTest];
|
||||
URI zipURI = URI.create("jar:file:"+ zip.toAbsolutePath().toString());
|
||||
Map<String, String> env = new HashMap<>();
|
||||
env.put("create", "true");
|
||||
zipfs = FileSystems.newFileSystem(zipURI, env);
|
||||
for (int i = 0; i < entriesToTest; i++) {
|
||||
Path dir = zipfs.getPath("dir-" + (random.nextInt(90000) + 10000)
|
||||
+ "-" + i);
|
||||
Files.createDirectory(dir);
|
||||
Path entry = dir.resolve("entry-" +
|
||||
(random.nextInt(90000) + 10000)
|
||||
+ "-" + i);
|
||||
Files.write(entry, "".getBytes(StandardCharsets.UTF_8));
|
||||
entries[i] = entry.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@TearDown
|
||||
public void cleanup() throws IOException {
|
||||
zipfs.close();
|
||||
Files.deleteIfExists(Paths.get(ZIP_FILE));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void existsWithEntry() {
|
||||
if (index >= entriesToTest) {
|
||||
index = 0;
|
||||
}
|
||||
Files.exists(zipfs.getPath(entries[index++]));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void existsWithNonExistingEntry() {
|
||||
if (index >= entriesToTest) {
|
||||
index = 0;
|
||||
}
|
||||
Files.exists(zipfs.getPath(entries[index++] + NON_EXISTENT_SUFFIX));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void isDirectoryWithEntry() {
|
||||
if (index >= entriesToTest) {
|
||||
index = 0;
|
||||
}
|
||||
Files.isDirectory(zipfs.getPath(entries[index++]));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void isDirectoryWithNonExistingEntry() {
|
||||
if (index >= entriesToTest) {
|
||||
index = 0;
|
||||
}
|
||||
Files.isDirectory(zipfs.getPath(entries[index++] + NON_EXISTENT_SUFFIX));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void isRegularFileWithEntry() {
|
||||
if (index >= entriesToTest) {
|
||||
index = 0;
|
||||
}
|
||||
Files.isRegularFile(zipfs.getPath(entries[index++]));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void isRegularFileWithNonExistingEntry() {
|
||||
if (index >= entriesToTest) {
|
||||
index = 0;
|
||||
}
|
||||
Files.isRegularFile(zipfs.getPath(entries[index++] + NON_EXISTENT_SUFFIX));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user