Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve setting out-of-range values in mac implementation #28

Merged
merged 9 commits into from
Mar 10, 2023
26 changes: 8 additions & 18 deletions jfuse-mac/src/main/java/org/cryptomator/jfuse/mac/StatvfsImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

record StatvfsImpl(MemorySegment segment) implements Statvfs {

private static final long MAX_UINT = 0xFFFFFFFFL;

public StatvfsImpl(MemoryAddress address, MemorySession scope) {
this(statvfs.ofAddress(address, scope));
}
Expand All @@ -35,44 +37,32 @@ public void setFrsize(long frsize) {

@Override
public long getBlocks() {
return statvfs.f_blocks$get(segment);
return Integer.toUnsignedLong(statvfs.f_blocks$get(segment));
}

@Override
public void setBlocks(long blocks) {
if (blocks > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Max supported number of blocks: " + Integer.MAX_VALUE);
} else {
statvfs.f_blocks$set(segment, (int) blocks);
}
statvfs.f_blocks$set(segment,(int) Math.min(MAX_UINT, blocks));
}

@Override
public long getBfree() {
return statvfs.f_bfree$get(segment);
return Integer.toUnsignedLong(statvfs.f_bfree$get(segment));
}

@Override
public void setBfree(long bfree) {
if (bfree > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Max supported number of blocks: " + Integer.MAX_VALUE);
} else {
statvfs.f_bfree$set(segment, (int) bfree);
}
statvfs.f_bfree$set(segment,(int) Math.min(MAX_UINT, bfree));
}

@Override
public long getBavail() {
return statvfs.f_bavail$get(segment);
return Integer.toUnsignedLong(statvfs.f_bavail$get(segment));
}

@Override
public void setBavail(long bavail) {
if (bavail > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Max supported number of blocks: " + Integer.MAX_VALUE);
} else {
statvfs.f_bavail$set(segment, (int) bavail);
}
statvfs.f_bavail$set(segment,(int) Math.min(MAX_UINT, bavail));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.cryptomator.jfuse.mac;

import org.cryptomator.jfuse.api.Statvfs;
import org.cryptomator.jfuse.mac.extr.statvfs;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Named;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Stream;

public class StatvfsImplTest {

@DisplayName("test getters")
@ParameterizedTest(name = "{1}")
@MethodSource
public void testGetters(SetInMemorySegment<Number> setter, GetInStatvfs<Number> getter, Number value, long expected) {
try (var scope = MemorySession.openConfined()) {
var segment = statvfs.allocate(scope);
var statvfs = new StatvfsImpl(segment.address(), scope);

setter.accept(segment, value);

Assertions.assertEquals(expected, getter.apply(statvfs).longValue());
}
}

public static Stream<Arguments> testGetters() {
return Stream.of(
Arguments.arguments((SetInMemorySegment<Long>) statvfs::f_bsize$set, Named.of("getBsize()", (GetInStatvfs<Long>) Statvfs::getBsize), 42L, 42L),
Arguments.arguments((SetInMemorySegment<Long>) statvfs::f_frsize$set, Named.of("getFrsize()", (GetInStatvfs<Long>) Statvfs::getFrsize), 42L, 42L),
Arguments.arguments((SetInMemorySegment<Long>) statvfs::f_namemax$set, Named.of("getNameMax()", (GetInStatvfs<Long>) Statvfs::getNameMax), 42L, 42L),

Arguments.arguments((SetInMemorySegment<Integer>) statvfs::f_blocks$set, Named.of("getBlocks() with memory containing value < INT32", (GetInStatvfs<Long>) Statvfs::getBlocks), 42, 42L),
Arguments.arguments((SetInMemorySegment<Integer>) statvfs::f_bfree$set, Named.of("getBfree() with memory containing value < INT32", (GetInStatvfs<Long>) Statvfs::getBfree), 42, 42L),
Arguments.arguments((SetInMemorySegment<Integer>) statvfs::f_bavail$set, Named.of("getBavail() with memory containing value < INT32", (GetInStatvfs<Long>) Statvfs::getBavail), 42, 42L),

Arguments.arguments((SetInMemorySegment<Integer>) statvfs::f_blocks$set, Named.of("getBlocks() with memory containing value < UINT32", (GetInStatvfs<Long>) Statvfs::getBlocks), 0xFFFFFFD6, 0x00000000_FFFFFFD6L),
Arguments.arguments((SetInMemorySegment<Integer>) statvfs::f_bfree$set, Named.of("getBfree() with memory containing value < UINT32", (GetInStatvfs<Long>) Statvfs::getBfree), 0xFFFFFFD6, 0x00000000_FFFFFFD6L),
Arguments.arguments((SetInMemorySegment<Integer>) statvfs::f_bavail$set, Named.of("getBavail() with memory containing value < UINT32", (GetInStatvfs<Long>) Statvfs::getBavail), 0xFFFFFFD6, 0x00000000_FFFFFFD6L)
);
}

private interface SetInMemorySegment<T> extends BiConsumer<MemorySegment, T> {
}

private interface GetInStatvfs<T> extends Function<Statvfs, T> {
}

@DisplayName("test setters")
@ParameterizedTest(name = "{0}")
@MethodSource
public void testSetters(SetInStatvfs<Number> setter, GetInMemorySegment<Number> getter, Number value, long expected) {
try (var scope = MemorySession.openConfined()) {
var segment = statvfs.allocate(scope);
var statvfs = new StatvfsImpl(segment.address(), scope);

setter.accept(statvfs, value.longValue());

Assertions.assertEquals(expected, getter.apply(segment).longValue());
}
}

public static Stream<Arguments> testSetters() {
return Stream.of(
Arguments.arguments(Named.of("setBsize()", (SetInStatvfs<Long>) Statvfs::setBsize), (GetInMemorySegment<Long>) statvfs::f_bsize$get, 42L, 42L),
Arguments.arguments(Named.of("setFrsize()", (SetInStatvfs<Long>) Statvfs::setFrsize), (GetInMemorySegment<Long>) statvfs::f_frsize$get, 42L, 42L),
Arguments.arguments(Named.of("setNameMax()", (SetInStatvfs<Long>) Statvfs::setNameMax), (GetInMemorySegment<Long>) statvfs::f_namemax$get, 42L, 42L),

Arguments.arguments(Named.of("setBlocks(i) with i < INT32", (SetInStatvfs<Long>) Statvfs::setBlocks), (GetInMemorySegment<Integer>) statvfs::f_blocks$get, 42, 42),
Arguments.arguments(Named.of("setBfree(i) with i < INT32", (SetInStatvfs<Long>) Statvfs::setBfree), (GetInMemorySegment<Integer>) statvfs::f_bfree$get, 42, 42),
Arguments.arguments(Named.of("setBavail(i) with i < INT32", (SetInStatvfs<Long>) Statvfs::setBavail), (GetInMemorySegment<Integer>) statvfs::f_bavail$get, 42, 42),

Arguments.arguments(Named.of("setBlocks(i) with i > INT32", (SetInStatvfs<Long>) Statvfs::setBlocks), (GetInMemorySegment<Integer>) statvfs::f_blocks$get, 0xFFFFFFD6, 0xFFFFFFD6),
Arguments.arguments(Named.of("setBfree(i) with i > INT32", (SetInStatvfs<Long>) Statvfs::setBfree), (GetInMemorySegment<Integer>) statvfs::f_bfree$get, 0xFFFFFFD6, 0xFFFFFFD6),
Arguments.arguments(Named.of("setBavail(i) with i > INT32", (SetInStatvfs<Long>) Statvfs::setBavail), (GetInMemorySegment<Integer>) statvfs::f_bavail$get, 0xFFFFFFD6, 0xFFFFFFD6),

Arguments.arguments(Named.of("setBlocks(i) with i > UINT32", (SetInStatvfs<Long>) Statvfs::setBlocks), (GetInMemorySegment<Integer>) statvfs::f_blocks$get, 0x01234567_89ABCDEFL, 0xFFFFFFFF),
Arguments.arguments(Named.of("setBfree(i) with i > UINT32", (SetInStatvfs<Long>) Statvfs::setBfree), (GetInMemorySegment<Integer>) statvfs::f_bfree$get, 0x01234567_89ABCDEFL, 0xFFFFFFFF),
Arguments.arguments(Named.of("setBavail(i) with i > UINT32", (SetInStatvfs<Long>) Statvfs::setBavail), (GetInMemorySegment<Integer>) statvfs::f_bavail$get, 0x01234567_89ABCDEFL, 0xFFFFFFFF)
);
}


private interface SetInStatvfs<T> extends BiConsumer<Statvfs, T> {
}

private interface GetInMemorySegment<T> extends Function<MemorySegment, T> {
}
}