8322166: Files.isReadable/isWritable/isExecutable expensive when file does not exist

Reviewed-by: alanb
This commit is contained in:
Brian Burkhalter 2023-12-19 18:27:06 +00:00
parent 0f8e4e0a81
commit 51be857f3c
6 changed files with 98 additions and 50 deletions

View file

@ -80,6 +80,7 @@ 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,
@ -2609,6 +2610,10 @@ public final class Files {
* is invoked to check read access to the file.
*/
public static boolean isReadable(Path path) {
FileSystemProvider provider = provider(path);
if (provider instanceof AbstractFileSystemProvider afsp)
return afsp.isReadable(path);
else
return isAccessible(path, AccessMode.READ);
}
@ -2640,6 +2645,10 @@ public final class Files {
* is invoked to check write access to the file.
*/
public static boolean isWritable(Path path) {
FileSystemProvider provider = provider(path);
if (provider instanceof AbstractFileSystemProvider afsp)
return afsp.isWritable(path);
else
return isAccessible(path, AccessMode.WRITE);
}
@ -2675,6 +2684,10 @@ public final class Files {
* checkExec} is invoked to check execute access to the file.
*/
public static boolean isExecutable(Path path) {
FileSystemProvider provider = provider(path);
if (provider instanceof AbstractFileSystemProvider afsp)
return afsp.isExecutable(path);
else
return isAccessible(path, AccessMode.EXECUTE);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2023, 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
@ -25,8 +25,9 @@
package sun.nio.fs;
import java.nio.file.Path;
import java.nio.file.AccessMode;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.spi.FileSystemProvider;
import java.io.IOException;
import java.util.Map;
@ -115,4 +116,40 @@ public abstract class AbstractFileSystemProvider extends FileSystemProvider {
* If path is empty, then an empty byte[] is returned.
*/
public abstract byte[] getSunPathForSocketFile(Path path);
/**
* Tests whether a file is readable.
*/
public boolean isReadable(Path path) {
try {
checkAccess(path, AccessMode.READ);
} catch (IOException e) {
return false;
}
return true;
}
/**
* Tests whether a file is writable.
*/
public boolean isWritable(Path path) {
try {
checkAccess(path, AccessMode.WRITE);
} catch (IOException e) {
return false;
}
return true;
}
/**
* Tests whether a file is executable.
*/
public boolean isExecutable(Path path) {
try {
checkAccess(path, AccessMode.EXECUTE);
} catch (IOException e) {
return false;
}
return true;
}
}

View file

@ -893,7 +893,9 @@ abstract class UnixFileSystem
sourceAttrs = UnixFileAttributes.get(source, false);
if (sourceAttrs.isDirectory()) {
// ensure source can be moved
access(source, W_OK);
int errno = access(source, W_OK);
if (errno != 0)
new UnixException(errno).rethrowAsIOException(source);
}
} catch (UnixException x) {
x.rethrowAsIOException(source);
@ -1024,13 +1026,11 @@ abstract class UnixFileSystem
// ensure source can be copied
if (!sourceAttrs.isSymbolicLink() || flags.followLinks) {
try {
// the access(2) system call always follows links so it
// is suppressed if the source is an unfollowed link
access(source, R_OK);
} catch (UnixException exc) {
exc.rethrowAsIOException(source);
}
int errno = access(source, R_OK);
if (errno != 0)
new UnixException(errno).rethrowAsIOException(source);
}
// get attributes of target file (don't follow links)

View file

@ -349,11 +349,35 @@ public abstract class UnixFileSystemProvider
}
mode |= X_OK;
}
try {
access(file, mode);
} catch (UnixException exc) {
exc.rethrowAsIOException(file);
int errno = access(file, mode);
if (errno != 0)
new UnixException(errno).rethrowAsIOException(file);
}
@Override
public boolean isReadable(Path path) {
UnixPath file = UnixPath.toUnixPath(path);
file.checkRead();
return access(file, R_OK) == 0;
}
@Override
public boolean isWritable(Path path) {
UnixPath file = UnixPath.toUnixPath(path);
file.checkWrite();
return access(file, W_OK) == 0;
}
@Override
public boolean isExecutable(Path path) {
UnixPath file = UnixPath.toUnixPath(path);
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// not cached
sm.checkExec(file.getPathForPermissionCheck());
}
return access(file, X_OK) == 0;
}
@Override
@ -561,7 +585,7 @@ public abstract class UnixFileSystemProvider
if (Util.followLinks(options)) {
UnixPath file = UnixPath.toUnixPath(path);
file.checkRead();
return UnixNativeDispatcher.exists(file);
return access(file, F_OK) == 0;
} else {
return super.exists(path, options);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2023, 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
@ -597,34 +597,17 @@ class UnixNativeDispatcher {
/**
* access(const char* path, int amode);
*/
static void access(UnixPath path, int amode) throws UnixException {
static int access(UnixPath path, int amode) {
try (NativeBuffer buffer = copyToNativeBuffer(path)) {
long comp = Blocker.begin();
try {
access0(buffer.address(), amode);
return access0(buffer.address(), amode);
} finally {
Blocker.end(comp);
}
}
}
private static native void access0(long pathAddress, int amode) throws UnixException;
/**
* access(constant char* path, F_OK)
*
* @return true if the file exists, false otherwise
*/
static boolean exists(UnixPath path) {
try (NativeBuffer buffer = copyToNativeBuffer(path)) {
long comp = Blocker.begin();
try {
return exists0(buffer.address());
} finally {
Blocker.end(comp);
}
}
}
private static native boolean exists0(long pathAddress);
private static native int access0(long pathAddress, int amode);
/**
* struct passwd *getpwuid(uid_t uid);

View file

@ -1190,7 +1190,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this,
return result;
}
JNIEXPORT void JNICALL
JNIEXPORT jint JNICALL
Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this,
jlong pathAddress, jint amode)
{
@ -1198,17 +1198,8 @@ Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this,
const char* path = (const char*)jlong_to_ptr(pathAddress);
RESTARTABLE(access(path, (int)amode), err);
if (err == -1) {
throwUnixException(env, errno);
}
}
JNIEXPORT jboolean JNICALL
Java_sun_nio_fs_UnixNativeDispatcher_exists0(JNIEnv* env, jclass this, jlong pathAddress) {
int err;
const char* path = (const char*)jlong_to_ptr(pathAddress);
RESTARTABLE(access(path, F_OK), err);
return (err == 0) ? JNI_TRUE : JNI_FALSE;
return (err == -1) ? errno : 0;
}
JNIEXPORT void JNICALL