- determine available space in NIO file system (fixes #97)

- mount volumes via Finder, not via shell script. this makes creating volumes manually unnecessary
This commit is contained in:
Sebastian Stenzel
2016-02-23 21:52:27 +01:00
parent 7cb435e517
commit 2ae5abfc0a
4 changed files with 80 additions and 31 deletions

View File

@@ -1,5 +1,7 @@
package org.cryptomator.filesystem.nio;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
@@ -18,14 +20,25 @@ public class NioFileSystem extends NioFolder implements FileSystem {
@Override
public Optional<Long> quotaUsedBytes() {
// TODO du -sh
return Optional.empty();
try {
long availableBytes = Files.getFileStore(path).getUsableSpace();
long totalBytes = Files.getFileStore(path).getTotalSpace();
return Optional.of(totalBytes - availableBytes);
} catch (IOException e) {
e.printStackTrace();
return Optional.empty();
}
}
@Override
public Optional<Long> quotaAvailableBytes() {
// TODO df -lh
return Optional.empty();
try {
long availableBytes = Files.getFileStore(path).getUsableSpace();
return Optional.of(availableBytes);
} catch (IOException e) {
e.printStackTrace();
return Optional.empty();
}
}
}

View File

@@ -19,7 +19,7 @@ import org.cryptomator.filesystem.delegating.DelegatingFile;
import org.cryptomator.filesystem.delegating.DelegatingReadableFile;
import org.cryptomator.filesystem.delegating.DelegatingWritableFile;
public class StatsFile extends DelegatingFile<StatsFolder> {
class StatsFile extends DelegatingFile<StatsFolder> {
private final Consumer<Long> readCounter;
private final Consumer<Long> writeCounter;

View File

@@ -14,7 +14,7 @@ import org.cryptomator.filesystem.File;
import org.cryptomator.filesystem.Folder;
import org.cryptomator.filesystem.delegating.DelegatingFolder;
public class StatsFolder extends DelegatingFolder<StatsFolder, StatsFile> {
class StatsFolder extends DelegatingFolder<StatsFolder, StatsFile> {
private final Consumer<Long> readCounter;
private final Consumer<Long> writeCounter;

View File

@@ -9,20 +9,21 @@
******************************************************************************/
package org.cryptomator.frontend.webdav.mount;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.frontend.CommandFailedException;
import org.cryptomator.frontend.Frontend.MountParam;
import org.cryptomator.frontend.webdav.mount.command.Script;
@Singleton
final class MacOsXWebDavMounter implements WebDavMounterStrategy {
@@ -43,42 +44,77 @@ final class MacOsXWebDavMounter implements WebDavMounterStrategy {
@Override
public WebDavMount mount(URI uri, Map<MountParam, Optional<String>> mountParams) throws CommandFailedException {
final String mountName = mountParams.get(MountParam.MOUNT_NAME).orElseThrow(() -> {
return new IllegalArgumentException("Missing mount parameter MOUNT_NAME.");
});
// we don't use the uri to derive a path, as it *could* be longer than 255 chars.
final String path = "/Volumes/Cryptomator_" + UUID.randomUUID().toString();
final Script mountScript = Script.fromLines("mkdir \"$MOUNT_PATH\"", "mount_webdav -S -v $MOUNT_NAME \"$DAV_AUTHORITY$DAV_PATH\" \"$MOUNT_PATH\"").addEnv("DAV_AUTHORITY", uri.getRawAuthority())
.addEnv("DAV_PATH", uri.getRawPath()).addEnv("MOUNT_PATH", path).addEnv("MOUNT_NAME", mountName);
mountScript.execute();
return new MacWebDavMount(path);
try {
String mountAppleScript = String.format("mount volume \"%s\"", uri.toString());
ProcessBuilder mount = new ProcessBuilder("/usr/bin/osascript", "-e", mountAppleScript);
Process mountProcess = mount.start();
String stdout = IOUtils.toString(mountProcess.getInputStream(), StandardCharsets.UTF_8);
waitForProcessAndCheckSuccess(mountProcess, 1, TimeUnit.SECONDS);
String volumeIdentifier = StringUtils.trim(StringUtils.removeStart(stdout, "file "));
String waitAppleScript1 = String.format("tell application \"Finder\" to repeat while not (\"%s\" exists)", volumeIdentifier);
String waitAppleScript2 = "delay 0.1";
String waitAppleScript3 = "end repeat";
ProcessBuilder wait = new ProcessBuilder("/usr/bin/osascript", "-e", waitAppleScript1, "-e", waitAppleScript2, "-e", waitAppleScript3);
Process waitProcess = wait.start();
waitForProcessAndCheckSuccess(waitProcess, 5, TimeUnit.SECONDS);
return new MacWebDavMount(volumeIdentifier);
} catch (IOException e) {
throw new CommandFailedException(e);
}
}
private static class MacWebDavMount extends AbstractWebDavMount {
private final String mountPath;
private final Script revealScript;
private final Script unmountScript;
private final ProcessBuilder revealCommand;
private final ProcessBuilder unmountCommand;
private MacWebDavMount(String mountPath) {
this.mountPath = mountPath;
this.revealScript = Script.fromLines("open \"$MOUNT_PATH\"").addEnv("MOUNT_PATH", mountPath);
this.unmountScript = Script.fromLines("diskutil umount $MOUNT_PATH").addEnv("MOUNT_PATH", mountPath);
private MacWebDavMount(String volumeIdentifier) {
String openAppleScript = String.format("tell application \"Finder\" to open \"%s\"", volumeIdentifier);
String activateAppleScript = String.format("tell application \"Finder\" to activate \"%s\"", volumeIdentifier);
String ejectAppleScript = String.format("tell application \"Finder\" to if \"%s\" exists then eject \"%s\"", volumeIdentifier, volumeIdentifier);
System.err.println("open: " + openAppleScript + "\nactivate: " + activateAppleScript + "\neject: " + ejectAppleScript);
this.revealCommand = new ProcessBuilder("/usr/bin/osascript", "-e", openAppleScript, "-e", activateAppleScript);
this.unmountCommand = new ProcessBuilder("/usr/bin/osascript", "-e", ejectAppleScript);
}
@Override
public void unmount() throws CommandFailedException {
// only attempt unmount if user didn't unmount manually:
if (Files.exists(FileSystems.getDefault().getPath(mountPath))) {
unmountScript.execute();
try {
Process proc = unmountCommand.start();
waitForProcessAndCheckSuccess(proc, 1, TimeUnit.SECONDS);
} catch (IOException e) {
throw new CommandFailedException(e);
}
}
@Override
public void reveal() throws CommandFailedException {
revealScript.execute();
try {
Process proc = revealCommand.start();
waitForProcessAndCheckSuccess(proc, 1, TimeUnit.SECONDS);
} catch (IOException e) {
throw new CommandFailedException(e);
}
}
}
private static void waitForProcessAndCheckSuccess(Process proc, long timeout, TimeUnit unit) throws CommandFailedException, IOException {
try {
boolean finishedInTime = proc.waitFor(timeout, unit);
if (!finishedInTime) {
proc.destroyForcibly();
throw new CommandFailedException("Command timed out.");
}
int exitCode = proc.exitValue();
if (exitCode != 0) {
String error = IOUtils.toString(proc.getErrorStream(), StandardCharsets.UTF_8);
throw new CommandFailedException("Command failed with exit code " + exitCode + ". Stderr: " + error);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}