Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #13949. #13956

Merged
merged 5 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import ch.cyberduck.core.AttributedList;
import ch.cyberduck.core.DisabledListProgressListener;
import ch.cyberduck.core.DisabledLoginCallback;
import ch.cyberduck.core.IndexedListProgressListener;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.Delete;
Expand Down Expand Up @@ -69,13 +70,23 @@ public void testListLexicographicSortOrderAssumption() throws Exception {
new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
assertTrue(new AzureObjectListService(session, null).list(directory, new DisabledListProgressListener()).isEmpty());
final List<String> files = Arrays.asList(
"aa", "0a", "a", "AAA", "B", "~$a", ".c"
"Z", "aa", "0a", "a", "AAA", "B", "~$a", ".c"
);
for(String f : files) {
new AzureTouchFeature(session, null).touch(new Path(directory, f, EnumSet.of(Path.Type.file)), new TransferStatus());
}
files.sort(session.getHost().getProtocol().getListComparator());
final AttributedList<Path> list = new AzureObjectListService(session, null).list(directory, new DisabledListProgressListener());
final AttributedList<Path> list = new AzureObjectListService(session, null).list(directory, new IndexedListProgressListener() {
@Override
public void message(final String message) {
//
}

@Override
public void visit(final AttributedList<Path> list, final int index, final Path file) {
assertEquals(files.get(index), file.getName());
}
});
for(int i = 0; i < list.size(); i++) {
assertEquals(files.get(i), list.get(i).getName());
new AzureDeleteFeature(session, null).delete(Collections.singletonList(list.get(i)), new DisabledLoginCallback(), new Delete.DisabledCallback());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import ch.cyberduck.core.DisabledConnectionCallback;
import ch.cyberduck.core.DisabledListProgressListener;
import ch.cyberduck.core.DisabledLoginCallback;
import ch.cyberduck.core.IndexedListProgressListener;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.PathAttributes;
import ch.cyberduck.core.SimplePathPredicate;
Expand Down Expand Up @@ -259,16 +260,26 @@ public void testIdenticalNamingFileFolder() throws Exception {
public void testListLexicographicSortOrderAssumption() throws Exception {
final B2VersionIdProvider fileid = new B2VersionIdProvider(session);
final Path directory = new B2DirectoryFeature(session, fileid).mkdir(
new Path(String.format("test-%s", new AsciiRandomStringService().random()), EnumSet.of(Path.Type.directory, Path.Type.volume)), new TransferStatus());
new Path(String.format("test-%s", new AsciiRandomStringService().random()), EnumSet.of(Path.Type.directory, Path.Type.volume)), new TransferStatus());
assertTrue(new B2ObjectListService(session, fileid).list(directory, new DisabledListProgressListener()).isEmpty());
final List<String> files = Arrays.asList(
"aa", "0a", "a", "AAA", "B", "~$a", ".c"
"Z", "aa", "0a", "a", "AAA", "B", "~$a", ".c"
);
for(String f : files) {
new B2TouchFeature(session, fileid).touch(new Path(directory, f, EnumSet.of(Path.Type.file)), new TransferStatus());
}
files.sort(session.getHost().getProtocol().getListComparator());
final AttributedList<Path> list = new B2ObjectListService(session, fileid).list(directory, new DisabledListProgressListener());
final AttributedList<Path> list = new B2ObjectListService(session, fileid).list(directory, new IndexedListProgressListener() {
@Override
public void message(final String message) {
//
}

@Override
public void visit(final AttributedList<Path> list, final int index, final Path file) {
assertEquals(files.get(index), file.getName());
}
});
for(int i = 0; i < list.size(); i++) {
assertEquals(files.get(i), list.get(i).getName());
new B2DeleteFeature(session, fileid).delete(Collections.singletonList(list.get(i)), new DisabledLoginCallback(), new Delete.DisabledCallback());
Expand Down
49 changes: 25 additions & 24 deletions core/src/main/java/ch/cyberduck/core/AttributedList.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ public boolean addAll(final Iterable c) {
};

private final List<E> impl
= new CopyOnWriteArrayList<>();
= new CopyOnWriteArrayList<>();

/**
* Metadata of file listing
*/
private final AttributedListAttributes<E> attributes
= new AttributedListAttributes<E>().withTimestamp(System.currentTimeMillis());
= new AttributedListAttributes<E>().withTimestamp(System.currentTimeMillis());

/**
* Initialize an attributed list with default attributes
Expand Down Expand Up @@ -129,45 +129,46 @@ public Iterator<E> iterator() {
}

/**
* The CopyOnWriteArrayList iterator does not support remove but the sort implementation
* makes use of it. Provide our own implementation here to circumvent.
* Return filtered list
*
* @param copy The list copy to sort
* @param comparator The comparator to use
* @see java.util.Collections#sort(java.util.List, java.util.Comparator)
* @see java.util.concurrent.CopyOnWriteArrayList#iterator()
*/
private void doSort(final List<E> copy, final Comparator<E> comparator) {
if(null == comparator) {
return;
}
if(log.isDebugEnabled()) {
log.debug(String.format("Sort list %s with comparator %s", this, comparator));
}
copy.sort(comparator);
}

/**
* @param filter Filter
* @return Unsorted filtered list
* @return Unsorted filtered list. Does not modify this list but returns a copy instead.
*/
public AttributedList<E> filter(final Filter<E> filter) {
return this.filter(null, filter);
}

/**
* Return sorted list
*
* @param comparator Sorting comparator
* @return Does not modify this list but returns a copy instead.
*/
public AttributedList<E> filter(final Comparator<E> comparator) {
return this.filter(comparator, null);
}

/**
* @param comparator The comparator to use
* @param filter Filter
* @return Filtered list sorted with comparator
* @return Filtered list sorted with comparator. Does not modify this list but returns a copy instead.
*/
public AttributedList<E> filter(final Comparator<E> comparator, final Filter<E> filter) {
final AttributedList<E> filtered = new AttributedList<>(impl);
return this.filter(new AttributedList<>(impl), comparator, filter);
}

/**
* @param filtered Result set
* @param comparator The comparator to use
* @param filter Filter
* @return Filtered list
*/
public AttributedList<E> filter(final AttributedList<E> filtered, final Comparator<E> comparator, final Filter<E> filter) {
if(null != comparator) {
this.doSort(filtered.impl, comparator);
if(log.isDebugEnabled()) {
log.debug(String.format("Sort list %s with comparator %s", this, comparator));
}
filtered.impl.sort(comparator);
}
if(null != filter) {
if(log.isDebugEnabled()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ protected AttributedList<Path> list(final Path directory, final ListProgressList
if(bucket.attributes().getCustom().containsKey(GoogleStorageAttributesFinderFeature.KEY_REQUESTER_PAYS)) {
request.setUserProject(session.getHost().getCredentials().getUsername());
}
response = request
.execute();
response = request.execute();
if(response.getItems() != null) {
for(StorageObject object : response.getItems()) {
final String key = PathNormalizer.normalize(object.getName());
Expand Down Expand Up @@ -183,13 +182,14 @@ protected AttributedList<Path> list(final Path directory, final ListProgressList
}
}
page = response.getNextPageToken();
listener.chunk(directory, objects.filter((o1, o2) -> session.getHost().getProtocol().getListComparator().compare(o1.getName(), o2.getName())));
objects.filter(objects, (o1, o2) -> session.getHost().getProtocol().getListComparator().compare(o1.getName(), o2.getName()), null);
listener.chunk(directory, objects);
}
while(page != null);
if(!hasDirectoryPlaceholder && objects.isEmpty()) {
throw new NotfoundException(directory.getAbsolute());
}
return objects.filter((o1, o2) -> session.getHost().getProtocol().getListComparator().compare(o1.getName(), o2.getName()));
return objects;
}
catch(IOException e) {
throw new GoogleStorageExceptionMappingService().map("Listing directory {0} failed", e, directory);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package ch.cyberduck.core.cryptomator;

/*
* Copyright (c) 2002-2017 iterate GmbH. All rights reserved.
* https://cyberduck.io/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/

import ch.cyberduck.core.AlphanumericRandomStringService;
import ch.cyberduck.core.DisabledListProgressListener;
import ch.cyberduck.core.DisabledLoginCallback;
import ch.cyberduck.core.DisabledPasswordCallback;
import ch.cyberduck.core.DisabledPasswordStore;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.SimplePathPredicate;
import ch.cyberduck.core.cryptomator.features.CryptoListService;
import ch.cyberduck.core.cryptomator.features.CryptoTouchFeature;
import ch.cyberduck.core.features.Delete;
import ch.cyberduck.core.googlestorage.AbstractGoogleStorageTest;
import ch.cyberduck.core.googlestorage.GoogleStorageDeleteFeature;
import ch.cyberduck.core.googlestorage.GoogleStorageObjectListService;
import ch.cyberduck.core.googlestorage.GoogleStorageWriteFeature;
import ch.cyberduck.core.shared.DefaultTouchFeature;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.core.vault.DefaultVaultRegistry;
import ch.cyberduck.core.vault.VaultCredentials;
import ch.cyberduck.test.IntegrationTest;

import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

import java.util.Arrays;
import java.util.EnumSet;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

@Category(IntegrationTest.class)
@RunWith(value = Parameterized.class)
public class GoogleStorageListServiceTest extends AbstractGoogleStorageTest {

@Test
public void testListCryptomator() throws Exception {
final Path container = new Path("cyberduck-test-eu", EnumSet.of(Path.Type.directory, Path.Type.volume));
final CryptoVault cryptomator = new CryptoVault(
new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)));
final Path vault = cryptomator.create(session, new VaultCredentials("test"), new DisabledPasswordStore(), vaultVersion);
session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordStore(), new DisabledPasswordCallback(), cryptomator));
final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
assertTrue(new CryptoListService(session, new GoogleStorageObjectListService(session), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty());
new CryptoTouchFeature<>(session, new DefaultTouchFeature<>(new GoogleStorageWriteFeature(session)), new GoogleStorageWriteFeature(session), cryptomator).touch(test, new TransferStatus());
assertNotNull(new CryptoListService(session, new GoogleStorageObjectListService(session), cryptomator).list(vault, new DisabledListProgressListener()).
find(new SimplePathPredicate(test)));
cryptomator.getFeature(session, Delete.class, new GoogleStorageDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@
import ch.cyberduck.core.Profile;
import ch.cyberduck.core.ProtocolFactory;
import ch.cyberduck.core.Scheme;
import ch.cyberduck.core.cryptomator.CryptoVault;
import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader;
import ch.cyberduck.core.ssl.DefaultX509KeyManager;
import ch.cyberduck.core.ssl.DefaultX509TrustManager;

import org.junit.After;
import org.junit.Before;
import org.junit.runners.Parameterized;

import java.util.Collections;
import java.util.HashSet;
Expand All @@ -44,6 +46,14 @@

protected GoogleStorageSession session;

@Parameterized.Parameters(name = "vaultVersion = {0}")
public static Object[] data() {
return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION};
}

@Parameterized.Parameter
public int vaultVersion;

@After
public void disconnect() throws Exception {
session.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import ch.cyberduck.core.AttributedList;
import ch.cyberduck.core.DisabledListProgressListener;
import ch.cyberduck.core.DisabledLoginCallback;
import ch.cyberduck.core.IndexedListProgressListener;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.features.Delete;
import ch.cyberduck.core.transfer.TransferStatus;
Expand Down Expand Up @@ -70,7 +71,17 @@ public void testListLexicographicSortOrderAssumption() throws Exception {
}
files.addAll(folders);
files.sort(session.getHost().getProtocol().getListComparator());
final AttributedList<Path> list = new GoogleStorageObjectListService(session).list(directory, new DisabledListProgressListener());
final AttributedList<Path> list = new GoogleStorageObjectListService(session).list(directory, new IndexedListProgressListener() {
@Override
public void message(final String message) {
//
}

@Override
public void visit(final AttributedList<Path> list, final int index, final Path file) {
assertEquals(files.get(index), file.getName());
}
});
for(int i = 0; i < list.size(); i++) {
assertEquals(files.get(i), list.get(i).getName());
new GoogleStorageDeleteFeature(session).delete(Collections.singletonList(list.get(i)), new DisabledLoginCallback(), new Delete.DisabledCallback());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import ch.cyberduck.core.AttributedList;
import ch.cyberduck.core.DisabledListProgressListener;
import ch.cyberduck.core.DisabledLoginCallback;
import ch.cyberduck.core.IndexedListProgressListener;
import ch.cyberduck.core.Path;
import ch.cyberduck.core.exception.NotfoundException;
import ch.cyberduck.core.features.Delete;
Expand Down Expand Up @@ -182,14 +183,24 @@ public void testListLexicographicSortOrderAssumption() throws Exception {
final SwiftRegionService regionService = new SwiftRegionService(session);
final Path directory = new SwiftDirectoryFeature(session, regionService).mkdir(
new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus());
assertTrue(new SwiftObjectListService(session, regionService).list(directory, new DisabledListProgressListener()).isEmpty());
final List<String> files = Arrays.asList(
"aa", "0a", "a", "AAA", "B", "~$a", ".c"
"Z", "aa", "0a", "a", "AAA", "B", "~$a", ".c"
);
files.sort(session.getHost().getProtocol().getListComparator());
assertTrue(new SwiftObjectListService(session, regionService).list(directory, new IndexedListProgressListener() {
@Override
public void message(final String message) {
//
}

@Override
public void visit(final AttributedList<Path> list, final int index, final Path file) {
assertEquals(files.get(index), file.getName());
}
}).isEmpty());
for(String f : files) {
new SwiftTouchFeature(session, regionService).touch(new Path(directory, f, EnumSet.of(Path.Type.file)), new TransferStatus());
}
files.sort(session.getHost().getProtocol().getListComparator());
final AttributedList<Path> list = new SwiftObjectListService(session, regionService).list(directory, new DisabledListProgressListener());
for(int i = 0; i < list.size(); i++) {
assertEquals(files.get(i), list.get(i).getName());
Expand Down