From 6503727a40423aea4032e0f420373b97bdaa5efd Mon Sep 17 00:00:00 2001 From: Manuel Jenny Date: Thu, 22 Apr 2021 15:30:22 +0200 Subject: [PATCH] fix(S3): folder / file handling --- .../data/cloud/s3/RootS3Folder.java | 5 +++ .../data/cloud/s3/S3CloudNodeFactory.java | 14 +++++--- .../org/cryptomator/data/cloud/s3/S3File.java | 5 +++ .../cryptomator/data/cloud/s3/S3Folder.java | 7 ++++ .../org/cryptomator/data/cloud/s3/S3Impl.java | 34 +++++++++++++------ .../org/cryptomator/data/cloud/s3/S3Node.java | 2 ++ 6 files changed, 51 insertions(+), 16 deletions(-) diff --git a/data/src/main/java/org/cryptomator/data/cloud/s3/RootS3Folder.java b/data/src/main/java/org/cryptomator/data/cloud/s3/RootS3Folder.java index e52be7eb..25116de8 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/s3/RootS3Folder.java +++ b/data/src/main/java/org/cryptomator/data/cloud/s3/RootS3Folder.java @@ -17,6 +17,11 @@ class RootS3Folder extends S3Folder { return cloud; } + @Override + public String getKey() { + return ""; + } + @Override public S3Folder withCloud(Cloud cloud) { return new RootS3Folder((S3Cloud) cloud); diff --git a/data/src/main/java/org/cryptomator/data/cloud/s3/S3CloudNodeFactory.java b/data/src/main/java/org/cryptomator/data/cloud/s3/S3CloudNodeFactory.java index f17f4475..0f93e6bf 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/s3/S3CloudNodeFactory.java +++ b/data/src/main/java/org/cryptomator/data/cloud/s3/S3CloudNodeFactory.java @@ -9,7 +9,7 @@ import java.util.Date; class S3CloudNodeFactory { - private static final String SUFFIX = "/"; + private static final String DELIMITER = "/"; public static S3File file(S3Folder parent, S3ObjectSummary file) { String name = getNameFromKey(file.getKey()); @@ -47,15 +47,19 @@ class S3CloudNodeFactory { } private static String getNodePath(S3Folder parent, String name) { - return parent.getPath() + SUFFIX + name; + return parent.getKey() + name; } - private static String getNameFromKey(String key) { - return key.substring(key.lastIndexOf(SUFFIX) + 1); + public static String getNameFromKey(String key) { + String name = key; + if (key.endsWith(DELIMITER)) { + name = key.substring(0, key.length() -1); + } + return name.contains(DELIMITER) ? name.substring(name.lastIndexOf(DELIMITER) + 1) : name; } public static S3Node from(S3Folder parent, S3ObjectSummary objectSummary) { - if (objectSummary.getKey().endsWith(SUFFIX)) { + if (objectSummary.getKey().endsWith(DELIMITER)) { return folder(parent, objectSummary); } else { return file(parent, objectSummary); diff --git a/data/src/main/java/org/cryptomator/data/cloud/s3/S3File.java b/data/src/main/java/org/cryptomator/data/cloud/s3/S3File.java index b7c22c63..ce3520f8 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/s3/S3File.java +++ b/data/src/main/java/org/cryptomator/data/cloud/s3/S3File.java @@ -37,6 +37,11 @@ class S3File implements CloudFile, S3Node { return path; } + @Override + public String getKey() { + return path; + } + @Override public S3Folder getParent() { return parent; diff --git a/data/src/main/java/org/cryptomator/data/cloud/s3/S3Folder.java b/data/src/main/java/org/cryptomator/data/cloud/s3/S3Folder.java index 67b7f7fa..591c6dea 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/s3/S3Folder.java +++ b/data/src/main/java/org/cryptomator/data/cloud/s3/S3Folder.java @@ -5,6 +5,8 @@ import org.cryptomator.domain.CloudFolder; class S3Folder implements CloudFolder, S3Node { + private static final String DELIMITER = "/"; + private final S3Folder parent; private final String name; private final String path; @@ -30,6 +32,11 @@ class S3Folder implements CloudFolder, S3Node { return path; } + @Override + public String getKey() { + return path + DELIMITER; + } + @Override public S3Folder getParent() { return parent; diff --git a/data/src/main/java/org/cryptomator/data/cloud/s3/S3Impl.java b/data/src/main/java/org/cryptomator/data/cloud/s3/S3Impl.java index e31afaa7..cb64a1c7 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/s3/S3Impl.java +++ b/data/src/main/java/org/cryptomator/data/cloud/s3/S3Impl.java @@ -8,6 +8,7 @@ import com.amazonaws.services.s3.model.CopyObjectResult; import com.amazonaws.services.s3.model.DeleteObjectsRequest; import com.amazonaws.services.s3.model.DeleteObjectsRequest.KeyVersion; import com.amazonaws.services.s3.model.GetObjectRequest; +import com.amazonaws.services.s3.model.ListObjectsV2Request; import com.amazonaws.services.s3.model.ListObjectsV2Result; import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.Owner; @@ -49,7 +50,7 @@ import static org.cryptomator.util.file.LruFileCacheUtil.storeToLruCache; class S3Impl { - private static final String SUFFIX = "/"; + private static final String DELIMITER = "/"; private final S3ClientFactory clientFactory = new S3ClientFactory(); private final S3Cloud cloud; @@ -79,10 +80,10 @@ class S3Impl { } public S3Folder resolve(String path) { - if (path.startsWith(SUFFIX)) { + if (path.startsWith(DELIMITER)) { path = path.substring(1); } - String[] names = path.split(SUFFIX); + String[] names = path.split(DELIMITER); S3Folder folder = root; for (String name : names) { if (!name.isEmpty()) { @@ -97,17 +98,17 @@ class S3Impl { } public S3File file(S3Folder parent, String name, Optional size) throws BackendException, IOException { - return S3CloudNodeFactory.file(parent, name, size, parent.getPath() + name); + return S3CloudNodeFactory.file(parent, name, size, parent.getKey() + name); } public S3Folder folder(S3Folder parent, String name) { - return S3CloudNodeFactory.folder(parent, name, parent.getPath() + name + SUFFIX); + return S3CloudNodeFactory.folder(parent, name, parent.getKey() + name); } public boolean exists(S3Node node) { - String path = node.getPath(); + String key = node.getKey(); - ListObjectsV2Result result = client().listObjectsV2(cloud.s3Bucket(), path); + ListObjectsV2Result result = client().listObjectsV2(cloud.s3Bucket(), key); if (result.getObjectSummaries().size() > 0) { return true; @@ -119,9 +120,20 @@ class S3Impl { public List list(S3Folder folder) throws IOException, BackendException { List result = new ArrayList<>(); - ListObjectsV2Result listObjects = client().listObjectsV2(cloud.s3Bucket(), folder.getPath()); + ListObjectsV2Request request = new ListObjectsV2Request() + .withBucketName(cloud.s3Bucket()) + .withPrefix(folder.getKey()) + .withDelimiter(DELIMITER); + + ListObjectsV2Result listObjects = client().listObjectsV2(request); + for(String prefix : listObjects.getCommonPrefixes()) { + result.add(S3CloudNodeFactory.folder(folder, S3CloudNodeFactory.getNameFromKey(prefix))); + } + for (S3ObjectSummary objectSummary : listObjects.getObjectSummaries()) { - result.add(S3CloudNodeFactory.from(folder, objectSummary)); + if (!objectSummary.getKey().equals(listObjects.getPrefix())) { + result.add(S3CloudNodeFactory.from(folder, objectSummary)); + } } return result; } @@ -216,9 +228,9 @@ class S3Impl { ListObjectsV2Result listObjects; if (sharedPreferencesHandler.useLruCache() && createLruCache(sharedPreferencesHandler.lruCacheSize())) { - listObjects = client().listObjectsV2(cloud.s3Bucket(), file.getPath()); + listObjects = client().listObjectsV2(cloud.s3Bucket(), file.getKey()); if (listObjects.getObjectSummaries().size() != 1) { - throw new NoSuchCloudFileException(file.getPath()); + throw new NoSuchCloudFileException(file.getKey()); } S3ObjectSummary summary = listObjects.getObjectSummaries().get(0); cacheKey = Optional.of(summary.getKey() + summary.getETag()); diff --git a/data/src/main/java/org/cryptomator/data/cloud/s3/S3Node.java b/data/src/main/java/org/cryptomator/data/cloud/s3/S3Node.java index b5f241fe..570d338b 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/s3/S3Node.java +++ b/data/src/main/java/org/cryptomator/data/cloud/s3/S3Node.java @@ -7,4 +7,6 @@ interface S3Node extends CloudNode { @Override S3Folder getParent(); + String getKey(); + }