Skip to content

Commit

Permalink
Merge branch 'release/1.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
infeo committed Mar 30, 2021
2 parents 64b3811 + 8367931 commit 72227db
Show file tree
Hide file tree
Showing 21 changed files with 376 additions and 65 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/publish-github.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ jobs:
SLACK_ICON_EMOJI: ':bot:'
SLACK_CHANNEL: 'cryptomator-desktop'
SLACK_TITLE: "Published ${{ github.event.repository.name }} ${{ github.event.release.tag_name }}"
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions?query=workflow%3A%22Publish+to+Maven+Central%22|deploy to Maven Central>."
SLACK_MESSAGE: "Ready to <https://github.com/${{ github.repository }}/actions/workflows/publish-central.yml|deploy to Maven Central>."
SLACK_FOOTER:
MSG_MINIMAL: true
MSG_MINIMAL: true
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![Build Status](https://github.com/cryptomator/fuse-nio-adapter/workflows/Build/badge.svg)](https://github.com/cryptomator/fuse-nio-adapter/actions?query=workflow%3ABuild)
[![Codacy Code Quality](https://app.codacy.com/project/badge/Grade/47914e82b4c54f39b6150c24b83d7d09)](https://www.codacy.com/gh/cryptomator/fuse-nio-adapter)
[![Codacy Coverage](https://app.codacy.com/project/badge/Coverage/47914e82b4c54f39b6150c24b83d7d09)](https://www.codacy.com/gh/cryptomator/fuse-nio-adapter)
[![Codacy Code Quality](https://app.codacy.com/project/badge/Grade/47914e82b4c54f39b6150c24b83d7d09)](https://www.codacy.com/gh/cryptomator/fuse-nio-adapter/dashboard)
[![Codacy Coverage](https://app.codacy.com/project/badge/Coverage/47914e82b4c54f39b6150c24b83d7d09)](https://www.codacy.com/gh/cryptomator/fuse-nio-adapter/dashboard)
[![Known Vulnerabilities](https://snyk.io/test/github/cryptomator/fuse-nio-adapter/badge.svg)](https://snyk.io/test/github/cryptomator/fuse-nio-adapter)

# fuse-nio-adapter
Expand Down
4 changes: 2 additions & 2 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>fuse-nio-adapter</artifactId>
<version>1.2.9</version>
<version>1.3.0</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 Expand Up @@ -183,7 +183,7 @@
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>6.1.0</version>
<version>6.1.2</version>
<configuration>
<cveValidForHours>24</cveValidForHours>
<failBuildOnCVSS>0</failBuildOnCVSS>
Expand Down
44 changes: 38 additions & 6 deletions src/main/java/org/cryptomator/frontend/fuse/AdapterFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,58 @@

public class AdapterFactory {

private static final int DEFAULT_NAME_MAX = 254; // 255 is preferred, but nautilus checks for this value + 1
/**
* The default value for the maximum supported filename length.
*/
public static final int DEFAULT_MAX_FILENAMELENGTH = 254; // 255 is preferred, but nautilus checks for this value + 1

private AdapterFactory() {
}

/**
* Creates a read-only fuse-nio filesystem with a maximum file name length of {@value DEFAULT_MAX_FILENAMELENGTH} and an assumed filename encoding of UTF-8 NFC for FUSE and the NIO filesystem.
* @param root the root path of the NIO filesystem.
* @return an adapter mapping FUSE callbacks to the nio interface
* @see ReadOnlyAdapter
* @see FileNameTranscoder
*/
public static FuseNioAdapter createReadOnlyAdapter(Path root) {
return createReadOnlyAdapter(root, DEFAULT_NAME_MAX);
return createReadOnlyAdapter(root, DEFAULT_MAX_FILENAMELENGTH, FileNameTranscoder.transcoder() );
}

public static FuseNioAdapter createReadOnlyAdapter(Path root, int maxFileNameLength) {
FuseNioAdapterComponent comp = DaggerFuseNioAdapterComponent.builder().root(root).maxFileNameLength(maxFileNameLength).build();
public static FuseNioAdapter createReadOnlyAdapter(Path root, int maxFileNameLength, FileNameTranscoder fileNameTranscoder) {
FuseNioAdapterComponent comp = DaggerFuseNioAdapterComponent.builder()
.root(root)
.maxFileNameLength(maxFileNameLength)
.fileNameTranscoder(fileNameTranscoder)
.build();
return comp.readOnlyAdapter();
}

/**
* Creates a fuse-nio-filesystem with a maximum file name length of {@value DEFAULT_MAX_FILENAMELENGTH} and an assumed filename encoding of UTF-8 NFC for FUSE and the NIO filesystem.
* @param root the root path of the NIO filesystem.
* @return an adapter mapping FUSE callbacks to the nio interface
* @see ReadWriteAdapter
* @see FileNameTranscoder
*/
public static FuseNioAdapter createReadWriteAdapter(Path root) {
return createReadWriteAdapter(root, DEFAULT_NAME_MAX);
return createReadWriteAdapter(root, DEFAULT_MAX_FILENAMELENGTH);
}

/**
* Creates a fuse-nio-filesystem with an assumed filename encoding of UTF-8 NFC for FUSE and the NIO filesystem.
* @param root the root path of the NIO filesystem.
* @return an adapter mapping FUSE callbacks to the nio interface
* @see ReadWriteAdapter
* @see FileNameTranscoder
*/
public static FuseNioAdapter createReadWriteAdapter(Path root, int maxFileNameLength) {
FuseNioAdapterComponent comp = DaggerFuseNioAdapterComponent.builder().root(root).maxFileNameLength(maxFileNameLength).build();
return createReadWriteAdapter(root,maxFileNameLength,FileNameTranscoder.transcoder());
}

public static FuseNioAdapter createReadWriteAdapter(Path root, int maxFileNameLength, FileNameTranscoder fileNameTranscoder) {
FuseNioAdapterComponent comp = DaggerFuseNioAdapterComponent.builder().root(root).maxFileNameLength(maxFileNameLength).fileNameTranscoder(fileNameTranscoder).build();
return comp.readWriteAdapter();
}
}
107 changes: 107 additions & 0 deletions src/main/java/org/cryptomator/frontend/fuse/FileNameTranscoder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package org.cryptomator.frontend.fuse;

import com.google.common.base.Preconditions;

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.Normalizer;

/**
* Class to transcode filenames and path components from one encoding to another.
* <p>
* Instances created with {@link FileNameTranscoder#transcoder()} default to fuse and nio UTF-8 encoding with NFC normalization. To change encoding and normalization, use the supplied "withXXX()" methods. If an encoding is not part of the UTF famlily, the normalization is ignored.
*/
public class FileNameTranscoder {

private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private static final Normalizer.Form DEFAULT_NORMALIZATION = Normalizer.Form.NFC;

private final Charset fuseCharset;
private final Charset nioCharset;
private final Normalizer.Form fuseNormalization;
private final Normalizer.Form nioNormalization;
private final boolean fuseCharsetIsUnicode;
private final boolean nioCharsetIsUnicode;

FileNameTranscoder(Charset fuseCharset, Charset nioCharset, Normalizer.Form fuseNormalization, Normalizer.Form nioNormalization) {
this.fuseCharset = Preconditions.checkNotNull(fuseCharset);
this.nioCharset = Preconditions.checkNotNull(nioCharset);
this.fuseNormalization = Preconditions.checkNotNull(fuseNormalization);
this.nioNormalization = Preconditions.checkNotNull(nioNormalization);
this.fuseCharsetIsUnicode = fuseCharset.name().startsWith("UTF");
this.nioCharsetIsUnicode = nioCharset.name().startsWith("UTF");
}

/**
* Transcodes the given NIO file name to FUSE representation.
*
* @param nioFileName A file name encoded with the charset used in NIO
* @return The file name encoded with the charset used by FUSE
*/
public String nioToFuse(String nioFileName) {
return transcode(nioFileName, nioCharset, fuseCharset, nioNormalization, fuseNormalization, fuseCharsetIsUnicode);
}

/**
* Transcodes the given FUSE file name to NIO representation.
*
* @param fuseFileName A file name encoded with the charset used in FUSE
* @return The file name encoded with the charset used by NIO
*/
public String fuseToNio(String fuseFileName) {
return transcode(fuseFileName, fuseCharset, nioCharset, fuseNormalization, nioNormalization, nioCharsetIsUnicode);
}

/**
* Interprets the given string as FUSE character set encoded and returns the original byte sequence.
*
* @param fuseFileName string from the fuse layer
* @return A byte sequence with the original encoding of the input
*/
public ByteBuffer interpretAsFuseString(String fuseFileName) {
return fuseCharset.encode(fuseFileName);
}

/**
* Interprets the given string as NIO character set encoded and returns the original byte sequence.
*
* @param nioFileName string from the nio layer
* @return A byte sequence with the original encoding of the input
*/
public ByteBuffer interpretAsNioString(String nioFileName) {
return nioCharset.encode(nioFileName);
}

private String transcode(String original, Charset srcCharset, Charset dstCharset, Normalizer.Form srcNormalization, Normalizer.Form dstNormalization, boolean applyNormalization) {
String result = original;
if (!srcCharset.equals(dstCharset)) {
result = dstCharset.decode(srcCharset.encode(result)).toString();
}
if (applyNormalization && srcNormalization != dstNormalization) {
result = Normalizer.normalize(result, dstNormalization);
}
return result;
}

/* Builder/Wither */
public FileNameTranscoder withFuseCharset(Charset fuseCharset) {
return new FileNameTranscoder(fuseCharset, nioCharset, fuseNormalization, nioNormalization);
}

public FileNameTranscoder withNioCharset(Charset nioCharset) {
return new FileNameTranscoder(fuseCharset, nioCharset, fuseNormalization, nioNormalization);
}

public FileNameTranscoder withFuseNormalization(Normalizer.Form fuseNormalization) {
return new FileNameTranscoder(fuseCharset, nioCharset, fuseNormalization, nioNormalization);
}

public FileNameTranscoder withNioNormalization(Normalizer.Form nioNormalization) {
return new FileNameTranscoder(fuseCharset, nioCharset, fuseNormalization, nioNormalization);
}

public static FileNameTranscoder transcoder() {
return new FileNameTranscoder(DEFAULT_CHARSET, DEFAULT_CHARSET, DEFAULT_NORMALIZATION, DEFAULT_NORMALIZATION);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ interface Builder {
@BindsInstance
Builder maxFileNameLength(@Named("maxFileNameLength") int maxFileNameLength);

@BindsInstance
Builder fileNameTranscoder(FileNameTranscoder fileNameTranscoder);

FuseNioAdapterComponent build();
}

Expand Down
14 changes: 8 additions & 6 deletions src/main/java/org/cryptomator/frontend/fuse/ReadOnlyAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,18 @@ public class ReadOnlyAdapter extends FuseStubFS implements FuseNioAdapter {
private final int maxFileNameLength;
protected final FileStore fileStore;
protected final LockManager lockManager;
protected final FileNameTranscoder fileNameTranscoder;
private final ReadOnlyDirectoryHandler dirHandler;
private final ReadOnlyFileHandler fileHandler;
private final ReadOnlyLinkHandler linkHandler;
private final FileAttributesUtil attrUtil;
private final BooleanSupplier hasOpenFiles;

@Inject
public ReadOnlyAdapter(@Named("root") Path root, @Named("maxFileNameLength") int maxFileNameLength, FileStore fileStore, LockManager lockManager, ReadOnlyDirectoryHandler dirHandler, ReadOnlyFileHandler fileHandler, ReadOnlyLinkHandler linkHandler, FileAttributesUtil attrUtil, OpenFileFactory fileFactory) {
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) {
this.root = root;
this.maxFileNameLength = maxFileNameLength;
this.fileNameTranscoder = fileNameTranscoder;
this.fileStore = fileStore;
this.lockManager = lockManager;
this.dirHandler = dirHandler;
Expand Down Expand Up @@ -101,7 +103,7 @@ public int statfs(String path, Statvfs stbuf) {
@Override
public int access(String path, int mask) {
try {
Path node = resolvePath(path);
Path node = resolvePath(fileNameTranscoder.fuseToNio(path));
Set<AccessMode> accessModes = attrUtil.accessModeMaskToSet(mask);
return checkAccess(node, accessModes);
} catch (RuntimeException e) {
Expand Down Expand Up @@ -135,7 +137,7 @@ protected int checkAccess(Path path, Set<AccessMode> requiredAccessModes, Set<Ac
public int readlink(String path, Pointer buf, long size) {
try (PathLock pathLock = lockManager.createPathLock(path).forReading();
DataLock dataLock = pathLock.lockDataForReading()) {
Path node = resolvePath(path);
Path node = resolvePath(fileNameTranscoder.fuseToNio(path));
return linkHandler.readlink(node, buf, size);
} catch (NotLinkException | NoSuchFileException e) {
LOG.trace("readlink {} failed, node not found or not a symlink", path);
Expand All @@ -150,7 +152,7 @@ public int readlink(String path, Pointer buf, long size) {
public int getattr(String path, FileStat stat) {
try (PathLock pathLock = lockManager.createPathLock(path).forReading();
DataLock dataLock = pathLock.lockDataForReading()) {
Path node = resolvePath(path);
Path node = resolvePath(fileNameTranscoder.fuseToNio(path));
BasicFileAttributes attrs;
if (fileStore.supportsFileAttributeView(PosixFileAttributeView.class)) {
attrs = Files.readAttributes(node, PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
Expand Down Expand Up @@ -183,7 +185,7 @@ public int getattr(String path, FileStat stat) {
public int readdir(String path, Pointer buf, FuseFillDir filler, @off_t long offset, FuseFileInfo fi) {
try (PathLock pathLock = lockManager.createPathLock(path).forReading();
DataLock dataLock = pathLock.lockDataForReading()) {
Path node = resolvePath(path);
Path node = resolvePath(fileNameTranscoder.fuseToNio(path));
LOG.trace("readdir {}", path);
return dirHandler.readdir(node, buf, filler, offset, fi);
} catch (NotDirectoryException e) {
Expand All @@ -199,7 +201,7 @@ public int readdir(String path, Pointer buf, FuseFillDir filler, @off_t long off
public int open(String path, FuseFileInfo fi) {
try (PathLock pathLock = lockManager.createPathLock(path).forReading();
DataLock dataLock = pathLock.lockDataForReading()) {
Path node = resolvePath(path);
Path node = resolvePath(fileNameTranscoder.fuseToNio(path));
LOG.trace("open {} ({})", path, fi.fh.get());
fileHandler.open(node, fi);
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ public class ReadOnlyDirectoryHandler {
private static final Path SAME_DIR = Paths.get(".");
private static final Path PARENT_DIR = Paths.get("..");
protected final FileAttributesUtil attrUtil;
private final FileNameTranscoder fileNameTranscoder;

@Inject
public ReadOnlyDirectoryHandler(FileAttributesUtil attrUtil) {
public ReadOnlyDirectoryHandler(FileAttributesUtil attrUtil, FileNameTranscoder fileNameTranscoder) {
this.attrUtil = attrUtil;
this.fileNameTranscoder = fileNameTranscoder;
}

public int getattr(Path path, BasicFileAttributes attrs, FileStat stat) {
Expand Down Expand Up @@ -75,7 +77,7 @@ public int readdir(Path path, Pointer buf, FuseFillDir filler, long offset, Fuse
Iterator<Path> iter = Iterators.concat(sameAndParent, ds.iterator());
while (iter.hasNext()) {
String fileName = iter.next().getFileName().toString();
if (filler.apply(buf, fileName, null, 0) != 0) {
if (filler.apply(buf, fileNameTranscoder.nioToFuse(fileName), null, 0) != 0) {
return -ErrorCodes.ENOMEM();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import javax.inject.Inject;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
Expand All @@ -19,10 +19,12 @@ class ReadOnlyLinkHandler {
private static final Logger LOG = LoggerFactory.getLogger(ReadOnlyLinkHandler.class);

private final FileAttributesUtil attrUtil;
private final FileNameTranscoder fileNameTranscoder;

@Inject
public ReadOnlyLinkHandler(FileAttributesUtil attrUtil) {
public ReadOnlyLinkHandler(FileAttributesUtil attrUtil, FileNameTranscoder fileNameTranscoder) {
this.attrUtil = attrUtil;
this.fileNameTranscoder = fileNameTranscoder;
}

public int getattr(Path path, BasicFileAttributes attrs, FileStat stat) {
Expand All @@ -48,10 +50,11 @@ public int getattr(Path path, BasicFileAttributes attrs, FileStat stat) {
*/
public int readlink(Path path, Pointer buf, long size) throws IOException {
Path target = Files.readSymbolicLink(path);
String result = target.toString();
int maxSize = size == 0 ? 0 : (int) size - 1;
buf.putString(0, result, maxSize, StandardCharsets.UTF_8);
buf.putByte(maxSize, (byte) 0x00);
ByteBuffer fuseEncodedTarget = fileNameTranscoder.interpretAsFuseString(fileNameTranscoder.nioToFuse(target.toString()));
int len = (int) Math.min(fuseEncodedTarget.remaining(), size - 1);
assert len < size;
buf.put(0, fuseEncodedTarget.array(), 0, len);
buf.putByte(len, (byte) 0x00); // add null terminator
return 0;
}

Expand Down
Loading

0 comments on commit 72227db

Please sign in to comment.