Skip to content

Commit 2a8325b

Browse files
committed
Extract filters for protocol features used for specific file attributes in file transfers.
1 parent a7b3e75 commit 2a8325b

26 files changed

+1557
-586
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package ch.cyberduck.core.transfer;
2+
3+
/*
4+
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.core.Local;
19+
import ch.cyberduck.core.Path;
20+
import ch.cyberduck.core.ProgressListener;
21+
import ch.cyberduck.core.exception.BackgroundException;
22+
23+
import org.apache.logging.log4j.LogManager;
24+
import org.apache.logging.log4j.Logger;
25+
26+
import java.util.Optional;
27+
28+
public class ChainedFeatureFilter implements FeatureFilter {
29+
private static final Logger log = LogManager.getLogger(ChainedFeatureFilter.class);
30+
31+
private final FeatureFilter[] filters;
32+
33+
public ChainedFeatureFilter(final FeatureFilter... filters) {
34+
this.filters = filters;
35+
}
36+
37+
@Override
38+
public TransferStatus prepare(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
39+
for(final FeatureFilter filter : filters) {
40+
log.debug("Prepare {} with {}", file, filter);
41+
filter.prepare(file, local, status, progress);
42+
}
43+
return status;
44+
}
45+
46+
@Override
47+
public void complete(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
48+
for(final FeatureFilter filter : filters) {
49+
log.debug("Complete {} with {}", file, filter);
50+
filter.complete(file, local, status, progress);
51+
}
52+
}
53+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package ch.cyberduck.core.transfer;
2+
3+
/*
4+
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.core.Local;
19+
import ch.cyberduck.core.Path;
20+
import ch.cyberduck.core.ProgressListener;
21+
import ch.cyberduck.core.exception.BackgroundException;
22+
23+
import java.util.Optional;
24+
25+
public interface FeatureFilter {
26+
default TransferStatus prepare(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
27+
// No-op
28+
return status;
29+
}
30+
31+
default void apply(final Path file, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
32+
// No-op
33+
}
34+
35+
default void complete(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
36+
// No-op
37+
}
38+
39+
FeatureFilter noop = new FeatureFilter() {
40+
@Override
41+
public TransferStatus prepare(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) {
42+
// No-op
43+
return status;
44+
}
45+
};
46+
}

core/src/main/java/ch/cyberduck/core/transfer/download/AbstractDownloadFilter.java

Lines changed: 17 additions & 279 deletions
Large diffs are not rendered by default.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package ch.cyberduck.core.transfer.download.features;
2+
3+
/*
4+
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.core.Local;
19+
import ch.cyberduck.core.LocaleFactory;
20+
import ch.cyberduck.core.Path;
21+
import ch.cyberduck.core.ProgressListener;
22+
import ch.cyberduck.core.exception.BackgroundException;
23+
import ch.cyberduck.core.exception.ChecksumException;
24+
import ch.cyberduck.core.io.Checksum;
25+
import ch.cyberduck.core.io.ChecksumCompute;
26+
import ch.cyberduck.core.io.ChecksumComputeFactory;
27+
import ch.cyberduck.core.transfer.FeatureFilter;
28+
import ch.cyberduck.core.transfer.TransferStatus;
29+
30+
import org.apache.logging.log4j.LogManager;
31+
import org.apache.logging.log4j.Logger;
32+
33+
import java.text.MessageFormat;
34+
import java.util.Optional;
35+
36+
public class ChecksumFeatureFilter implements FeatureFilter {
37+
private static final Logger log = LogManager.getLogger(ChecksumFeatureFilter.class);
38+
39+
@Override
40+
public TransferStatus prepare(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
41+
return status.setChecksum(status.getRemote().getChecksum());
42+
}
43+
44+
@Override
45+
public void complete(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
46+
if(file.isFile()) {
47+
if(file.getType().contains(Path.Type.decrypted)) {
48+
log.warn("Skip checksum verification for {} with client side encryption enabled", file);
49+
}
50+
else {
51+
final Checksum checksum = status.getChecksum();
52+
if(Checksum.NONE != checksum) {
53+
if(local.isPresent()) {
54+
final ChecksumCompute compute = ChecksumComputeFactory.get(checksum.algorithm);
55+
progress.message(MessageFormat.format(LocaleFactory.localizedString("Calculate checksum for {0}", "Status"),
56+
file.getName()));
57+
final Checksum download = compute.compute(local.get().getInputStream(), new TransferStatus());
58+
if(!checksum.equals(download)) {
59+
throw new ChecksumException(
60+
MessageFormat.format(LocaleFactory.localizedString("Download {0} failed", "Error"), file.getName()),
61+
MessageFormat.format(LocaleFactory.localizedString("Mismatch between {0} hash {1} of downloaded data and checksum {2} returned by the server", "Error"),
62+
download.algorithm.toString(), download.hash, checksum.hash));
63+
}
64+
}
65+
}
66+
}
67+
}
68+
}
69+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ch.cyberduck.core.transfer.download.features;
2+
3+
/*
4+
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.core.Session;
19+
import ch.cyberduck.core.transfer.ChainedFeatureFilter;
20+
import ch.cyberduck.core.transfer.download.DownloadFilterOptions;
21+
22+
public class DefaultDownloadOptionsFilterChain extends ChainedFeatureFilter {
23+
24+
public DefaultDownloadOptionsFilterChain(final Session<?> session, final DownloadFilterOptions options) {
25+
super(
26+
options.timestamp ? new TimestampFeatureFilter() : noop,
27+
options.permissions ? new PermissionFeatureFilter(session) : noop,
28+
options.checksum ? new ChecksumFeatureFilter() : noop,
29+
new TemporaryFeatureFilter(),
30+
options.quarantine ? new QuarantineFilter(session) : noop,
31+
options.open ? new LauncherFilter() : noop
32+
);
33+
}
34+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package ch.cyberduck.core.transfer.download.features;
2+
3+
/*
4+
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.core.Local;
19+
import ch.cyberduck.core.Path;
20+
import ch.cyberduck.core.ProgressListener;
21+
import ch.cyberduck.core.exception.BackgroundException;
22+
import ch.cyberduck.core.local.ApplicationLauncher;
23+
import ch.cyberduck.core.local.ApplicationLauncherFactory;
24+
import ch.cyberduck.core.transfer.FeatureFilter;
25+
import ch.cyberduck.core.transfer.TransferStatus;
26+
27+
import java.util.Optional;
28+
29+
public class LauncherFilter implements FeatureFilter {
30+
31+
private final ApplicationLauncher launcher = ApplicationLauncherFactory.get();
32+
33+
@Override
34+
public void complete(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
35+
if(file.isFile()) {
36+
local.ifPresent(launcher::open);
37+
}
38+
}
39+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package ch.cyberduck.core.transfer.download.features;
2+
3+
/*
4+
* Copyright (c) 2002-2024 iterate GmbH. All rights reserved.
5+
* https://cyberduck.io/
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation, either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*/
17+
18+
import ch.cyberduck.core.Local;
19+
import ch.cyberduck.core.Path;
20+
import ch.cyberduck.core.Permission;
21+
import ch.cyberduck.core.ProgressListener;
22+
import ch.cyberduck.core.Session;
23+
import ch.cyberduck.core.exception.AccessDeniedException;
24+
import ch.cyberduck.core.exception.BackgroundException;
25+
import ch.cyberduck.core.preferences.HostPreferencesFactory;
26+
import ch.cyberduck.core.preferences.PreferencesReader;
27+
import ch.cyberduck.core.transfer.FeatureFilter;
28+
import ch.cyberduck.core.transfer.TransferStatus;
29+
30+
import org.apache.logging.log4j.LogManager;
31+
import org.apache.logging.log4j.Logger;
32+
33+
import java.util.Optional;
34+
35+
public class PermissionFeatureFilter implements FeatureFilter {
36+
private static final Logger log = LogManager.getLogger(PermissionFeatureFilter.class);
37+
38+
private final PreferencesReader preferences;
39+
40+
public PermissionFeatureFilter(final Session<?> session) {
41+
this.preferences = HostPreferencesFactory.get(session.getHost());
42+
}
43+
44+
@Override
45+
public TransferStatus prepare(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
46+
Permission permission = Permission.EMPTY;
47+
if(preferences.getBoolean("queue.download.permissions.default")) {
48+
if(file.isFile()) {
49+
permission = new Permission(
50+
preferences.getInteger("queue.download.permissions.file.default"));
51+
}
52+
if(file.isDirectory()) {
53+
permission = new Permission(
54+
preferences.getInteger("queue.download.permissions.folder.default"));
55+
}
56+
}
57+
else {
58+
permission = status.getRemote().getPermission();
59+
}
60+
return status.setPermission(permission);
61+
}
62+
63+
@Override
64+
public void complete(final Path file, final Optional<Local> local, final TransferStatus status, final ProgressListener progress) throws BackgroundException {
65+
if(!Permission.EMPTY.equals(status.getPermission())) {
66+
if(file.isDirectory()) {
67+
// Make sure we can read & write files to directory created.
68+
status.getPermission().setUser(status.getPermission().getUser().or(Permission.Action.read).or(Permission.Action.write).or(Permission.Action.execute));
69+
}
70+
if(file.isFile()) {
71+
// Make sure the owner can always read and write.
72+
status.getPermission().setUser(status.getPermission().getUser().or(Permission.Action.read).or(Permission.Action.write));
73+
}
74+
if(local.isPresent()) {
75+
log.info("Updating permissions of {} to {}", local, status.getPermission());
76+
try {
77+
local.get().attributes().setPermission(status.getPermission());
78+
}
79+
catch(AccessDeniedException e) {
80+
// Ignore
81+
log.warn(e.getMessage());
82+
}
83+
}
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)