mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
8322166: Files.isReadable/isWritable/isExecutable expensive when file does not exist
Reviewed-by: alanb
This commit is contained in:
parent
0f8e4e0a81
commit
51be857f3c
6 changed files with 98 additions and 50 deletions
|
@ -80,6 +80,7 @@ import java.util.stream.StreamSupport;
|
||||||
import jdk.internal.util.ArraysSupport;
|
import jdk.internal.util.ArraysSupport;
|
||||||
import sun.nio.ch.FileChannelImpl;
|
import sun.nio.ch.FileChannelImpl;
|
||||||
import sun.nio.cs.UTF_8;
|
import sun.nio.cs.UTF_8;
|
||||||
|
import sun.nio.fs.AbstractFileSystemProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class consists exclusively of static methods that operate on files,
|
* This class consists exclusively of static methods that operate on files,
|
||||||
|
@ -2609,7 +2610,11 @@ public final class Files {
|
||||||
* is invoked to check read access to the file.
|
* is invoked to check read access to the file.
|
||||||
*/
|
*/
|
||||||
public static boolean isReadable(Path path) {
|
public static boolean isReadable(Path path) {
|
||||||
return isAccessible(path, AccessMode.READ);
|
FileSystemProvider provider = provider(path);
|
||||||
|
if (provider instanceof AbstractFileSystemProvider afsp)
|
||||||
|
return afsp.isReadable(path);
|
||||||
|
else
|
||||||
|
return isAccessible(path, AccessMode.READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2640,7 +2645,11 @@ public final class Files {
|
||||||
* is invoked to check write access to the file.
|
* is invoked to check write access to the file.
|
||||||
*/
|
*/
|
||||||
public static boolean isWritable(Path path) {
|
public static boolean isWritable(Path path) {
|
||||||
return isAccessible(path, AccessMode.WRITE);
|
FileSystemProvider provider = provider(path);
|
||||||
|
if (provider instanceof AbstractFileSystemProvider afsp)
|
||||||
|
return afsp.isWritable(path);
|
||||||
|
else
|
||||||
|
return isAccessible(path, AccessMode.WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2675,7 +2684,11 @@ public final class Files {
|
||||||
* checkExec} is invoked to check execute access to the file.
|
* checkExec} is invoked to check execute access to the file.
|
||||||
*/
|
*/
|
||||||
public static boolean isExecutable(Path path) {
|
public static boolean isExecutable(Path path) {
|
||||||
return isAccessible(path, AccessMode.EXECUTE);
|
FileSystemProvider provider = provider(path);
|
||||||
|
if (provider instanceof AbstractFileSystemProvider afsp)
|
||||||
|
return afsp.isExecutable(path);
|
||||||
|
else
|
||||||
|
return isAccessible(path, AccessMode.EXECUTE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Recursive operations --
|
// -- Recursive operations --
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -25,8 +25,9 @@
|
||||||
|
|
||||||
package sun.nio.fs;
|
package sun.nio.fs;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.AccessMode;
|
||||||
import java.nio.file.LinkOption;
|
import java.nio.file.LinkOption;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.nio.file.spi.FileSystemProvider;
|
import java.nio.file.spi.FileSystemProvider;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -115,4 +116,40 @@ public abstract class AbstractFileSystemProvider extends FileSystemProvider {
|
||||||
* If path is empty, then an empty byte[] is returned.
|
* If path is empty, then an empty byte[] is returned.
|
||||||
*/
|
*/
|
||||||
public abstract byte[] getSunPathForSocketFile(Path path);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -893,7 +893,9 @@ abstract class UnixFileSystem
|
||||||
sourceAttrs = UnixFileAttributes.get(source, false);
|
sourceAttrs = UnixFileAttributes.get(source, false);
|
||||||
if (sourceAttrs.isDirectory()) {
|
if (sourceAttrs.isDirectory()) {
|
||||||
// ensure source can be moved
|
// 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) {
|
} catch (UnixException x) {
|
||||||
x.rethrowAsIOException(source);
|
x.rethrowAsIOException(source);
|
||||||
|
@ -1024,13 +1026,11 @@ abstract class UnixFileSystem
|
||||||
|
|
||||||
// ensure source can be copied
|
// ensure source can be copied
|
||||||
if (!sourceAttrs.isSymbolicLink() || flags.followLinks) {
|
if (!sourceAttrs.isSymbolicLink() || flags.followLinks) {
|
||||||
try {
|
// the access(2) system call always follows links so it
|
||||||
// the access(2) system call always follows links so it
|
// is suppressed if the source is an unfollowed link
|
||||||
// is suppressed if the source is an unfollowed link
|
int errno = access(source, R_OK);
|
||||||
access(source, R_OK);
|
if (errno != 0)
|
||||||
} catch (UnixException exc) {
|
new UnixException(errno).rethrowAsIOException(source);
|
||||||
exc.rethrowAsIOException(source);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get attributes of target file (don't follow links)
|
// get attributes of target file (don't follow links)
|
||||||
|
|
|
@ -349,11 +349,35 @@ public abstract class UnixFileSystemProvider
|
||||||
}
|
}
|
||||||
mode |= X_OK;
|
mode |= X_OK;
|
||||||
}
|
}
|
||||||
try {
|
int errno = access(file, mode);
|
||||||
access(file, mode);
|
if (errno != 0)
|
||||||
} catch (UnixException exc) {
|
new UnixException(errno).rethrowAsIOException(file);
|
||||||
exc.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
|
@Override
|
||||||
|
@ -561,7 +585,7 @@ public abstract class UnixFileSystemProvider
|
||||||
if (Util.followLinks(options)) {
|
if (Util.followLinks(options)) {
|
||||||
UnixPath file = UnixPath.toUnixPath(path);
|
UnixPath file = UnixPath.toUnixPath(path);
|
||||||
file.checkRead();
|
file.checkRead();
|
||||||
return UnixNativeDispatcher.exists(file);
|
return access(file, F_OK) == 0;
|
||||||
} else {
|
} else {
|
||||||
return super.exists(path, options);
|
return super.exists(path, options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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);
|
* 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)) {
|
try (NativeBuffer buffer = copyToNativeBuffer(path)) {
|
||||||
long comp = Blocker.begin();
|
long comp = Blocker.begin();
|
||||||
try {
|
try {
|
||||||
access0(buffer.address(), amode);
|
return access0(buffer.address(), amode);
|
||||||
} finally {
|
} finally {
|
||||||
Blocker.end(comp);
|
Blocker.end(comp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static native void access0(long pathAddress, int amode) throws UnixException;
|
private static native int access0(long pathAddress, int amode);
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct passwd *getpwuid(uid_t uid);
|
* struct passwd *getpwuid(uid_t uid);
|
||||||
|
|
|
@ -1190,7 +1190,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_realpath0(JNIEnv* env, jclass this,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this,
|
Java_sun_nio_fs_UnixNativeDispatcher_access0(JNIEnv* env, jclass this,
|
||||||
jlong pathAddress, jint amode)
|
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);
|
const char* path = (const char*)jlong_to_ptr(pathAddress);
|
||||||
|
|
||||||
RESTARTABLE(access(path, (int)amode), err);
|
RESTARTABLE(access(path, (int)amode), err);
|
||||||
if (err == -1) {
|
|
||||||
throwUnixException(env, errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL
|
return (err == -1) ? errno : 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue