8293122: (fs) Use file cloning in macOS version of Files::copy method

Reviewed-by: alanb
This commit is contained in:
Brian Burkhalter 2022-09-14 20:13:19 +00:00
parent 95c7c556a3
commit a75ddb836b
5 changed files with 124 additions and 1 deletions
src/java.base

@ -33,8 +33,13 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import sun.nio.ch.IOStatus;
import sun.security.action.GetPropertyAction;
import static sun.nio.fs.UnixConstants.*;
import static sun.nio.fs.UnixNativeDispatcher.chown;
import static sun.nio.fs.UnixNativeDispatcher.unlink;
/**
* Bsd implementation of FileSystem
*/
@ -71,6 +76,38 @@ class BsdFileSystem extends UnixFileSystem {
return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
}
/**
* Clones the file whose path name is {@code src} to that whose path
* name is {@code dst} using the {@code clonefile} system call.
*
* @param src the path of the source file
* @param dst the path of the destination file (clone)
* @param followLinks whether to follow links
*
* @return 0 on success, or IOStatus.UNSUPPORTED_CASE if the call
* does not work with the given parameters
*/
private int clone(UnixPath src, UnixPath dst, boolean followLinks)
throws IOException
{
int flags = followLinks ? 0 : CLONE_NOFOLLOW;
try {
BsdNativeDispatcher.clonefile(src, dst, flags);
} catch (UnixException x) {
switch (x.errno()) {
case ENOTSUP: // cloning not supported by filesystem
case EXDEV: // src and dst on different filesystems
case ENOTDIR: // problematic path parameter(s)
return IOStatus.UNSUPPORTED_CASE;
default:
x.rethrowAsIOException(src, dst);
return IOStatus.THROWN;
}
}
return 0;
}
@Override
protected int directCopy(int dst, int src, long addressToPollForCancel)
throws UnixException
@ -78,6 +115,45 @@ class BsdFileSystem extends UnixFileSystem {
return directCopy0(dst, src, addressToPollForCancel);
}
@Override
protected void copyFile(UnixPath source,
UnixFileAttributes attrs,
UnixPath target,
Flags flags,
long addressToPollForCancel)
throws IOException
{
// Attempt to clone the source unless cancellation is not possible,
// or attributes are not to be copied
if (addressToPollForCancel == 0 && flags.copyPosixAttributes) {
try {
int res = clone(source, target, flags.followLinks);
if (res == 0) {
// copy owner (not done by clonefile)
try {
chown(target, attrs.uid(), attrs.gid());
} catch (UnixException x) {
if (flags.failIfUnableToCopyPosix)
x.rethrowAsIOException(target);
}
return;
}
} catch (IOException e) {
// clone or chown failed so roll back
try {
unlink(target);
} catch (UnixException ignore) { }
throw e;
}
// fall through to superclass method
}
super.copyFile(source, attrs, target, flags, addressToPollForCancel);
}
@Override
void copyNonPosixAttributes(int ofd, int nfd) {
UnixUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);

@ -61,6 +61,26 @@ class BsdNativeDispatcher extends UnixNativeDispatcher {
}
static native byte[] getmntonname0(long pathAddress) throws UnixException;
/**
* int clonefile(const char * src, const char * dst, int flags);
*/
static int clonefile(UnixPath src, UnixPath dst, int flags)
throws UnixException
{
try (NativeBuffer srcBuffer = copyToNativeBuffer(src);
NativeBuffer dstBuffer = copyToNativeBuffer(dst)) {
long comp = Blocker.begin();
try {
return clonefile0(srcBuffer.address(), dstBuffer.address(),
flags);
} finally {
Blocker.end(comp);
}
}
}
private static native int clonefile0(long srcAddress, long dstAddress,
int flags);
/**
* setattrlist(const char* path, struct attrlist* attrList, void* attrBuf,
* size_t attrBufSize, unsigned long options)

@ -42,6 +42,8 @@
#include <stdlib.h>
#include <string.h>
#include <sys/attr.h>
#include <sys/clonefile.h>
static jfieldID entry_name;
static jfieldID entry_dir;
@ -225,6 +227,22 @@ Java_sun_nio_fs_BsdNativeDispatcher_getmntonname0(JNIEnv *env, jclass this,
return mntonname;
}
JNIEXPORT jint JNICALL
Java_sun_nio_fs_BsdNativeDispatcher_clonefile0(JNIEnv* env, jclass this,
jlong srcAddress, jlong dstAddress, jint flags)
{
const char* src = (const char*)jlong_to_ptr(srcAddress);
const char* dst = (const char*)jlong_to_ptr(dstAddress);
int ret = clonefile(src, dst, flags);
if (ret != 0) {
throwUnixException(env, errno);
return ret;
}
return 0;
}
JNIEXPORT void JNICALL
Java_sun_nio_fs_BsdNativeDispatcher_setattrlist0(JNIEnv* env, jclass this,
jlong pathAddress, int commonattr, jlong modTime, jlong accTime,

@ -32,6 +32,7 @@
#include <sys/stat.h>
#ifdef _ALLBSD_SOURCE
#include <sys/attr.h>
#include <sys/clonefile.h>
#endif
/* To be able to name the Java constants the same as the C constants without
@ -133,6 +134,10 @@ class UnixConstants {
static final int PREFIX_ERANGE = ERANGE;
static final int PREFIX_EMFILE = EMFILE;
#ifdef _ALLBSD_SOURCE
static final int PREFIX_ENOTSUP = ENOTSUP;
#endif
// flags used with openat/unlinkat/etc.
#if defined(AT_SYMLINK_NOFOLLOW) && defined(AT_REMOVEDIR)
static final int PREFIX_AT_SYMLINK_NOFOLLOW = AT_SYMLINK_NOFOLLOW;
@ -144,6 +149,10 @@ class UnixConstants {
#endif
#ifdef _ALLBSD_SOURCE
// flags used with clonefile
static final int PREFIX_CLONE_NOFOLLOW = CLONE_NOFOLLOW;
static final int PREFIX_CLONE_NOOWNERCOPY = CLONE_NOOWNERCOPY;
// flags used with setattrlist
static final int PREFIX_ATTR_CMN_CRTIME = ATTR_CMN_CRTIME;
static final int PREFIX_ATTR_CMN_MODTIME = ATTR_CMN_MODTIME;

@ -428,7 +428,7 @@ abstract class UnixFileSystem
}
// The flags that control how a file is copied or moved
private static class Flags {
protected static class Flags {
boolean replaceExisting;
boolean atomicMove;
boolean followLinks;