Skip to content

Commit 88aa52a

Browse files
authored
Merge pull request #14431 from iterate-ch/bugfix/MD-18435
Hide directory placeholders only containing hidden files
2 parents 7b7b07d + eb74cf0 commit 88aa52a

26 files changed

+122
-90
lines changed

backblaze/src/main/java/ch/cyberduck/core/b2/B2DeleteFeature.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,17 @@ else if(file.isFile()) {
8484
if(log.isDebugEnabled()) {
8585
log.debug(String.format("Add hide marker %s of %s", file.attributes().getVersionId(), file));
8686
}
87-
session.getClient().hideFile(fileid.getVersionId(containerService.getContainer(file)), containerService.getKey(file));
87+
try {
88+
session.getClient().hideFile(fileid.getVersionId(containerService.getContainer(file)), containerService.getKey(file));
89+
}
90+
catch(B2ApiException e) {
91+
if("already_hidden".equalsIgnoreCase(e.getCode())) {
92+
log.warn(String.format("Ignore failure %s hiding file %s already hidden", e.getMessage(), file));
93+
}
94+
else {
95+
throw e;
96+
}
97+
}
8898
}
8999
else {
90100
// Delete specific version

backblaze/src/main/java/ch/cyberduck/core/b2/B2ExceptionMappingService.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ public BackgroundException map(final B2ApiException e) {
7979
if("bad_bucket_id".equalsIgnoreCase(e.getCode())) {
8080
return new NotfoundException(buffer.toString(), e);
8181
}
82+
if("already_hidden".equalsIgnoreCase(e.getCode())) {
83+
return new NotfoundException(buffer.toString(), e);
84+
}
8285
if("cap_exceeded".equalsIgnoreCase(e.getCode())) {// Reached the storage cap that you set
8386
return new QuotaException(buffer.toString(), e);
8487
}

backblaze/src/main/java/ch/cyberduck/core/b2/B2ObjectListService.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import ch.cyberduck.core.AttributedList;
1919
import ch.cyberduck.core.DefaultIOExceptionMappingService;
2020
import ch.cyberduck.core.DefaultPathContainerService;
21+
import ch.cyberduck.core.DisabledListProgressListener;
2122
import ch.cyberduck.core.ListProgressListener;
2223
import ch.cyberduck.core.ListService;
2324
import ch.cyberduck.core.Path;
@@ -36,6 +37,7 @@
3637
import java.util.EnumSet;
3738
import java.util.HashMap;
3839
import java.util.Map;
40+
import java.util.stream.Collectors;
3941

4042
import synapticloop.b2.Action;
4143
import synapticloop.b2.exception.B2ApiException;
@@ -114,7 +116,7 @@ private String createPrefix(final Path directory) {
114116
}
115117

116118
private Marker parse(final Path directory, final AttributedList<Path> objects,
117-
final B2ListFilesResponse response, final Map<String, Long> revisions) {
119+
final B2ListFilesResponse response, final Map<String, Long> revisions) throws BackgroundException {
118120
final B2AttributesFinderFeature attr = new B2AttributesFinderFeature(session, fileid);
119121
for(B2FileInfoResponse info : response.getFiles()) {
120122
if(StringUtils.equals(PathNormalizer.name(info.getFileName()), B2PathContainerService.PLACEHOLDER)) {
@@ -131,6 +133,10 @@ private Marker parse(final Path directory, final AttributedList<Path> objects,
131133
final Path placeholder = new Path(directory.isDirectory() ? directory : directory.getParent(),
132134
PathNormalizer.name(StringUtils.chomp(info.getFileName(), String.valueOf(Path.DELIMITER))),
133135
EnumSet.of(Path.Type.directory, Path.Type.placeholder));
136+
// Need to check if only hidden files inside
137+
if(this.list(placeholder, new DisabledListProgressListener()).toStream().filter(f -> !f.attributes().isDuplicate()).collect(Collectors.toList()).isEmpty()) {
138+
placeholder.attributes().setDuplicate(true);
139+
}
134140
objects.add(placeholder);
135141
continue;
136142
}

backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2DirectoryFeatureTest.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
import ch.cyberduck.core.AlphanumericRandomStringService;
19+
import ch.cyberduck.core.DisabledListProgressListener;
1920
import ch.cyberduck.core.DisabledLoginCallback;
2021
import ch.cyberduck.core.DisabledPasswordCallback;
2122
import ch.cyberduck.core.DisabledPasswordStore;
@@ -25,9 +26,10 @@
2526
import ch.cyberduck.core.b2.B2DeleteFeature;
2627
import ch.cyberduck.core.b2.B2DirectoryFeature;
2728
import ch.cyberduck.core.b2.B2FindFeature;
29+
import ch.cyberduck.core.b2.B2ObjectListService;
2830
import ch.cyberduck.core.b2.B2VersionIdProvider;
2931
import ch.cyberduck.core.cryptomator.features.CryptoAttributesFeature;
30-
import ch.cyberduck.core.cryptomator.features.CryptoFindV6Feature;
32+
import ch.cyberduck.core.cryptomator.features.CryptoListService;
3133
import ch.cyberduck.core.features.Delete;
3234
import ch.cyberduck.core.features.Directory;
3335
import ch.cyberduck.core.features.Find;
@@ -44,8 +46,9 @@
4446
import org.junit.runners.Parameterized;
4547

4648
import java.util.Arrays;
49+
import java.util.Collections;
4750
import java.util.EnumSet;
48-
import java.util.UUID;
51+
import java.util.stream.Collectors;
4952

5053
import static org.junit.Assert.*;
5154
import static org.junit.Assume.assumeTrue;
@@ -63,17 +66,20 @@ public void testMakeDirectoryEncrypted() throws Exception {
6366
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordStore(), new DisabledPasswordCallback(), cryptomator));
6467
final B2VersionIdProvider fileid = new B2VersionIdProvider(session);
6568
final Path test = cryptomator.getFeature(session, Directory.class, new B2DirectoryFeature(session, fileid)).mkdir(
66-
new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)), new TransferStatus());
69+
new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
6770
assertTrue(test.getType().contains(Path.Type.placeholder));
6871
final String versionId = test.attributes().getVersionId();
6972
assertNotNull(versionId);
7073
// Assert both filename and file id matches
71-
assertTrue(new CryptoFindV6Feature(session, new B2FindFeature(session, fileid), cryptomator).find(test));
74+
assertTrue(cryptomator.getFeature(session, Find.class, new B2FindFeature(session, fileid)).find(test));
7275
assertTrue(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(test));
7376
assertEquals(versionId, new CryptoAttributesFeature(session, new B2AttributesFinderFeature(session, fileid), cryptomator).find(test).getVersionId());
7477
// Placeholder returned in list service with no file info
7578
new CryptoAttributesFeature(session, new DefaultAttributesFinderFeature(session), cryptomator).find(test).getVersionId();
76-
cryptomator.getFeature(session, Delete.class, new B2DeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
79+
cryptomator.getFeature(session, Delete.class, new B2DeleteFeature(session, fileid)).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
80+
assertTrue(new CryptoListService(session, new B2ObjectListService(session, fileid), cryptomator).list(vault, new DisabledListProgressListener())
81+
.toStream().filter(f -> !f.attributes().isDuplicate()).collect(Collectors.toList()).isEmpty());
82+
cryptomator.getFeature(session, Delete.class, new B2DeleteFeature(session, fileid)).delete(Collections.singletonList(vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
7783
}
7884

7985
@Test

backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadServiceTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,10 @@
3333
import ch.cyberduck.core.b2.B2WriteFeature;
3434
import ch.cyberduck.core.cryptomator.features.CryptoAttributesFeature;
3535
import ch.cyberduck.core.cryptomator.features.CryptoBulkFeature;
36-
import ch.cyberduck.core.cryptomator.features.CryptoFindV6Feature;
3736
import ch.cyberduck.core.cryptomator.features.CryptoReadFeature;
3837
import ch.cyberduck.core.cryptomator.features.CryptoUploadFeature;
3938
import ch.cyberduck.core.features.Delete;
39+
import ch.cyberduck.core.features.Find;
4040
import ch.cyberduck.core.io.BandwidthThrottle;
4141
import ch.cyberduck.core.io.StreamCopier;
4242
import ch.cyberduck.core.shared.DisabledBulkFeature;
@@ -93,7 +93,7 @@ public void testWrite() throws Exception {
9393
m.upload(test, local, new BandwidthThrottle(BandwidthThrottle.UNLIMITED), counter, writeStatus, null);
9494
assertEquals(content.length, counter.getSent());
9595
assertTrue(writeStatus.isComplete());
96-
assertTrue(new CryptoFindV6Feature(session, new B2FindFeature(session, fileid), cryptomator).find(test));
96+
assertTrue(cryptomator.getFeature(session, Find.class, new B2FindFeature(session, fileid)).find(test));
9797
assertEquals(content.length, new CryptoAttributesFeature(session, new B2AttributesFinderFeature(session, fileid), cryptomator).find(test).getSize());
9898
final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length);
9999
final TransferStatus readStatus = new TransferStatus().withLength(content.length);
@@ -129,7 +129,7 @@ public void testUploadWithBulk() throws Exception {
129129
m.upload(test, local, new BandwidthThrottle(BandwidthThrottle.UNLIMITED), counter, writeStatus, null);
130130
assertEquals(content.length, counter.getSent());
131131
assertTrue(writeStatus.isComplete());
132-
assertTrue(new CryptoFindV6Feature(session, new B2FindFeature(session, fileid), cryptomator).find(test));
132+
assertTrue(cryptomator.getFeature(session, Find.class, new B2FindFeature(session, fileid)).find(test));
133133
assertEquals(content.length, new CryptoAttributesFeature(session, new B2AttributesFinderFeature(session, fileid), cryptomator).find(test).getSize());
134134
final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length);
135135
final TransferStatus readStatus = new TransferStatus().withLength(content.length);

backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadWriteFeatureTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@
2727
import ch.cyberduck.core.b2.B2LargeUploadWriteFeature;
2828
import ch.cyberduck.core.b2.B2ReadFeature;
2929
import ch.cyberduck.core.b2.B2VersionIdProvider;
30-
import ch.cyberduck.core.cryptomator.features.CryptoFindV6Feature;
3130
import ch.cyberduck.core.cryptomator.features.CryptoReadFeature;
3231
import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature;
3332
import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator;
3433
import ch.cyberduck.core.features.Delete;
34+
import ch.cyberduck.core.features.Find;
3535
import ch.cyberduck.core.io.StreamCopier;
3636
import ch.cyberduck.core.transfer.TransferStatus;
3737
import ch.cyberduck.core.vault.DefaultVaultRegistry;
@@ -79,7 +79,7 @@ public void testWrite() throws Exception {
7979
final ByteArrayInputStream in = new ByteArrayInputStream(content);
8080
final TransferStatus progress = new TransferStatus();
8181
new StreamCopier(new TransferStatus(), progress).transfer(in, out);
82-
assertTrue(new CryptoFindV6Feature(session, new B2FindFeature(session, fileid), cryptomator).find(test));
82+
assertTrue(cryptomator.getFeature(session, Find.class, new B2FindFeature(session, fileid)).find(test));
8383
final byte[] compare = new byte[content.length];
8484
final InputStream stream = new CryptoReadFeature(session, new B2ReadFeature(session, fileid), cryptomator).read(test, new TransferStatus().withLength(content.length), new DisabledConnectionCallback());
8585
IOUtils.readFully(stream, compare);

backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2TouchFeatureTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import ch.cyberduck.core.b2.B2VersionIdProvider;
2929
import ch.cyberduck.core.b2.B2WriteFeature;
3030
import ch.cyberduck.core.cryptomator.features.CryptoAttributesFeature;
31-
import ch.cyberduck.core.cryptomator.features.CryptoFindV6Feature;
3231
import ch.cyberduck.core.cryptomator.features.CryptoTouchFeature;
3332
import ch.cyberduck.core.features.Delete;
3433
import ch.cyberduck.core.features.Find;
@@ -69,7 +68,7 @@ public void testTouchEncrypted() throws Exception {
6968
assertEquals(0L, test.attributes().getSize());
7069
assertEquals(0L, status.getResponse().getSize());
7170
assertNotNull(test.attributes().getVersionId());
72-
assertTrue(new CryptoFindV6Feature(session, new B2FindFeature(session, fileid), cryptomator).find(test));
71+
assertTrue(cryptomator.getFeature(session, Find.class, new B2FindFeature(session, fileid)).find(test));
7372
assertEquals(test.attributes(), new CryptoAttributesFeature(session, new B2AttributesFinderFeature(session, fileid), cryptomator).find(test));
7473
cryptomator.getFeature(session, Delete.class, new B2DeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
7574
}
@@ -88,7 +87,7 @@ public void testTouchLongFilenameEncrypted() throws Exception {
8887
new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)), status);
8988
assertEquals(0L, test.attributes().getSize());
9089
assertEquals(0L, status.getResponse().getSize());
91-
assertTrue(new CryptoFindV6Feature(session, new B2FindFeature(session, fileid), cryptomator).find(test));
90+
assertTrue(cryptomator.getFeature(session, Find.class, new B2FindFeature(session, fileid)).find(test));
9291
cryptomator.getFeature(session, Delete.class, new B2DeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
9392
}
9493

backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2WriteFeatureTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@
3030
import ch.cyberduck.core.b2.B2VersionIdProvider;
3131
import ch.cyberduck.core.b2.B2WriteFeature;
3232
import ch.cyberduck.core.cryptomator.features.CryptoAttributesFeature;
33-
import ch.cyberduck.core.cryptomator.features.CryptoFindV6Feature;
3433
import ch.cyberduck.core.cryptomator.features.CryptoReadFeature;
3534
import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature;
3635
import ch.cyberduck.core.cryptomator.random.RotatingNonceGenerator;
3736
import ch.cyberduck.core.features.Delete;
37+
import ch.cyberduck.core.features.Find;
3838
import ch.cyberduck.core.io.StreamCopier;
3939
import ch.cyberduck.core.transfer.TransferStatus;
4040
import ch.cyberduck.core.vault.DefaultVaultRegistry;
@@ -76,7 +76,7 @@ public void testWrite() throws Exception {
7676
final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
7777
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordStore(), new DisabledPasswordCallback(), cryptomator));
7878
final B2VersionIdProvider fileid = new B2VersionIdProvider(session);
79-
final CryptoWriteFeature<BaseB2Response> writer = new CryptoWriteFeature<BaseB2Response>(session, new B2WriteFeature(session, fileid), cryptomator);
79+
final CryptoWriteFeature<BaseB2Response> writer = new CryptoWriteFeature<>(session, new B2WriteFeature(session, fileid), cryptomator);
8080
final FileHeader header = cryptomator.getFileHeaderCryptor().create();
8181
status.setHeader(cryptomator.getFileHeaderCryptor().encryptHeader(header));
8282
status.setNonces(new RotatingNonceGenerator(cryptomator.getNonceSize(), cryptomator.numberOfChunks(content.length)));
@@ -85,7 +85,7 @@ public void testWrite() throws Exception {
8585
assertNotNull(out);
8686
new StreamCopier(status, status).transfer(new ByteArrayInputStream(content), out);
8787
out.close();
88-
assertTrue(new CryptoFindV6Feature(session, new B2FindFeature(session, fileid), cryptomator).find(test));
88+
assertTrue(cryptomator.getFeature(session, Find.class, new B2FindFeature(session, fileid)).find(test));
8989
final PathAttributes attributes = new CryptoAttributesFeature(session, new B2AttributesFinderFeature(session, fileid), cryptomator).find(test);
9090
assertEquals(content.length, attributes.getSize());
9191
assertEquals(content.length, writer.append(test, status.withRemote(attributes)).size, 0L);

0 commit comments

Comments
 (0)