Skip to content
This repository has been archived by the owner on Mar 14, 2024. It is now read-only.

Commit

Permalink
Merge branch 'release/1.3.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
infeo committed Sep 22, 2021
2 parents 64f2c57 + 539b25a commit e100551
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 61 deletions.
16 changes: 2 additions & 14 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>dokany-nio-adapter</artifactId>
<version>1.3.2</version>
<version>1.3.3</version>
<description>Access resources at a given NIO path via Dokany.</description>
<name>Dokany-NIO Adapter</name>
<url>https://github.com/cryptomator/dokany-nio-adapter</url>
Expand Down Expand Up @@ -98,19 +98,7 @@
<!-- Testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<artifactId>junit-jupiter</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
Expand Down
49 changes: 35 additions & 14 deletions src/main/java/com/dokany/java/DokanyMount.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
public final class DokanyMount implements Mount {

private static final Logger LOG = LoggerFactory.getLogger(DokanyMount.class);
private static final int MOUNT_TIMEOUT_MILLIS = Integer.getInteger("org.cryptomator.frontend.dokany.mountTimeOut",22500);
private static final int MOUNT_TIMEOUT_MILLIS = Integer.getInteger("org.cryptomator.frontend.dokany.mountTimeOut", 5000);
private static final int ADDITIONAL_TIMEOUT_MILLIS = 5000;
private static final AtomicInteger MOUNT_COUNTER = new AtomicInteger(1);

private final DeviceOptions deviceOptions;
Expand All @@ -48,7 +49,7 @@ public DokanyMount(final DeviceOptions deviceOptions, final DokanyFileSystem fil
* @return
* @see {@link NativeMethods#DokanDriverVersion()}
*/
public long getDriverVersion() {
public static long getDriverVersion() {
return NativeMethods.DokanDriverVersion();
}

Expand All @@ -58,7 +59,7 @@ public long getDriverVersion() {
* @return
* @see {@link NativeMethods#DokanVersion()}
*/
public long getVersion() {
public static long getVersion() {
return NativeMethods.DokanVersion();
}

Expand All @@ -84,10 +85,8 @@ public synchronized void mount(Consumer<Throwable> onDokanExit) throws DokanyExc
if (!isMounted.getAndSet(true)) {
int mountId = MOUNT_COUNTER.getAndIncrement();
try {
checkReportedVersions();
Runtime.getRuntime().addShutdownHook(new Thread(this::close));

LOG.info("Dokany API/driver version: {} / {}", getVersion(), getDriverVersion());

//real mount op
CountDownLatch mountSuccessSignal = new CountDownLatch(1);
AtomicReference<Throwable> exception = new AtomicReference<>();
Expand All @@ -109,17 +108,17 @@ public synchronized void mount(Consumer<Throwable> onDokanExit) throws DokanyExc
mountThread.start();

// wait for mounted() is called, unlocking the barrier
// since Dokany has problems with the execution of the mounted method,
// we do not rely completely on its call and assume after a certain time just a success (probably successful)
if (!mountSuccessSignal.await(MOUNT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
NativeMethods.DokanRemoveMountPoint(deviceOptions.MountPoint);
if (exception.get() != null) {
if( exception.get() instanceof DokanyException) {
throw (DokanyException) exception.get();
} else {
throw new DokanyException(exception.get());
}
checkToChoke(exception.get(), mountThread.isAlive());
LOG.debug("Mount success not signaled after {} milliseconds. Waiting additional {} milliseconds.", MOUNT_TIMEOUT_MILLIS, ADDITIONAL_TIMEOUT_MILLIS);
if (!mountSuccessSignal.await(ADDITIONAL_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
checkToChoke(exception.get(), mountThread.isAlive());
LOG.info("Mount success not signaled after second wait. Assume successful mount.");
}
throw new DokanyException("Mount timed out");
}
return;

} catch (UnsatisfiedLinkError err) {
throw new DokanyException(err);
Expand All @@ -133,6 +132,28 @@ public synchronized void mount(Consumer<Throwable> onDokanExit) throws DokanyExc
}
}

private void checkReportedVersions() throws DokanyException {
var apiVersion = NativeMethods.DokanVersion();
var driverVersion = NativeMethods.DokanDriverVersion();
LOG.info("Dokany API/driver version: {} / {}", getVersion(), getDriverVersion());
if (apiVersion == 0 || driverVersion == 0) {
throw new DokanyException("Dokany not properly installed (Reported versions: " + apiVersion + "/" + driverVersion);
}
}

//visible for testing
void checkToChoke(Throwable e, boolean threadIsAlive) throws DokanyException {
if (e != null) {
if (e instanceof DokanyException) {
throw (DokanyException) e;
} else {
throw new DokanyException(e);
}
} else if (!threadIsAlive) {
throw new DokanyException("Unknown reason of failure.");
}
}

/**
* Unmounts the Dokan device from its mount point. No-op if the device is not mounted.
*/
Expand Down
19 changes: 6 additions & 13 deletions src/main/java/com/dokany/java/constants/DokanOption.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,25 @@ public enum DokanOption implements EnumInteger {
REMOVABLE_DRIVE(32, "Use removable drive"),
MOUNT_MANAGER(64, "Use mount manager"),
CURRENT_SESSION(128, "Mount the drive on current session only"),
FILELOCK_USER_MODE(256, "Enable Lockfile/Unlockfile operations. Otherwise Dokan will take care of it");
FILELOCK_USER_MODE(256, "Enable Lockfile/Unlockfile operations. Otherwise Dokan will take care of it"),
ENABLE_NOTIFICATION_API(512,"Enable DokanNotify-API"),
ENABLE_FCB_GARBAGE_COLLECTION(2048,"Prevents exponentially slow down certain operations caused by filter drivers."),
CASE_SENSITIVE(4096,"Enables case sensitivity"),
ENABLE_UNMOUNT_NETWORK_DRIVE(8192,"Allows unmounting network drives via explorer"),
DISPATCH_DRIVER_LOGS(16384,"Forward driver and volume logs to userland");

private final int mask;
private final String description;
private final boolean isReadonly;

DokanOption(final int i, final String desc) {
mask = i;
description = desc;
// TODO: is this proper logic?
isReadonly = (mask == 8);
}

public static EnumIntegerSet<DokanOption> fromInt(final int value) {
return DokanyUtils.enumSetFromInt(value, values());
}

private DokanOption(final int mask, final String description, final boolean isReadonly) {
this.mask = mask;
this.description = description;
this.isReadonly = isReadonly;
}

public int getMask() {
return this.mask;
}
Expand All @@ -43,7 +39,4 @@ public String getDescription() {
return this.description;
}

public boolean isReadonly() {
return this.isReadonly;
}
}
40 changes: 20 additions & 20 deletions src/main/java/org/cryptomator/frontend/dokany/MountUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* <item>allocation-unit-size -- Allocation Unit Size of the volume. This will affect the file size.</item>
* <item>sector-size -- Sector Size of the volume. This will affect the file size.</item>
* <item>timeout -- Maximum timeout in milliseconds of each request before Dokany gives up to wait events to complete.</item>
* <item>options -- Features enabled for the mount given as a comma separated list without whitespaces. Supported features are DEBUG_MODE, STD_ERR_OUTPUT, MOUNT_MANAGER, CURRENT_SESSION, REMOVABLE_DRIVE and WRITE_PROTECTION. For their description see the Dokany API documentation. </item>
* <item>options -- Features enabled for the mount given as a comma separated list without whitespaces. Supported features are DEBUG_MODE, STD_ERR_OUTPUT, MOUNT_MANAGER, CURRENT_SESSION, REMOVABLE_DRIVE, WRITE_PROTECTION and DISPATCH_DRIVER_LOGS. For their description see the Dokany API documentation. </item>
* </li>
*/
public class MountUtil {
Expand All @@ -48,22 +48,22 @@ public class MountUtil {
OPTIONS.addOption(null, allocationUnitSizeString, true, "Allocation Unit Size of the volume. This will affect the file size.");
OPTIONS.addOption(null, sectorSizeName, true, "Sector Size of the volume. This will affect the file size.");
OPTIONS.addOption(null, timeoutName, true, "Maximum timeout in milliseconds of each request before Dokany gives up to wait events to complete.");
OPTIONS.addOption(Option.builder()
.argName("arg1,arg2,...")
.longOpt(optionsName)
.hasArgs()
.valueSeparator(',')
.desc("Features enabled for the mount")
OPTIONS.addOption(Option.builder() //
.argName("arg1,arg2,...") //
.longOpt(optionsName) //
.hasArgs() //
.valueSeparator(',') //
.desc("Features enabled for the mount") //
.build());
}

private static final EnumIntegerSet<DokanOption> POSSIBLY_SUPPORTED_DOKAN_OPTIONS = new EnumIntegerSet(
DEBUG_MODE,
STD_ERR_OUTPUT,
MOUNT_MANAGER,
CURRENT_SESSION,
REMOVABLE_DRIVE,
WRITE_PROTECTION);
private static final EnumIntegerSet<DokanOption> POSSIBLY_SUPPORTED_DOKAN_OPTIONS = new EnumIntegerSet(DEBUG_MODE, //
STD_ERR_OUTPUT, //
MOUNT_MANAGER, //
CURRENT_SESSION, //
REMOVABLE_DRIVE, //
WRITE_PROTECTION, //
DISPATCH_DRIVER_LOGS);

public static class MountOptions {

Expand Down Expand Up @@ -173,12 +173,12 @@ public static MountOptions parse(String argsString) throws ParseException, Illeg
builder.addTimeout(Integer.parseInt(cmd.getOptionValue(timeoutName)));
}
if (cmd.hasOption(optionsName)) {
builder.addDokanOptions(
Arrays.stream(cmd.getOptionValues(optionsName))
.filter(s -> !s.isEmpty())
.map(String::trim)
.map(MountUtil::convertAndCheck)
.collect(Collectors.toList()));
builder.addDokanOptions(Arrays.stream(cmd.getOptionValues(optionsName)) //
.filter(s -> !s.isEmpty()) //
.map(String::trim) //
.map(MountUtil::convertAndCheck) //
.collect(Collectors.toList()) //
);

}
return builder.build();
Expand Down
32 changes: 32 additions & 0 deletions src/test/java/com/dokany/java/DokanyMountTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.dokany.java;

import com.dokany.java.structure.DeviceOptions;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class DokanyMountTest {

DokanyFileSystem fs;
DeviceOptions options;
DokanyMount mount;

@BeforeEach
public void beforeEach() {
options = Mockito.mock(DeviceOptions.class);
fs = Mockito.mock(DokanyFileSystem.class);
mount = new DokanyMount(options, fs);
}

@Test
public void testCheckToChoke() throws DokanyException {
Assertions.assertAll( //
() -> Assertions.assertThrows(DokanyException.class, () -> mount.checkToChoke(new Exception(), true)), //
() -> Assertions.assertThrows(DokanyException.class, () -> mount.checkToChoke(null, false)), //
() -> Assertions.assertThrows(DokanyException.class, () -> mount.checkToChoke(new Exception(), true)), //
() -> Assertions.assertDoesNotThrow(() -> mount.checkToChoke(null, true)) //
);
}

}

0 comments on commit e100551

Please sign in to comment.