Skip to content

Commit e190a9a

Browse files
Merge branch 'release/0.1.4'
# Conflicts: # pom.xml
2 parents e4a7c3b + ef4f856 commit e190a9a

23 files changed

+1017
-266
lines changed

.travis.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
language: java
2-
sudo: false
2+
sudo: required
33
jdk:
44
- oraclejdk8
55
env:
@@ -10,6 +10,7 @@ env:
1010
- secure: aLCaSgLfFniEPpiEdvEyFLlak4cTspVE3uqeGFCncPFUyyxPZ0JW+DdyFpvO5DXBa3hr9oS240H6f1T6Eo/J4K5SaKq3gS3yIzbvs2BS5yoCE4hGIZ6yS/70sIhlxvFvujJDT9KPYo8J6KE0w5vqy8BHEMZYBMEDWWvswwrvlqdaoZqe6vaoV1TsOeWeW+2qFdYu5j1KVQgSwOgzMdQuqQVSsrdA1FH+AzmMMbk3QgdGGd1U4MnFStIeG5/YfqVHkUVpZayhYB9yFzUCObT9R5zZ1OtghdOrkX1FRTKbFPAmJouToeFrIqrZEMbaE9PWaajuUZeqL2hQD1s0A+wj65cXjgbQhz4v7Gr0J/+2AU+9N+IRAIguiq6rXtt1HeR3YbBwlxFdwmEgYJjqO7+XFZFNYbr3YPgqbqJbgXpoxeUTdPNdNwckBUEQTTN6fs89Og6wHLDgoZb5niypSKWd/SFCU81FAGQ0mxy41jJOdltxVtG1+UOfb/41PRAzS6br7CpNnaq379kKlMiyOXY4UCWuFgwW4KhlUx0dgidqi2etcYrDZhZbguHmfLRfumEQ8nCp8LJ5FwJWlkmJhE8hFTu3sGmVUl06Ly1gybMPazev8hYjyr3vaexmek7qeqDtNT6n8L96qZkResjFI2pJmzZaNIg2yK92ZS/5v073OgM= # MAVEN_OSSRH_PASSWORD
1111
- secure: JUBj12rP7sEsNp8R3o9Mjwl7HCYKQan58CZ1WDm7L2MteFRDBJr625P4fk4cQOTjR6fb3jiogCD7dqkHoGJQlvi2ReQJLXKBhy3Bqtnzksf4c1By9bLB5NYH6MQV1FFazzAjjPjGlQYJB+kUx+pQ8vxMJC5yzp6vpKWu3vTobEFNtuFAWZq7qM91VJBUc8z+k1awas9vqgDlqWxH+K05L2c+tpnnmqXk9/HN9Z4akkKB++oACenE+w+D9Snyiif9WyhVR3+ZcMtL44YAQDabl6LlrTdM4afNaPcwgOdFuxL7GCZyIMgMP26O8JquK4ZtE2b/ZMz5h0jtE+r6M0E+yVAN+kG7UviNd9kKItiRiokDsaYeNCWVPHndGBtw6GU5GFNJTDhEb/oeqzclI/PaFHXA4O/o4A9N+nrzb28xWaihAM/NymVOE1iNNQfyNqPb9fjsMntNOTDT/sLH3tTJ62nvVPpurUXVV0+jbSrE20xclOZ1xBbMztQwya4EB/0fS+raCiR5spXHTNHpmSp2ubKAuo6V4AUXQXk6LHxiiIvcYSRYVgnBeOcreuDYv7+09xeIejxVcSzh7Nz7aK/0Fkq42ALYs/cDOq0mJGwoJ4yC7vlMj6GQNwZtCP+bzdGM3+cjTcD2F997Hf75lEVeYXK2oNE3/ycSQjdYlc3wTl0= #COVERITY_SCAN_TOKEN
1212
install:
13+
- sudo apt-get install haveged
1314
- mvn dependency:go-offline -Pdependency-check
1415
- mvn dependency:go-offline -Pcoverage
1516
- mvn source:help javadoc:help dependency:go-offline -Prelease
@@ -33,7 +34,6 @@ addons:
3334
branch_pattern: release.*
3435
before_deploy:
3536
- "if ! gpg --list-secret-keys 34C80F11; then gpg --import 34C80F11.gpg; fi"
36-
- "ls -la target"
3737
deploy:
3838
- provider: script # SNAPSHOTS
3939
script: mvn clean deploy -DskipTests -Prelease --settings settings.xml
@@ -56,6 +56,7 @@ deploy:
5656
- "target/dependency-list.txt"
5757
- "target/*.jar"
5858
skip_cleanup: true
59+
prerelease: true
5960
on:
6061
repo: cryptomator/cryptofs
6162
tags: true

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<modelVersion>4.0.0</modelVersion>
33
<groupId>org.cryptomator</groupId>
44
<artifactId>cryptofs</artifactId>
5-
<version>0.1.3</version>
5+
<version>0.1.4</version>
66
<name>Cryptomator Crypto Filesystem</name>
77
<description>This library provides the Java filesystem provider used by Cryptomator.</description>
88
<url>https://github.com/cryptomator/cryptofs</url>
@@ -61,7 +61,7 @@
6161
<dependency>
6262
<groupId>org.cryptomator</groupId>
6363
<artifactId>cryptolib</artifactId>
64-
<version>1.0.2</version>
64+
<version>1.0.4</version>
6565
</dependency>
6666
<dependency>
6767
<groupId>org.apache.commons</groupId>
@@ -71,7 +71,7 @@
7171
<dependency>
7272
<groupId>com.google.guava</groupId>
7373
<artifactId>guava</artifactId>
74-
<version>19.0</version>
74+
<version>20.0</version>
7575
</dependency>
7676
<dependency>
7777
<groupId>commons-codec</groupId>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.cryptomator.cryptofs;
2+
3+
interface BiConsumerThrowingException<A, B, E extends Exception> {
4+
5+
void accept(A a, B b) throws E;
6+
7+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package org.cryptomator.cryptofs;
2+
3+
import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;
4+
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
5+
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
6+
import static java.nio.file.StandardOpenOption.CREATE_NEW;
7+
import static java.nio.file.StandardOpenOption.READ;
8+
import static java.nio.file.StandardOpenOption.WRITE;
9+
10+
import java.io.IOException;
11+
import java.nio.channels.FileChannel;
12+
import java.nio.file.AtomicMoveNotSupportedException;
13+
import java.nio.file.CopyOption;
14+
import java.nio.file.DirectoryStream;
15+
import java.nio.file.FileAlreadyExistsException;
16+
import java.nio.file.NoSuchFileException;
17+
import java.nio.file.Path;
18+
import java.nio.file.attribute.BasicFileAttributeView;
19+
import java.nio.file.attribute.BasicFileAttributes;
20+
import java.nio.file.spi.FileSystemProvider;
21+
import java.util.EnumSet;
22+
import java.util.Optional;
23+
24+
import javax.inject.Inject;
25+
26+
import org.apache.commons.lang3.ArrayUtils;
27+
28+
@PerProvider
29+
class CopyAndMoveOperations {
30+
31+
@Inject
32+
public CopyAndMoveOperations() {
33+
}
34+
35+
public void copy(CryptoPath source, CryptoPath target, CopyOption... options) throws IOException {
36+
if (source.equals(target)) {
37+
return;
38+
}
39+
if (pathsBelongToSameFileSystem(source, target)) {
40+
source.getFileSystem().copy(source, target, options);
41+
} else {
42+
Optional<BasicFileAttributes> sourceAttrs = attributes(source);
43+
Optional<BasicFileAttributes> targetAttrs = attributes(target);
44+
if (!sourceAttrs.isPresent()) {
45+
throw new NoSuchFileException(source.toUri().toString());
46+
}
47+
if (targetAttrs.isPresent()) {
48+
if (ArrayUtils.contains(options, REPLACE_EXISTING)) {
49+
provider(target).delete(target);
50+
} else {
51+
throw new FileAlreadyExistsException(target.toUri().toString());
52+
}
53+
}
54+
if (sourceAttrs.get().isDirectory()) {
55+
provider(target).createDirectory(target);
56+
} else {
57+
try (FileChannel sourceChannel = provider(source).newFileChannel(source, EnumSet.of(READ)); //
58+
FileChannel targetChannel = provider(target).newFileChannel(target, EnumSet.of(CREATE_NEW, WRITE))) {
59+
sourceChannel.transferTo(0, sourceChannel.size(), targetChannel);
60+
}
61+
}
62+
if (ArrayUtils.contains(options, COPY_ATTRIBUTES)) {
63+
BasicFileAttributeView targetAttrView = provider(target).getFileAttributeView(target, BasicFileAttributeView.class);
64+
targetAttrView.setTimes(sourceAttrs.get().lastModifiedTime(), sourceAttrs.get().lastAccessTime(), sourceAttrs.get().creationTime());
65+
}
66+
}
67+
}
68+
69+
private FileSystemProvider provider(CryptoPath path) {
70+
return path.getFileSystem().provider();
71+
}
72+
73+
public void move(CryptoPath source, CryptoPath target, CopyOption... options) throws IOException {
74+
if (source.equals(target)) {
75+
return;
76+
}
77+
if (pathsBelongToSameFileSystem(source, target)) {
78+
source.getFileSystem().move(source, target, options);
79+
} else {
80+
if (ArrayUtils.contains(options, ATOMIC_MOVE)) {
81+
throw new AtomicMoveNotSupportedException(source.toUri().toString(), target.toUri().toString(), "Move of encrypted file to different FileSystem");
82+
}
83+
if (isNonEmptyDirectory(source)) {
84+
throw new IOException("Can not move non empty directory to different FileSystem");
85+
}
86+
boolean success = false;
87+
try {
88+
copy(source, target, addCopyAttributesTo(options));
89+
success = true;
90+
} finally {
91+
if (!success) {
92+
// do a best effort to clean a partially copied file
93+
try {
94+
provider(target).deleteIfExists(target);
95+
} catch (IOException e) {
96+
// ignore
97+
}
98+
}
99+
}
100+
provider(source).deleteIfExists(source);
101+
}
102+
}
103+
104+
private boolean pathsBelongToSameFileSystem(CryptoPath source, CryptoPath target) {
105+
return source.getFileSystem() == target.getFileSystem();
106+
}
107+
108+
private boolean isNonEmptyDirectory(CryptoPath source) throws IOException {
109+
Optional<BasicFileAttributes> sourceAttrs = attributes(source);
110+
if (!sourceAttrs.map(BasicFileAttributes::isDirectory).orElse(false)) {
111+
return false;
112+
}
113+
try (DirectoryStream<Path> contents = provider(source).newDirectoryStream(source, ignored -> true)) {
114+
return contents.iterator().hasNext();
115+
}
116+
}
117+
118+
private Optional<BasicFileAttributes> attributes(CryptoPath path) {
119+
try {
120+
return Optional.of(provider(path).readAttributes(path, BasicFileAttributes.class));
121+
} catch (IOException e) {
122+
return Optional.empty();
123+
}
124+
}
125+
126+
private CopyOption[] addCopyAttributesTo(CopyOption[] options) {
127+
CopyOption[] result = new CopyOption[options.length + 1];
128+
for (int i = 0; i < options.length; i++) {
129+
result[i] = options[i];
130+
}
131+
result[options.length] = COPY_ATTRIBUTES;
132+
return result;
133+
}
134+
135+
}

src/main/java/org/cryptomator/cryptofs/CryptoDirectoryStream.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
*******************************************************************************/
99
package org.cryptomator.cryptofs;
1010

11+
import static org.cryptomator.cryptofs.FinallyUtils.guaranteeInvocationOf;
12+
1113
import java.io.IOException;
1214
import java.io.UncheckedIOException;
1315
import java.nio.charset.StandardCharsets;
@@ -16,6 +18,7 @@
1618
import java.nio.file.Path;
1719
import java.util.Iterator;
1820
import java.util.Objects;
21+
import java.util.function.Consumer;
1922
import java.util.regex.Matcher;
2023
import java.util.regex.Pattern;
2124

@@ -38,8 +41,11 @@ class CryptoDirectoryStream implements DirectoryStream<Path> {
3841
private final FileNameCryptor filenameCryptor;
3942
private final LongFileNameProvider longFileNameProvider;
4043
private final DirectoryStream.Filter<? super Path> filter;
44+
private final Consumer<CryptoDirectoryStream> onClose;
4145

42-
public CryptoDirectoryStream(Directory ciphertextDir, Path cleartextDir, FileNameCryptor filenameCryptor, LongFileNameProvider longFileNameProvider, DirectoryStream.Filter<? super Path> filter) throws IOException {
46+
public CryptoDirectoryStream(Directory ciphertextDir, Path cleartextDir, FileNameCryptor filenameCryptor, LongFileNameProvider longFileNameProvider, DirectoryStream.Filter<? super Path> filter,
47+
Consumer<CryptoDirectoryStream> onClose) throws IOException {
48+
this.onClose = onClose;
4349
this.directoryId = ciphertextDir.dirId;
4450
this.ciphertextDirStream = Files.newDirectoryStream(ciphertextDir.path, p -> true);
4551
LOG.trace("OPEN " + directoryId);
@@ -101,8 +107,10 @@ private boolean isAcceptableByFilter(Path path) {
101107

102108
@Override
103109
public void close() throws IOException {
104-
ciphertextDirStream.close();
105-
LOG.trace("CLOSE " + directoryId);
110+
guaranteeInvocationOf( //
111+
() -> ciphertextDirStream.close(), //
112+
() -> onClose.accept(this), //
113+
() -> LOG.trace("CLOSE " + directoryId));
106114
}
107115

108116
}

0 commit comments

Comments
 (0)