From db699195362347eee7eedbba01a4edf0a2fb633b Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 30 Nov 2024 11:17:19 +0800 Subject: [PATCH 1/3] Fix unhandled UnsupportedOperationException in Fallocate --- src/freenet/support/io/Fallocate.java | 50 +++++++++++++++++++-------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/freenet/support/io/Fallocate.java b/src/freenet/support/io/Fallocate.java index 6df493444ba..ba104e940ff 100644 --- a/src/freenet/support/io/Fallocate.java +++ b/src/freenet/support/io/Fallocate.java @@ -38,49 +38,69 @@ private Fallocate(FileChannel channel, int fd, long final_filesize) { } public static Fallocate forChannel(FileChannel channel, long final_filesize) { - return new Fallocate(channel, getDescriptor(channel), final_filesize); + try { + return new Fallocate(channel, getDescriptor(channel), final_filesize); + } catch (final UnsupportedOperationException exception) { + // File descriptor is not supported: fd is null and unavailable + return new Fallocate(channel, 0, final_filesize); + } } public static Fallocate forChannel(FileChannel channel, FileDescriptor fd, long final_filesize) { - return new Fallocate(channel, getDescriptor(fd), final_filesize); + try { + return new Fallocate(channel, getDescriptor(fd), final_filesize); + } catch (final UnsupportedOperationException exception) { + // File descriptor is not supported: fd is null and unavailable + return new Fallocate(channel, 0, final_filesize); + } } - public Fallocate fromOffset(long offset) { + public Fallocate fromOffset(long offset) throws IllegalArgumentException { if(offset < 0 || offset > final_filesize) throw new IllegalArgumentException(); this.offset = offset; return this; } - public Fallocate keepSize() { + public Fallocate keepSize() throws UnsupportedOperationException { requireLinux("fallocate keep size"); mode |= FALLOC_FL_KEEP_SIZE; return this; } - private void requireLinux(String feature) { + private void requireLinux(String feature) throws UnsupportedOperationException { if (!IS_LINUX) { throwUnsupported(feature); } } - private void throwUnsupported(String feature) { + private void throwUnsupported(String feature) throws UnsupportedOperationException { throw new UnsupportedOperationException(feature + " is not supported on this file system"); } public void execute() throws IOException { int errno = 0; boolean isUnsupported = false; - if (IS_LINUX) { - final int result = FallocateHolder.fallocate(fd, mode, offset, final_filesize-offset); - errno = result == 0 ? 0 : Native.getLastError(); - } else if (IS_POSIX) { - errno = FallocateHolderPOSIX.posix_fallocate(fd, offset, final_filesize-offset); + if (fd != 0) { + if (IS_LINUX) { + final int result = FallocateHolder.fallocate(fd, mode, offset, final_filesize-offset); + errno = result == 0 ? 0 : Native.getLastError(); + } else if (IS_POSIX) { + errno = FallocateHolderPOSIX.posix_fallocate(fd, offset, final_filesize-offset); + } else { + isUnsupported = true; + } } else { - isUnsupported = true; + // fd is null and unavailable + if (Platform.isWindows()) { + // Windows do not create sparse files by default, so just write a byte at the end. + channel.write(ByteBuffer.allocate(1), final_filesize - 1); + } else { + isUnsupported = true; + } } if (isUnsupported || errno != 0) { - Logger.normal(this, "fallocate() failed; using legacy method; errno="+errno); + Logger.normal(this, "fallocate() failed; using legacy method; errno=" + errno); legacyFill(channel, final_filesize, offset); } } @@ -101,7 +121,7 @@ private static class FallocateHolderPOSIX { private static native int posix_fallocate(int fd, long offset, long length); } - private static int getDescriptor(FileChannel channel) { + private static int getDescriptor(FileChannel channel) throws UnsupportedOperationException { try { // sun.nio.ch.FileChannelImpl declares private final java.io.FileDescriptor fd final Field field = channel.getClass().getDeclaredField("fd"); @@ -112,7 +132,7 @@ private static int getDescriptor(FileChannel channel) { } } - private static int getDescriptor(FileDescriptor descriptor) { + private static int getDescriptor(FileDescriptor descriptor) throws UnsupportedOperationException { try { // Oracle java.io.FileDescriptor declares private int fd final Field field = descriptor.getClass().getDeclaredField(IS_ANDROID ? "descriptor" : "fd"); From 3292cbca61e667a4f2505bed56633ced05b291c5 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 30 Nov 2024 23:25:06 +0800 Subject: [PATCH 2/3] Do not throw UnsupportedOperationException in Fallocate --- src/freenet/support/io/Fallocate.java | 74 +++++++++++---------------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/src/freenet/support/io/Fallocate.java b/src/freenet/support/io/Fallocate.java index ba104e940ff..158cfd82e65 100644 --- a/src/freenet/support/io/Fallocate.java +++ b/src/freenet/support/io/Fallocate.java @@ -10,7 +10,6 @@ import java.nio.channels.FileChannel; import freenet.support.Logger; -import freenet.support.math.MersenneTwister; /** * Provides access to operating system-specific {@code fallocate} and @@ -20,6 +19,7 @@ public final class Fallocate { private static final boolean IS_LINUX = Platform.isLinux(); + private static final boolean IS_WINDOWS = Platform.isWindows(); private static final boolean IS_POSIX = !Platform.isWindows() && !Platform.isMac() && !Platform.isOpenBSD(); private static final boolean IS_ANDROID = Platform.isAndroid(); @@ -38,21 +38,11 @@ private Fallocate(FileChannel channel, int fd, long final_filesize) { } public static Fallocate forChannel(FileChannel channel, long final_filesize) { - try { - return new Fallocate(channel, getDescriptor(channel), final_filesize); - } catch (final UnsupportedOperationException exception) { - // File descriptor is not supported: fd is null and unavailable - return new Fallocate(channel, 0, final_filesize); - } + return new Fallocate(channel, getDescriptor(channel), final_filesize); } public static Fallocate forChannel(FileChannel channel, FileDescriptor fd, long final_filesize) { - try { - return new Fallocate(channel, getDescriptor(fd), final_filesize); - } catch (final UnsupportedOperationException exception) { - // File descriptor is not supported: fd is null and unavailable - return new Fallocate(channel, 0, final_filesize); - } + return new Fallocate(channel, getDescriptor(fd), final_filesize); } public Fallocate fromOffset(long offset) throws IllegalArgumentException { @@ -61,22 +51,16 @@ public Fallocate fromOffset(long offset) throws IllegalArgumentException { return this; } + // This method only works for Linux, do not use it. + @Deprecated public Fallocate keepSize() throws UnsupportedOperationException { - requireLinux("fallocate keep size"); + if (!IS_LINUX) { + throw new UnsupportedOperationException("fallocate keep size is not supported on this file system"); + } mode |= FALLOC_FL_KEEP_SIZE; return this; } - private void requireLinux(String feature) throws UnsupportedOperationException { - if (!IS_LINUX) { - throwUnsupported(feature); - } - } - - private void throwUnsupported(String feature) throws UnsupportedOperationException { - throw new UnsupportedOperationException(feature + " is not supported on this file system"); - } - public void execute() throws IOException { int errno = 0; boolean isUnsupported = false; @@ -90,17 +74,14 @@ public void execute() throws IOException { isUnsupported = true; } } else { - // fd is null and unavailable - if (Platform.isWindows()) { - // Windows do not create sparse files by default, so just write a byte at the end. - channel.write(ByteBuffer.allocate(1), final_filesize - 1); - } else { - isUnsupported = true; - } + isUnsupported = true; } if (isUnsupported || errno != 0) { - Logger.normal(this, "fallocate() failed; using legacy method; errno=" + errno); + if (errno != 0) { + // OS supports fallocate() but it failed. Do not log if the OS does not support fallocate(). + Logger.normal(this, "fallocate() failed; using legacy method; errno=" + errno); + } legacyFill(channel, final_filesize, offset); } } @@ -121,38 +102,41 @@ private static class FallocateHolderPOSIX { private static native int posix_fallocate(int fd, long offset, long length); } - private static int getDescriptor(FileChannel channel) throws UnsupportedOperationException { + private static int getDescriptor(FileChannel channel) { try { // sun.nio.ch.FileChannelImpl declares private final java.io.FileDescriptor fd final Field field = channel.getClass().getDeclaredField("fd"); field.setAccessible(true); return getDescriptor((FileDescriptor) field.get(channel)); } catch (final Exception e) { - throw new UnsupportedOperationException("unsupported FileChannel implementation", e); + // File descriptor is not supported: fd is null and unavailable, return 0 + return 0; } } - private static int getDescriptor(FileDescriptor descriptor) throws UnsupportedOperationException { + private static int getDescriptor(FileDescriptor descriptor) { try { // Oracle java.io.FileDescriptor declares private int fd final Field field = descriptor.getClass().getDeclaredField(IS_ANDROID ? "descriptor" : "fd"); field.setAccessible(true); return (int) field.get(descriptor); } catch (final Exception e) { - throw new UnsupportedOperationException("unsupported FileDescriptor implementation", e); + // File descriptor is not supported: fd is null and unavailable, return 0 + return 0; } } private static void legacyFill(FileChannel fc, long newLength, long offset) throws IOException { - MersenneTwister mt = new MersenneTwister(); - byte[] b = new byte[4096]; - ByteBuffer bb = ByteBuffer.wrap(b); - while (offset < newLength) { - bb.rewind(); - mt.nextBytes(b); - offset += fc.write(bb, offset); - if (offset % (1024 * 1024 * 1024L) == 0) { - mt = new MersenneTwister(); + if (IS_WINDOWS) { + // Windows do not create sparse files by default, so just write a byte at the end. + fc.write(ByteBuffer.allocate(1), newLength - 1); + } else { + // fill fc with zeros + byte[] b = new byte[4096]; + ByteBuffer bb = ByteBuffer.wrap(b); + while (offset < newLength) { + bb.rewind(); + offset += fc.write(bb, offset); } } } From f8eb2efcd7e2d4416c3b0a1861b7c92b99a80912 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sun, 1 Dec 2024 10:44:54 +0800 Subject: [PATCH 3/3] Remove throws clause --- src/freenet/support/io/Fallocate.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/freenet/support/io/Fallocate.java b/src/freenet/support/io/Fallocate.java index 158cfd82e65..1d80b2aed54 100644 --- a/src/freenet/support/io/Fallocate.java +++ b/src/freenet/support/io/Fallocate.java @@ -45,15 +45,21 @@ public static Fallocate forChannel(FileChannel channel, FileDescriptor fd, long return new Fallocate(channel, getDescriptor(fd), final_filesize); } - public Fallocate fromOffset(long offset) throws IllegalArgumentException { + /** + * @throws IllegalArgumentException + */ + public Fallocate fromOffset(long offset) { if(offset < 0 || offset > final_filesize) throw new IllegalArgumentException(); this.offset = offset; return this; } - // This method only works for Linux, do not use it. + /** + * This method only works for Linux, do not use it. + * @throws UnsupportedOperationException + */ @Deprecated - public Fallocate keepSize() throws UnsupportedOperationException { + public Fallocate keepSize() { if (!IS_LINUX) { throw new UnsupportedOperationException("fallocate keep size is not supported on this file system"); } @@ -64,7 +70,7 @@ public Fallocate keepSize() throws UnsupportedOperationException { public void execute() throws IOException { int errno = 0; boolean isUnsupported = false; - if (fd != 0) { + if (fd > 2) { if (IS_LINUX) { final int result = FallocateHolder.fallocate(fd, mode, offset, final_filesize-offset); errno = result == 0 ? 0 : Native.getLastError();