Skip to content

Commit

Permalink
8293122: (fs) Use file cloning in macOS version of Files::copy method
Browse files Browse the repository at this point in the history
Reviewed-by: alanb
  • Loading branch information
Brian Burkhalter committed Sep 14, 2022
1 parent 95c7c55 commit a75ddb8
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 1 deletion.
76 changes: 76 additions & 0 deletions src/java.base/macosx/classes/sun/nio/fs/BsdFileSystem.java
Expand Up @@ -33,8 +33,13 @@
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
*/
Expand Down Expand Up @@ -71,13 +76,84 @@ public Set<String> supportedFileAttributeViews() {
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
{
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);
Expand Down
20 changes: 20 additions & 0 deletions src/java.base/macosx/classes/sun/nio/fs/BsdNativeDispatcher.java
Expand Up @@ -61,6 +61,26 @@ static byte[] getmntonname(UnixPath path) throws UnixException {
}
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)
Expand Down
18 changes: 18 additions & 0 deletions src/java.base/macosx/native/libnio/fs/BsdNativeDispatcher.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java
Expand Up @@ -428,7 +428,7 @@ private static int temporaryBufferSize(UnixPath source, UnixPath target) {
}

// 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;
Expand Down

1 comment on commit a75ddb8

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.