Skip to content

Commit

Permalink
Merge branch 'release/1.3.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
infeo committed Apr 15, 2021
2 parents 72227db + 0eaa306 commit 1e06aeb
Show file tree
Hide file tree
Showing 17 changed files with 189 additions and 100 deletions.
2 changes: 1 addition & 1 deletion 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>fuse-nio-adapter</artifactId>
<version>1.3.0</version>
<version>1.3.1</version>
<name>FUSE-NIO-Adapter</name>
<description>Access resources at a given NIO path via FUSE.</description>
<url>https://github.com/cryptomator/fuse-nio-adapter</url>
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/cryptomator/frontend/fuse/FuseNioAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import ru.serce.jnrfuse.FuseFS;

import java.util.concurrent.TimeoutException;

public interface FuseNioAdapter extends FuseFS, AutoCloseable {

boolean isMounted();
Expand All @@ -24,4 +26,14 @@ public interface FuseNioAdapter extends FuseFS, AutoCloseable {
* Allows custom unmount implementations to prevent subsequent invocations of {@link #umount()} to run into illegal states.
*/
void setUnmounted();

/**
* If the init() callback of fuse_operations is implemented, this method blocks until it is called or a specified timeout is hit. Otherwise returns directly.
*
* @param timeOutMillis the timeout in milliseconds to wait until the init() call
* @throws InterruptedException If the waiting thread is interrupted.
* @throws TimeoutException If the waiting thread waits longer than the specified {@code timeout}.
*/
void awaitInitCall(long timeOutMillis) throws InterruptedException, TimeoutException;

}
18 changes: 18 additions & 0 deletions src/main/java/org/cryptomator/frontend/fuse/ReadOnlyAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BooleanSupplier;

/**
Expand All @@ -59,6 +62,7 @@ public class ReadOnlyAdapter extends FuseStubFS implements FuseNioAdapter {
private final ReadOnlyLinkHandler linkHandler;
private final FileAttributesUtil attrUtil;
private final BooleanSupplier hasOpenFiles;
private final CountDownLatch initSignaler;

@Inject
public ReadOnlyAdapter(@Named("root") Path root, @Named("maxFileNameLength") int maxFileNameLength, FileNameTranscoder fileNameTranscoder, FileStore fileStore, LockManager lockManager, ReadOnlyDirectoryHandler dirHandler, ReadOnlyFileHandler fileHandler, ReadOnlyLinkHandler linkHandler, FileAttributesUtil attrUtil, OpenFileFactory fileFactory) {
Expand All @@ -72,6 +76,7 @@ public ReadOnlyAdapter(@Named("root") Path root, @Named("maxFileNameLength") int
this.linkHandler = linkHandler;
this.attrUtil = attrUtil;
this.hasOpenFiles = () -> fileFactory.getOpenFileCount() != 0;
this.initSignaler = new CountDownLatch(1);
}

protected Path resolvePath(String absolutePath) {
Expand Down Expand Up @@ -250,6 +255,12 @@ public int release(String path, FuseFileInfo fi) {
}
}

@Override
public Pointer init(Pointer p) {
initSignaler.countDown();
return p;
}

@Override
public void destroy(Pointer initResult) {
try {
Expand All @@ -273,6 +284,13 @@ public boolean isInUse() {
}
}

@Override
public void awaitInitCall(long timeoutMillis) throws InterruptedException, TimeoutException {
if (!initSignaler.await(timeoutMillis, TimeUnit.MILLISECONDS)) {
throw new TimeoutException("fuse init() not called after " + timeoutMillis + " milliseconds.");
}
}

@Override
public void setUnmounted() {
if (mounted.compareAndSet(true, false)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public int symlink(String targetPath, String linkPath) {
try (PathLock pathLock = lockManager.createPathLock(linkPath).forWriting();
DataLock dataLock = pathLock.lockDataForWriting()) {
Path link = resolvePath(fileNameTranscoder.fuseToNio(linkPath));
Path target = resolvePath(fileNameTranscoder.fuseToNio(targetPath));
Path target = link.getFileSystem().getPath(fileNameTranscoder.fuseToNio(targetPath));
LOG.trace("symlink {} -> {}", linkPath, targetPath);
Files.createSymbolicLink(link, target);
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,32 +28,32 @@ public void reveal(Revealer revealer) throws Exception {
}

@Override
public void unmount() throws CommandFailedException {
public void unmount() throws FuseMountException {
if (fuseAdapter.isInUse()) {
throw new CommandFailedException("Unmount refused: There are open files or pending operations.");
throw new FuseMountException("Unmount refused: There are open files or pending operations.");
}

unmountInternal();
}

@Override
public void unmountForced() throws CommandFailedException {
public void unmountForced() throws FuseMountException {
unmountForcedInternal();
}

protected abstract void unmountInternal() throws CommandFailedException;
protected abstract void unmountInternal() throws FuseMountException;

protected abstract void unmountForcedInternal() throws CommandFailedException;
protected abstract void unmountForcedInternal() throws FuseMountException;

@Override
public void close() throws CommandFailedException {
public void close() throws FuseMountException {
if (this.fuseAdapter.isMounted()) {
throw new IllegalStateException("Can not close file system adapter while still mounted.");
}
try {
this.fuseAdapter.close();
} catch (Exception e) {
throw new CommandFailedException(e);
throw new FuseMountException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.cryptomator.frontend.fuse.mount;

import org.cryptomator.frontend.fuse.AdapterFactory;
import org.cryptomator.frontend.fuse.FuseNioAdapter;

import java.nio.file.Path;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

public abstract class AbstractMounter implements Mounter {

private static final int MOUNT_TIMEOUT_MILLIS = 10000;
private static final AtomicInteger MOUNT_COUNTER = new AtomicInteger(0);

@Override
public synchronized Mount mount(Path directory, EnvironmentVariables envVars, Consumer<Throwable> onFuseExit, boolean debug) throws FuseMountException {
AtomicReference<Throwable> exception = new AtomicReference<>();
FuseNioAdapter fuseAdapter = AdapterFactory.createReadWriteAdapter(directory, //
AdapterFactory.DEFAULT_MAX_FILENAMELENGTH, //
envVars.getFileNameTranscoder());
//real mount op
var mountThread = new Thread(() -> {
try {
fuseAdapter.mount(envVars.getMountPoint(), true, debug, envVars.getFuseFlags());
} catch (Exception e) {
exception.set(e);
} finally {
onFuseExit.accept(exception.get());
}
});
mountThread.setName("fuseMount-" + MOUNT_COUNTER.getAndIncrement() + "-main");
mountThread.setDaemon(true);
mountThread.start();

// wait for mounted() is called, unlocking the barrier
try {
fuseAdapter.awaitInitCall(MOUNT_TIMEOUT_MILLIS);
return createMountObject(fuseAdapter, envVars);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new FuseMountException("Mounting operation interrupted.");
} catch (TimeoutException e) {
if (exception.get() != null) {
throw new FuseMountException(exception.get());
} else {
throw new FuseMountException(e);
}
}
}

@Override
public abstract String[] defaultMountFlags();

@Override
public abstract boolean isApplicable();

protected abstract Mount createMountObject(FuseNioAdapter fuseNioAdapter, EnvironmentVariables envVars);
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.cryptomator.frontend.fuse.mount;

public class FuseMountException extends Exception {

public FuseMountException(String message) {
super(message);
}

public FuseMountException(Throwable cause) {
super(cause);
}

}
31 changes: 11 additions & 20 deletions src/main/java/org/cryptomator/frontend/fuse/mount/LinuxMounter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.cryptomator.frontend.fuse.mount;

import org.cryptomator.frontend.fuse.AdapterFactory;
import org.cryptomator.frontend.fuse.FuseNioAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -13,25 +12,12 @@
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;

class LinuxMounter implements Mounter {
class LinuxMounter extends AbstractMounter {

private static final Logger LOG = LoggerFactory.getLogger(LinuxMounter.class);
private static final boolean IS_LINUX = System.getProperty("os.name").toLowerCase().contains("linux");
private static final Path USER_HOME = Paths.get(System.getProperty("user.home"));

@Override
public synchronized Mount mount(Path directory, boolean blocking, boolean debug, EnvironmentVariables envVars) throws CommandFailedException {
FuseNioAdapter fuseAdapter = AdapterFactory.createReadWriteAdapter(directory, //
AdapterFactory.DEFAULT_MAX_FILENAMELENGTH, //
envVars.getFileNameTranscoder());
try {
fuseAdapter.mount(envVars.getMountPoint(), blocking, debug, envVars.getFuseFlags());
} catch (RuntimeException e) {
throw new CommandFailedException(e);
}
return new LinuxMount(fuseAdapter, envVars);
}

@Override
public String[] defaultMountFlags() {
try {
Expand All @@ -50,14 +36,19 @@ public boolean isApplicable() {
return IS_LINUX;
}

@Override
protected Mount createMountObject(FuseNioAdapter fuseNioAdapter, EnvironmentVariables envVars) {
return new LinuxMount(fuseNioAdapter, envVars);
}

private static class LinuxMount extends AbstractMount {

private LinuxMount(FuseNioAdapter fuseAdapter, EnvironmentVariables envVars) {
super(fuseAdapter, envVars.getMountPoint());
}

@Override
public void unmountInternal() throws CommandFailedException {
public void unmountInternal() throws FuseMountException {
if (!fuseAdapter.isMounted()) {
return;
}
Expand All @@ -69,7 +60,7 @@ public void unmountInternal() throws CommandFailedException {
}

@Override
public void unmountForcedInternal() throws CommandFailedException {
public void unmountForcedInternal() throws FuseMountException {
if (!fuseAdapter.isMounted()) {
return;
}
Expand All @@ -80,7 +71,7 @@ public void unmountForcedInternal() throws CommandFailedException {
fuseAdapter.setUnmounted();
}

private void assertUmountSucceeded(Process proc) throws CommandFailedException {
private void assertUmountSucceeded(Process proc) throws FuseMountException {
if (proc.exitValue() == 0) {
return;
}
Expand All @@ -90,10 +81,10 @@ private void assertUmountSucceeded(Process proc) throws CommandFailedException {
LOG.info("Already unmounted");
return;
} else {
throw new CommandFailedException("Unmount failed. STDERR: " + stderr);
throw new FuseMountException("Unmount failed. STDERR: " + stderr);
}
} catch (IOException e) {
throw new CommandFailedException(e);
throw new FuseMountException(e);
}
}
}
Expand Down
31 changes: 11 additions & 20 deletions src/main/java/org/cryptomator/frontend/fuse/mount/MacMounter.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.cryptomator.frontend.fuse.mount;

import org.cryptomator.frontend.fuse.AdapterFactory;
import org.cryptomator.frontend.fuse.FileNameTranscoder;
import org.cryptomator.frontend.fuse.FuseNioAdapter;
import org.slf4j.Logger;
Expand Down Expand Up @@ -30,7 +29,7 @@
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

class MacMounter implements Mounter {
class MacMounter extends AbstractMounter {

private static final Logger LOG = LoggerFactory.getLogger(MacMounter.class);
private static final boolean IS_MAC = System.getProperty("os.name").toLowerCase().contains("mac");
Expand All @@ -40,19 +39,6 @@ class MacMounter implements Mounter {
private static final String OSXFUSE_VERSIONFILE_XPATH = "/plist/dict/key[.='CFBundleShortVersionString']/following-sibling::string[1]";
private static final String PLIST_DTD_URL = "http://www.apple.com/DTDs/PropertyList-1.0.dtd";

@Override
public synchronized Mount mount(Path directory, boolean blocking, boolean debug, EnvironmentVariables envVars) throws CommandFailedException {
FuseNioAdapter fuseAdapter = AdapterFactory.createReadWriteAdapter(directory, //
AdapterFactory.DEFAULT_MAX_FILENAMELENGTH, //
envVars.getFileNameTranscoder());
try {
fuseAdapter.mount(envVars.getMountPoint(), blocking, debug, envVars.getFuseFlags());
} catch (RuntimeException e) {
throw new CommandFailedException(e);
}
return new MacMount(fuseAdapter, envVars);
}

@Override
public String[] defaultMountFlags() {
// see: https://github.com/osxfuse/osxfuse/wiki/Mount-options
Expand Down Expand Up @@ -85,6 +71,11 @@ public boolean isApplicable() {
// && installedVersionSupported(); // FIXME: #52
}

@Override
protected Mount createMountObject(FuseNioAdapter fuseNioAdapter, EnvironmentVariables envVars) {
return new MacMount(fuseNioAdapter, envVars);
}

public boolean installedVersionSupported() {
String versionString = getVersionString();
if (versionString == null) {
Expand Down Expand Up @@ -152,7 +143,7 @@ private MacMount(FuseNioAdapter fuseAdapter, EnvironmentVariables envVars) {
}

@Override
public void unmountInternal() throws CommandFailedException {
public void unmountInternal() throws FuseMountException {
if (!fuseAdapter.isMounted()) {
return;
}
Expand All @@ -164,7 +155,7 @@ public void unmountInternal() throws CommandFailedException {
}

@Override
public void unmountForcedInternal() throws CommandFailedException {
public void unmountForcedInternal() throws FuseMountException {
if (!fuseAdapter.isMounted()) {
return;
}
Expand All @@ -175,7 +166,7 @@ public void unmountForcedInternal() throws CommandFailedException {
fuseAdapter.setUnmounted();
}

private void assertUmountSucceeded(Process proc) throws CommandFailedException {
private void assertUmountSucceeded(Process proc) throws FuseMountException {
if (proc.exitValue() == 0) {
return;
}
Expand All @@ -185,10 +176,10 @@ private void assertUmountSucceeded(Process proc) throws CommandFailedException {
LOG.info("Already unmounted");
return;
} else {
throw new CommandFailedException("Unmount failed. STDERR: " + stderr);
throw new FuseMountException("Unmount failed. STDERR: " + stderr);
}
} catch (IOException e) {
throw new CommandFailedException(e);
throw new FuseMountException(e);
}
}

Expand Down
Loading

0 comments on commit 1e06aeb

Please sign in to comment.