You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2020/11/12 15:05:55 UTC
[mina-sshd] branch master updated: [SSHD-1102] Provide filter
support for SftpDirectoryStream
This is an automated email from the ASF dual-hosted git repository.
lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
The following commit(s) were added to refs/heads/master by this push:
new fbc5d18 [SSHD-1102] Provide filter support for SftpDirectoryStream
fbc5d18 is described below
commit fbc5d187bb2d792f57bf584e2f1c3922e4fd1444
Author: Lyor Goldstein <lg...@apache.org>
AuthorDate: Thu Nov 12 11:38:40 2020 +0200
[SSHD-1102] Provide filter support for SftpDirectoryStream
---
CHANGES.md | 2 +
.../sshd/sftp/client/fs/SftpDirectoryStream.java | 55 ++++++-
.../sftp/client/fs/SftpFileSystemProvider.java | 2 +-
.../sshd/sftp/client/fs/SftpPathIterator.java | 70 +++++++--
.../client/fs/AbstractSftpFilesSystemSupport.java | 165 +++++++++++++++++++++
.../sftp/client/fs/SftpDirectoryScannersTest.java | 75 ++++++++++
.../sshd/sftp/client/fs/SftpFileSystemTest.java | 136 -----------------
7 files changed, 349 insertions(+), 156 deletions(-)
diff --git a/CHANGES.md b/CHANGES.md
index d6d1370..0c8196a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -60,3 +60,5 @@ or `-key-file` command line option.
* [SSHD-1066](https://issues.apache.org/jira/browse/SSHD-1066) Allow multiple binding to local port tunnel on different addresses
* [SSHD-1070](https://issues.apache.org/jira/browse/SSHD-1070) OutOfMemoryError when use async port forwarding
* [SSHD-1100](https://issues.apache.org/jira/browse/SSHD-1100) Updated used moduli for DH group KEX
+* [SSHD-1102](https://issues.apache.org/jira/browse/SSHD-1102) Provide filter support for SftpDirectoryStream
+
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpDirectoryStream.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpDirectoryStream.java
index fab00fd..c53625b 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpDirectoryStream.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpDirectoryStream.java
@@ -22,6 +22,7 @@ import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Path;
import java.util.Iterator;
+import java.util.Objects;
import org.apache.sshd.sftp.client.SftpClient;
@@ -31,19 +32,36 @@ import org.apache.sshd.sftp.client.SftpClient;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class SftpDirectoryStream implements DirectoryStream<Path> {
+ protected SftpPathIterator pathIterator;
+
+ private final SftpPath path;
+ private final Filter<? super Path> filter;
private final SftpClient sftp;
- private final Iterable<SftpClient.DirEntry> iter;
- private final SftpPath p;
/**
* @param path The remote {@link SftpPath}
* @throws IOException If failed to initialize the directory access handle
*/
public SftpDirectoryStream(SftpPath path) throws IOException {
+ this(path, null);
+ }
+
+ /**
+ *
+ * @param path The remote {@link SftpPath}
+ * @param filter An <U>optional</U> {@link java.nio.file.DirectoryStream.Filter filter} - ignored if
+ * {@code null}
+ * @throws IOException If failed to initialize the directory access handle
+ */
+ public SftpDirectoryStream(SftpPath path, Filter<? super Path> filter) throws IOException {
+ this.path = Objects.requireNonNull(path, "No path specified");
+ this.filter = filter;
+
SftpFileSystem fs = path.getFileSystem();
- p = path;
sftp = fs.getClient();
- iter = sftp.readDir(path.toString());
+
+ Iterable<SftpClient.DirEntry> iter = sftp.readDir(path.toString());
+ pathIterator = new SftpPathIterator(getRootPath(), iter, getFilter());
}
/**
@@ -55,9 +73,36 @@ public class SftpDirectoryStream implements DirectoryStream<Path> {
return sftp;
}
+ /**
+ * @return The root {@link SftpPath} for this directory stream
+ */
+ public final SftpPath getRootPath() {
+ return path;
+ }
+
+ /**
+ * @return The original filter - may be {@code null} to indicate no filter
+ */
+ public final Filter<? super Path> getFilter() {
+ return filter;
+ }
+
@Override
public Iterator<Path> iterator() {
- return new SftpPathIterator(p, iter);
+ if (!sftp.isOpen()) {
+ throw new IllegalStateException("Stream has been closed");
+ }
+
+ /*
+ * According to documentation this method can be called only once
+ */
+ if (pathIterator == null) {
+ throw new IllegalStateException("Iterator has already been consumed");
+ }
+
+ Iterator<Path> iter = pathIterator;
+ pathIterator = null;
+ return iter;
}
@Override
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
index e1645c2..f4b62b6 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpFileSystemProvider.java
@@ -520,7 +520,7 @@ public class SftpFileSystemProvider extends FileSystemProvider {
@Override
public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) throws IOException {
final SftpPath p = toSftpPath(dir);
- return new SftpDirectoryStream(p);
+ return new SftpDirectoryStream(p, filter);
}
@Override
diff --git a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpPathIterator.java b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpPathIterator.java
index 259dd06..d34a66d 100644
--- a/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpPathIterator.java
+++ b/sshd-sftp/src/main/java/org/apache/sshd/sftp/client/fs/SftpPathIterator.java
@@ -19,30 +19,65 @@
package org.apache.sshd.sftp.client.fs;
+import java.io.IOException;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.DirectoryStream.Filter;
import java.nio.file.Path;
import java.util.Iterator;
import java.util.NoSuchElementException;
+import java.util.Objects;
import org.apache.sshd.sftp.client.SftpClient;
/**
+ * Implements and {@link Iterator} of {@link SftpPath}-s returned by a {@link DirectoryStream#iterator()} method.
+ *
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class SftpPathIterator implements Iterator<Path> {
- private final SftpPath p;
- private final Iterator<? extends SftpClient.DirEntry> it;
- private boolean dotIgnored;
- private boolean dotdotIgnored;
- private SftpClient.DirEntry curEntry;
+ protected final Iterator<? extends SftpClient.DirEntry> it;
+ protected boolean dotIgnored;
+ protected boolean dotdotIgnored;
+ protected SftpPath curEntry;
+
+ private final SftpPath path;
+ private DirectoryStream.Filter<? super Path> filter;
public SftpPathIterator(SftpPath path, Iterable<? extends SftpClient.DirEntry> iter) {
- this(path, (iter == null) ? null : iter.iterator());
+ this(path, iter, null);
+ }
+
+ public SftpPathIterator(SftpPath path, Iterable<? extends SftpClient.DirEntry> iter,
+ DirectoryStream.Filter<? super Path> filter) {
+ this(path, (iter == null) ? null : iter.iterator(), filter);
}
public SftpPathIterator(SftpPath path, Iterator<? extends SftpClient.DirEntry> iter) {
- p = path;
+ this(path, iter, null);
+ }
+
+ public SftpPathIterator(SftpPath path, Iterator<? extends SftpClient.DirEntry> iter,
+ DirectoryStream.Filter<? super Path> filter) {
+ this.path = Objects.requireNonNull(path, "No root path provided");
+ this.filter = filter;
+
it = iter;
- curEntry = nextEntry();
+ curEntry = nextEntry(path, filter);
+ }
+
+ /**
+ * @return The root {@link SftpPath} for this directory iterator
+ */
+ public final SftpPath getRootPath() {
+ return path;
+ }
+
+ /**
+ * @return The original filter - may be {@code null} to indicate no filter
+ */
+ public final Filter<? super Path> getFilter() {
+ return filter;
}
@Override
@@ -56,12 +91,12 @@ public class SftpPathIterator implements Iterator<Path> {
throw new NoSuchElementException("No next entry");
}
- SftpClient.DirEntry entry = curEntry;
- curEntry = nextEntry();
- return p.resolve(entry.getFilename());
+ SftpPath returnValue = curEntry;
+ curEntry = nextEntry(getRootPath(), getFilter());
+ return returnValue;
}
- private SftpClient.DirEntry nextEntry() {
+ protected SftpPath nextEntry(SftpPath root, DirectoryStream.Filter<? super Path> selector) {
while ((it != null) && it.hasNext()) {
SftpClient.DirEntry entry = it.next();
String name = entry.getFilename();
@@ -70,7 +105,14 @@ public class SftpPathIterator implements Iterator<Path> {
} else if ("..".equals(name) && (!dotdotIgnored)) {
dotdotIgnored = true;
} else {
- return entry;
+ SftpPath candidate = root.resolve(entry.getFilename());
+ try {
+ if ((selector == null) || selector.accept(candidate)) {
+ return candidate;
+ }
+ } catch (IOException e) {
+ throw new DirectoryIteratorException(e);
+ }
}
}
@@ -79,6 +121,6 @@ public class SftpPathIterator implements Iterator<Path> {
@Override
public void remove() {
- throw new UnsupportedOperationException("newDirectoryStream(" + p + ") Iterator#remove() N/A");
+ throw new UnsupportedOperationException("newDirectoryStream(" + getRootPath() + ") Iterator#remove() N/A");
}
}
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/AbstractSftpFilesSystemSupport.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/AbstractSftpFilesSystemSupport.java
index 7ede88f..b516290 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/AbstractSftpFilesSystemSupport.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/AbstractSftpFilesSystemSupport.java
@@ -21,14 +21,31 @@ package org.apache.sshd.sftp.client.fs;
import java.io.IOException;
import java.net.URI;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.attribute.AclEntry;
+import java.nio.file.attribute.AclFileAttributeView;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.util.OsUtils;
import org.apache.sshd.sftp.client.AbstractSftpClientTestSupport;
import org.apache.sshd.sftp.client.SftpClientFactory;
import org.apache.sshd.sftp.client.SftpVersionSelector;
+import org.apache.sshd.sftp.common.SftpConstants;
+import org.apache.sshd.util.test.CommonTestSupportUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -38,6 +55,154 @@ public abstract class AbstractSftpFilesSystemSupport extends AbstractSftpClientT
super();
}
+ protected void testFileSystem(FileSystem fs, int version) throws Exception {
+ testRootDirs(fs);
+
+ Path targetPath = detectTargetFolder();
+ Path lclSftp = CommonTestSupportUtils.resolve(targetPath,
+ SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
+ CommonTestSupportUtils.deleteRecursive(lclSftp);
+
+ Path current = fs.getPath(".").toRealPath().normalize();
+ outputDebugMessage("CWD: %s", current);
+
+ Path parentPath = targetPath.getParent();
+ Path clientFolder = lclSftp.resolve("client");
+ String remFile1Path = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, clientFolder.resolve("file-1.txt"));
+ Path file1 = fs.getPath(remFile1Path);
+ assertHierarchyTargetFolderExists(file1.getParent());
+
+ String expected = "Hello world: " + getCurrentTestName();
+ outputDebugMessage("Write initial data to %s", file1);
+ Files.write(file1, expected.getBytes(StandardCharsets.UTF_8));
+ String buf = new String(Files.readAllBytes(file1), StandardCharsets.UTF_8);
+ assertEquals("Mismatched read test data", expected, buf);
+
+ if (version >= SftpConstants.SFTP_V4) {
+ testAclFileAttributeView(file1);
+ }
+
+ String remFile2Path = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, clientFolder.resolve("file-2.txt"));
+ Path file2 = fs.getPath(remFile2Path);
+ String remFile3Path = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, clientFolder.resolve("file-3.txt"));
+ Path file3 = fs.getPath(remFile3Path);
+ try {
+ outputDebugMessage("Move with failure expected %s => %s", file2, file3);
+ Files.move(file2, file3, LinkOption.NOFOLLOW_LINKS);
+ fail("Unexpected success in moving " + file2 + " => " + file3);
+ } catch (NoSuchFileException e) {
+ // expected
+ }
+
+ Files.write(file2, "h".getBytes(StandardCharsets.UTF_8));
+ try {
+ outputDebugMessage("Move with failure expected %s => %s", file1, file2);
+ Files.move(file1, file2, LinkOption.NOFOLLOW_LINKS);
+ fail("Unexpected success in moving " + file1 + " => " + file2);
+ } catch (FileAlreadyExistsException e) {
+ // expected
+ }
+
+ outputDebugMessage("Move with success expected %s => %s", file1, file2);
+ Files.move(file1, file2, LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING);
+ outputDebugMessage("Move with success expected %s => %s", file2, file1);
+ Files.move(file2, file1, LinkOption.NOFOLLOW_LINKS);
+
+ Map<String, Object> attrs = Files.readAttributes(file1, "*");
+ outputDebugMessage("%s attributes: %s", file1, attrs);
+
+ // TODO there are many issues with symbolic links on Windows
+ if (OsUtils.isUNIX()) {
+ Path link = fs.getPath(remFile2Path);
+ Path linkParent = link.getParent();
+ Path relPath = linkParent.relativize(file1);
+
+ testSymbolicLinks(link, relPath);
+ }
+
+ attrs = Files.readAttributes(file1, "*", LinkOption.NOFOLLOW_LINKS);
+ outputDebugMessage("%s no-follow attributes: %s", file1, attrs);
+ assertEquals("Mismatched symlink data", expected, new String(Files.readAllBytes(file1), StandardCharsets.UTF_8));
+
+ testFileChannelLock(file1);
+
+ Files.delete(file1);
+ }
+
+ protected static Iterable<Path> testRootDirs(FileSystem fs) throws IOException {
+ Iterable<Path> rootDirs = fs.getRootDirectories();
+ for (Path root : rootDirs) {
+ String rootName = root.toString();
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(root)) {
+ for (Path child : ds) {
+ String name = child.getFileName().toString();
+ assertNotEquals("Unexpected dot name", ".", name);
+ assertNotEquals("Unexpected dotdot name", "..", name);
+ outputDebugMessage("[%s] %s", rootName, child);
+ }
+ } catch (IOException | RuntimeException e) {
+ // TODO on Windows one might get share problems for *.sys files
+ // e.g. "C:\hiberfil.sys: The process cannot access the file because it is being used by another
+ // process"
+ // for now, Windows is less of a target so we are lenient with it
+ if (OsUtils.isWin32()) {
+ System.err.println(
+ e.getClass().getSimpleName() + " while accessing children of root=" + root + ": " + e.getMessage());
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ return rootDirs;
+ }
+
+ protected static AclFileAttributeView testAclFileAttributeView(Path file) throws IOException {
+ outputDebugMessage("getFileAttributeView(%s)", file);
+ AclFileAttributeView aclView
+ = Files.getFileAttributeView(file, AclFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
+ assertNotNull("No ACL view for " + file, aclView);
+
+ Map<String, ?> attrs = Files.readAttributes(file, "acl:*", LinkOption.NOFOLLOW_LINKS);
+ outputDebugMessage("readAttributes(%s) %s", file, attrs);
+ assertEquals("Mismatched owner for " + file, aclView.getOwner(), attrs.get("owner"));
+
+ @SuppressWarnings("unchecked")
+ List<AclEntry> acl = (List<AclEntry>) attrs.get("acl");
+ outputDebugMessage("acls(%s) %s", file, acl);
+ assertListEquals("Mismatched ACLs for " + file, aclView.getAcl(), acl);
+
+ return aclView;
+ }
+
+ protected static void testSymbolicLinks(Path link, Path relPath) throws IOException {
+ outputDebugMessage("Create symlink %s => %s", link, relPath);
+ Files.createSymbolicLink(link, relPath);
+ assertTrue("Not a symbolic link: " + link, Files.isSymbolicLink(link));
+
+ Path symLink = Files.readSymbolicLink(link);
+ assertEquals("mismatched symbolic link name", relPath.toString(), symLink.toString());
+
+ outputDebugMessage("Delete symlink %s", link);
+ Files.delete(link);
+ }
+
+ protected static void testFileChannelLock(Path file) throws IOException {
+ try (FileChannel channel = FileChannel.open(file)) {
+ try (FileLock lock = channel.lock()) {
+ outputDebugMessage("Lock %s: %s", file, lock);
+
+ try (FileChannel channel2 = FileChannel.open(file)) {
+ try (FileLock lock2 = channel2.lock()) {
+ fail("Unexpected success in re-locking " + file + ": " + lock2);
+ } catch (OverlappingFileLockException e) {
+ // expected
+ }
+ }
+ }
+ }
+ }
+
protected static FileSystem createSftpFileSystem(ClientSession session, SftpVersionSelector selector) throws IOException {
return SftpClientFactory.instance().createSftpFileSystem(session, selector);
}
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpDirectoryScannersTest.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpDirectoryScannersTest.java
index 12ee16b..995eb35 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpDirectoryScannersTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpDirectoryScannersTest.java
@@ -22,11 +22,13 @@ package org.apache.sshd.sftp.client.fs;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -91,6 +93,79 @@ public class SftpDirectoryScannersTest extends AbstractSftpFilesSystemSupport {
testSftpClientDirectoryScanner(setupFileSuffixMatching(), "*.txt");
}
+ @Test // see SSHD-1102
+ public void testDirectoryStreamFilter() throws IOException {
+ SetupDetails details = setupFileSuffixMatching();
+ List<Path> expected = details.getExpected();
+ List<Path> actual = new ArrayList<>();
+ try (FileSystem fs = FileSystems.newFileSystem(createDefaultFileSystemURI(), Collections.emptyMap())) {
+ DirectoryStream.Filter<Path> filter = p -> {
+ if (Files.isDirectory(p)) {
+ return true;
+ }
+
+ if (!Files.isRegularFile(p)) {
+ return false;
+ }
+
+ return p.getFileName().toString().endsWith(".txt");
+ };
+ collectMatchingFiles(fs.getPath(details.getRemoteFilePath()), filter, actual);
+ }
+
+ Collections.sort(actual);
+
+ assertListEquals(getCurrentTestName(), expected, actual, PathUtils.EQ_CASE_SENSITIVE_FILENAME);
+ }
+
+ private static void collectMatchingFiles(
+ Path dir, DirectoryStream.Filter<? super Path> filter, Collection<Path> matches)
+ throws IOException {
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir, filter)) {
+ for (Path p : ds) {
+ assertTrue("Unfiltered path: " + p, filter.accept(p));
+
+ if (Files.isDirectory(p)) {
+ collectMatchingFiles(p, filter, matches);
+ } else if (Files.isRegularFile(p)) {
+ matches.add(p);
+ }
+ }
+ }
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testClosedDirectoryStreamIteration() throws IOException {
+ SetupDetails details = setupDeepScanning();
+ try (FileSystem fs = FileSystems.newFileSystem(createDefaultFileSystemURI(), Collections.emptyMap())) {
+ Path dir = fs.getPath(details.getRemoteFilePath());
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir)) {
+ ds.close();
+
+ for (Path p : ds) {
+ fail("Unexpected iterated path: " + p);
+ }
+ }
+ }
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testDirectoryStreamRepeatedIteration() throws IOException {
+ SetupDetails details = setupDeepScanning();
+ try (FileSystem fs = FileSystems.newFileSystem(createDefaultFileSystemURI(), Collections.emptyMap())) {
+ Path dir = fs.getPath(details.getRemoteFilePath());
+ try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir)) {
+ for (Path p : ds) {
+ assertNotNull(p);
+ }
+
+ for (Path p : ds) {
+ fail("Unexpected iterated path: " + p);
+ }
+ }
+ }
+ }
+
private void testSftpClientDirectoryScanner(SetupDetails setup, String pattern) throws IOException {
List<Path> expected = setup.getExpected();
String remRoot = setup.getRemoteFilePath();
diff --git a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpFileSystemTest.java b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpFileSystemTest.java
index 94727ca..12552ed 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpFileSystemTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/fs/SftpFileSystemTest.java
@@ -26,22 +26,13 @@ import java.io.Reader;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.nio.channels.OverlappingFileLockException;
import java.nio.charset.StandardCharsets;
-import java.nio.file.DirectoryStream;
-import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
-import java.nio.file.LinkOption;
-import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
-import java.nio.file.attribute.AclEntry;
-import java.nio.file.attribute.AclFileAttributeView;
import java.nio.file.attribute.FileAttributeView;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.GroupPrincipal;
@@ -341,131 +332,4 @@ public class SftpFileSystemTest extends AbstractSftpFilesSystemSupport {
assertTrue("No configuration found", found);
}
-
- private void testFileSystem(FileSystem fs, int version) throws Exception {
- Iterable<Path> rootDirs = fs.getRootDirectories();
- for (Path root : rootDirs) {
- String rootName = root.toString();
- try (DirectoryStream<Path> ds = Files.newDirectoryStream(root)) {
- for (Path child : ds) {
- String name = child.getFileName().toString();
- assertNotEquals("Unexpected dot name", ".", name);
- assertNotEquals("Unexpected dotdot name", "..", name);
- outputDebugMessage("[%s] %s", rootName, child);
- }
- } catch (IOException | RuntimeException e) {
- // TODO on Windows one might get share problems for *.sys files
- // e.g. "C:\hiberfil.sys: The process cannot access the file because it is being used by another
- // process"
- // for now, Windows is less of a target so we are lenient with it
- if (OsUtils.isWin32()) {
- System.err.println(
- e.getClass().getSimpleName() + " while accessing children of root=" + root + ": " + e.getMessage());
- } else {
- throw e;
- }
- }
- }
-
- Path targetPath = detectTargetFolder();
- Path lclSftp = CommonTestSupportUtils.resolve(targetPath,
- SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
- CommonTestSupportUtils.deleteRecursive(lclSftp);
-
- Path current = fs.getPath(".").toRealPath().normalize();
- outputDebugMessage("CWD: %s", current);
-
- Path parentPath = targetPath.getParent();
- Path clientFolder = lclSftp.resolve("client");
- String remFile1Path = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, clientFolder.resolve("file-1.txt"));
- Path file1 = fs.getPath(remFile1Path);
- assertHierarchyTargetFolderExists(file1.getParent());
-
- String expected = "Hello world: " + getCurrentTestName();
- outputDebugMessage("Write initial data to %s", file1);
- Files.write(file1, expected.getBytes(StandardCharsets.UTF_8));
- String buf = new String(Files.readAllBytes(file1), StandardCharsets.UTF_8);
- assertEquals("Mismatched read test data", expected, buf);
-
- if (version >= SftpConstants.SFTP_V4) {
- outputDebugMessage("getFileAttributeView(%s)", file1);
- AclFileAttributeView aclView
- = Files.getFileAttributeView(file1, AclFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
- assertNotNull("No ACL view for " + file1, aclView);
-
- Map<String, ?> attrs = Files.readAttributes(file1, "acl:*", LinkOption.NOFOLLOW_LINKS);
- outputDebugMessage("readAttributes(%s) %s", file1, attrs);
- assertEquals("Mismatched owner for " + file1, aclView.getOwner(), attrs.get("owner"));
-
- @SuppressWarnings("unchecked")
- List<AclEntry> acl = (List<AclEntry>) attrs.get("acl");
- outputDebugMessage("acls(%s) %s", file1, acl);
- assertListEquals("Mismatched ACLs for " + file1, aclView.getAcl(), acl);
- }
-
- String remFile2Path = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, clientFolder.resolve("file-2.txt"));
- Path file2 = fs.getPath(remFile2Path);
- String remFile3Path = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, clientFolder.resolve("file-3.txt"));
- Path file3 = fs.getPath(remFile3Path);
- try {
- outputDebugMessage("Move with failure expected %s => %s", file2, file3);
- Files.move(file2, file3, LinkOption.NOFOLLOW_LINKS);
- fail("Unexpected success in moving " + file2 + " => " + file3);
- } catch (NoSuchFileException e) {
- // expected
- }
-
- Files.write(file2, "h".getBytes(StandardCharsets.UTF_8));
- try {
- outputDebugMessage("Move with failure expected %s => %s", file1, file2);
- Files.move(file1, file2, LinkOption.NOFOLLOW_LINKS);
- fail("Unexpected success in moving " + file1 + " => " + file2);
- } catch (FileAlreadyExistsException e) {
- // expected
- }
-
- outputDebugMessage("Move with success expected %s => %s", file1, file2);
- Files.move(file1, file2, LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING);
- outputDebugMessage("Move with success expected %s => %s", file2, file1);
- Files.move(file2, file1, LinkOption.NOFOLLOW_LINKS);
-
- Map<String, Object> attrs = Files.readAttributes(file1, "*");
- outputDebugMessage("%s attributes: %s", file1, attrs);
-
- // TODO there are many issues with symbolic links on Windows
- if (OsUtils.isUNIX()) {
- Path link = fs.getPath(remFile2Path);
- Path linkParent = link.getParent();
- Path relPath = linkParent.relativize(file1);
- outputDebugMessage("Create symlink %s => %s", link, relPath);
- Files.createSymbolicLink(link, relPath);
- assertTrue("Not a symbolic link: " + link, Files.isSymbolicLink(link));
-
- Path symLink = Files.readSymbolicLink(link);
- assertEquals("mismatched symbolic link name", relPath.toString(), symLink.toString());
-
- outputDebugMessage("Delete symlink %s", link);
- Files.delete(link);
- }
-
- attrs = Files.readAttributes(file1, "*", LinkOption.NOFOLLOW_LINKS);
- outputDebugMessage("%s no-follow attributes: %s", file1, attrs);
- assertEquals("Mismatched symlink data", expected, new String(Files.readAllBytes(file1), StandardCharsets.UTF_8));
-
- try (FileChannel channel = FileChannel.open(file1)) {
- try (FileLock lock = channel.lock()) {
- outputDebugMessage("Lock %s: %s", file1, lock);
-
- try (FileChannel channel2 = FileChannel.open(file1)) {
- try (FileLock lock2 = channel2.lock()) {
- fail("Unexpected success in re-locking " + file1 + ": " + lock2);
- } catch (OverlappingFileLockException e) {
- // expected
- }
- }
- }
- }
-
- Files.delete(file1);
- }
}