You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2019/07/05 00:54:51 UTC
[commons-vfs] branch master updated: [VFS-721] Add support for
symbolic links for the local file system and add
FileObject#isSymbolicLink().
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-vfs.git
The following commit(s) were added to refs/heads/master by this push:
new 2174c55 [VFS-721] Add support for symbolic links for the local file system and add FileObject#isSymbolicLink().
2174c55 is described below
commit 2174c55e87292b6d6ee0dabe0334713ed1668c43
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Thu Jul 4 20:54:48 2019 -0400
[VFS-721] Add support for symbolic links for the local file system and
add FileObject#isSymbolicLink().
---
.../java/org/apache/commons/vfs2/FileObject.java | 11 ++
.../org/apache/commons/vfs2/Resources.properties | 1 +
.../vfs2/filter/SymbolicLinkFileFilter.java | 89 ++++++++++++++
.../commons/vfs2/provider/AbstractFileObject.java | 31 +++++
.../commons/vfs2/provider/local/LocalFile.java | 10 ++
.../apache/commons/vfs2/filter/BaseFilterTest.java | 6 +
.../vfs2/filter/SymbolicLinkFileFilterTest.java | 136 +++++++++++++++++++++
.../commons/vfs2/test/ProviderReadTests.java | 8 ++
.../commons/vfs2/test/ProviderWriteTests.java | 1 +
src/changes/changes.xml | 3 +
10 files changed, 296 insertions(+)
diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/FileObject.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/FileObject.java
index a6480b2..4ebe734 100644
--- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/FileObject.java
+++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/FileObject.java
@@ -359,6 +359,17 @@ public interface FileObject extends Comparable<FileObject>, Iterable<FileObject>
boolean isReadable() throws FileSystemException;
/**
+ * Determines if this file is a symbolic link.
+ *
+ * @return {@code true} if this file is a symbolic link, {@code false} if not.
+ * @throws FileSystemException On error determining if this file exists.
+ * @since 2.4
+ */
+ default boolean isSymbolicLink() throws FileSystemException {
+ return false;
+ }
+
+ /**
* Determines if this file can be written to.
*
* @return {@code true} if this file is writeable, {@code false} if not.
diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/Resources.properties b/commons-vfs2/src/main/java/org/apache/commons/vfs2/Resources.properties
index e5058b5..d9184d4 100644
--- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/Resources.properties
+++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/Resources.properties
@@ -57,6 +57,7 @@ vfs.provider/check-is-executable.error=Could not determine if file "{0}" is exec
vfs.provider/check-is-hidden.error=Could not determine if file "{0}" is hidden.
vfs.provider/check-is-writeable.error=Could not determine if file "{0}" is writeable.
vfs.provider/check-is-readable.error=Could not determine if file "{0}" is readable.
+vfs.provider/check-is-symbolic-link.error=Could not determine if file "{0}" is a symbolic link.
vfs.provider/set-executable.error=Could not set the executable flag of file "{0}".
vfs.provider/set-writeable.error=Could not set the writeable flag of file "{0}".
vfs.provider/set-readable.error=Could not set the readable flag of file "{0}".
diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/filter/SymbolicLinkFileFilter.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/filter/SymbolicLinkFileFilter.java
new file mode 100644
index 0000000..4ca078c
--- /dev/null
+++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/filter/SymbolicLinkFileFilter.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.vfs2.filter;
+
+import java.io.Serializable;
+
+import org.apache.commons.vfs2.FileFilter;
+import org.apache.commons.vfs2.FileSelectInfo;
+import org.apache.commons.vfs2.FileSystemException;
+
+/**
+ * This filter accepts <code>File</code>s that are symbolic links.
+ * <p>
+ * Example, showing how to print out a list of the current directory's
+ * <i>symbolic link</i> files:
+ * </p>
+ *
+ * <pre>
+ * FileSystemManager fsManager = VFS.getManager();
+ * FileObject dir = fsManager.toFileObject(new File("."));
+ * FileObject[] files = dir.findFiles(new FileFilterSelector(SymbolicLinkFileFilter.SYMBOLIC));
+ * for (int i = 0; i < files.length; i++) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * <p>
+ * Example, showing how to print out a list of the current directory's
+ * <i>actual</i> (i.e. symbolic link) files:
+ * </p>
+ *
+ * <pre>
+ * FileSystemManager fsManager = VFS.getManager();
+ * FileObject dir = fsManager.toFileObject(new File("."));
+ * FileObject[] files = dir.findFiles(new FileFilterSelector(SymbolicLinkFileFilter.ACTUAL));
+ * for (int i = 0; i < files.length; i++) {
+ * System.out.println(files[i]);
+ * }
+ * </pre>
+ *
+ * @since 2.4
+ */
+public class SymbolicLinkFileFilter implements FileFilter, Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ /** Singleton instance of <i>hidden</i> filter. */
+ public static final FileFilter SYMBOLIC = new SymbolicLinkFileFilter();
+
+ /** Singleton instance of <i>visible</i> filter. */
+ public static final FileFilter ACTUAL = new NotFileFilter(SYMBOLIC);
+
+ /**
+ * Restrictive constructor.
+ */
+ protected SymbolicLinkFileFilter() {
+ }
+
+ /**
+ * Checks to see if the file is a symbolic link. Non existing files won't be accepted.
+ *
+ * @param fileInfo the file to check
+ *
+ * @return {@code true} if the file is <i>symbolic link</i>, otherwise {@code false}.
+ * @throws FileSystemException Thrown for file system errors.
+ */
+ @Override
+ public boolean accept(final FileSelectInfo fileInfo) throws FileSystemException {
+ if (!fileInfo.getFile().exists()) {
+ return false;
+ }
+ return fileInfo.getFile().isSymbolicLink();
+ }
+
+}
diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileObject.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileObject.java
index 1c73172..1fac6f0 100644
--- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileObject.java
+++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/AbstractFileObject.java
@@ -732,6 +732,21 @@ public abstract class AbstractFileObject<AFS extends AbstractFileSystem> impleme
}
/**
+ * Determines if this file is a symbolic link. Is only called if {@link #doGetType} does not return
+ * {@link FileType#IMAGINARY}.
+ * <p>
+ * This implementation always returns false.
+ * </p>
+ *
+ * @return true if the file is readable, false otherwise.
+ * @throws Exception if an error occurs.
+ * @since 2.4
+ */
+ protected boolean doIsSymbolicLink() throws Exception {
+ return false;
+ }
+
+ /**
* Determines if this file can be written to. Is only called if {@link #doGetType} does not return
* {@link FileType#IMAGINARY}.
* <p>
@@ -1549,6 +1564,22 @@ public abstract class AbstractFileObject<AFS extends AbstractFileSystem> impleme
}
/**
+ * Determines if this file can be read.
+ *
+ * @return true if the file can be read, false otherwise.
+ * @throws FileSystemException if an error occurs.
+ * @since 2.4
+ */
+ @Override
+ public boolean isSymbolicLink() throws FileSystemException {
+ try {
+ return exists() ? doIsSymbolicLink() : false;
+ } catch (final Exception exc) {
+ throw new FileSystemException("vfs.provider/check-is-symbolic-link.error", fileName, exc);
+ }
+ }
+
+ /**
* Determines if this file can be written to.
*
* @return true if the file can be written to, false otherwise.
diff --git a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/local/LocalFile.java b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/local/LocalFile.java
index bcb770d..e0dcf59 100644
--- a/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/local/LocalFile.java
+++ b/commons-vfs2/src/main/java/org/apache/commons/vfs2/provider/local/LocalFile.java
@@ -22,6 +22,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.file.Files;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
@@ -202,6 +203,15 @@ public class LocalFile extends AbstractFileObject<LocalFileSystem> {
}
/**
+ * Determines if this file is a symbolic link.
+ * @since 2.4
+ */
+ @Override
+ protected boolean doIsSymbolicLink() throws FileSystemException {
+ return Files.isSymbolicLink(file.toPath());
+ }
+
+ /**
* Returns the children of the file.
*/
@Override
diff --git a/commons-vfs2/src/test/java/org/apache/commons/vfs2/filter/BaseFilterTest.java b/commons-vfs2/src/test/java/org/apache/commons/vfs2/filter/BaseFilterTest.java
index 2f4cdb3..7435e9d 100644
--- a/commons-vfs2/src/test/java/org/apache/commons/vfs2/filter/BaseFilterTest.java
+++ b/commons-vfs2/src/test/java/org/apache/commons/vfs2/filter/BaseFilterTest.java
@@ -28,6 +28,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@@ -73,6 +74,11 @@ public abstract class BaseFilterTest {
throw new RuntimeException(ex);
}
}
+
+ @Override
+ public String toString() {
+ return Objects.toString(fileObject);
+ }
};
} catch (final FileSystemException ex) {
throw new RuntimeException(ex);
diff --git a/commons-vfs2/src/test/java/org/apache/commons/vfs2/filter/SymbolicLinkFileFilterTest.java b/commons-vfs2/src/test/java/org/apache/commons/vfs2/filter/SymbolicLinkFileFilterTest.java
new file mode 100644
index 0000000..ff010d2
--- /dev/null
+++ b/commons-vfs2/src/test/java/org/apache/commons/vfs2/filter/SymbolicLinkFileFilterTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.vfs2.filter;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.vfs2.FileFilter;
+import org.apache.commons.vfs2.FileFilterSelector;
+import org.apache.commons.vfs2.FileObject;
+import org.apache.commons.vfs2.FileSelectInfo;
+import org.apache.commons.vfs2.FileSystemException;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Test for {@link SymbolicLinkFileFilter}.
+ * <p>
+ * On Windows, in order for this test to pass, you MUST run the VM with admin rights.
+ * </p>
+ * <p>
+ * To enable this test set the system property "SymbolicLinkFileFilterTest.Enable" to "true".
+ *
+ * <p>
+ * To run only this test with Maven:
+ * </p>
+ *
+ * <pre>
+ * mvn test -Dtest=SymbolicLinkFileFilterTest -pl commons-vfs2 -DSymbolicLinkFileFilterTest.Enable=true
+ * </pre>
+ */
+// CHECKSTYLE:OFF Test code
+public class SymbolicLinkFileFilterTest extends BaseFilterTest {
+
+ private static File testDir;
+
+ private static File targetFile;
+
+ private static FileSelectInfo targetFileInfo;
+
+ private static File linkFile;
+
+ private static FileSelectInfo linkFileInfo;
+
+ private static File notExistingFile;
+
+ private static FileSelectInfo notExistingFileInfo;
+
+ private static File zipFile;
+
+ private static FileObject zipFileObject;
+
+ @BeforeClass
+ public static void beforeClass() throws IOException {
+ testDir = getTestDir(SymbolicLinkFileFilterTest.class.getName());
+ testDir.mkdir();
+
+ linkFile = new File(testDir, "visible.txt");
+ linkFileInfo = createFileSelectInfo(linkFile);
+
+ targetFile = new File(testDir, "symbolic.txt");
+ Files.deleteIfExists(targetFile.toPath());
+ FileUtils.touch(targetFile);
+ Files.createSymbolicLink(linkFile.toPath(), targetFile.toPath());
+ targetFileInfo = createFileSelectInfo(targetFile);
+
+ notExistingFile = new File(testDir, "not-existing-file.txt");
+ notExistingFileInfo = createFileSelectInfo(notExistingFile);
+
+ // Zip the test directory
+ zipFile = new File(getTempDir(), SymbolicLinkFileFilterTest.class.getName() + ".zip");
+ zipDir(testDir, "", zipFile);
+ zipFileObject = getZipFileObject(zipFile);
+ }
+
+ @AfterClass
+ public static void afterClass() throws IOException {
+ Assume.assumeTrue(Boolean.getBoolean(SymbolicLinkFileFilterTest.class.getSimpleName() + ".Enable"));
+ targetFile = null;
+ targetFileInfo = null;
+ linkFile = null;
+ linkFileInfo = null;
+ notExistingFile = null;
+ notExistingFileInfo = null;
+ if (zipFileObject != null) {
+ zipFileObject.close();
+ }
+ FileUtils.deleteQuietly(zipFile);
+ zipFile = null;
+ FileUtils.deleteDirectory(testDir);
+ testDir = null;
+ }
+
+ @Test
+ public void testAcceptActual() throws FileSystemException {
+ final FileFilter testee = SymbolicLinkFileFilter.ACTUAL;
+ Assert.assertTrue(targetFileInfo.getBaseFolder().exists());
+ Assert.assertTrue(targetFileInfo.getFile().exists());
+ Assert.assertTrue(targetFileInfo.toString(), testee.accept(targetFileInfo));
+ Assert.assertTrue(notExistingFileInfo.toString(), testee.accept(notExistingFileInfo));
+ }
+
+ @Test
+ public void testAcceptSymbolic() throws FileSystemException {
+ final FileFilter testee = SymbolicLinkFileFilter.SYMBOLIC;
+ Assert.assertTrue(linkFileInfo.toString(), testee.accept(linkFileInfo));
+ Assert.assertFalse(notExistingFileInfo.toString(), testee.accept(notExistingFileInfo));
+ }
+
+ @Test
+ public void testZipFile() throws FileSystemException {
+ FileObject[] files = zipFileObject.findFiles(new FileFilterSelector(SymbolicLinkFileFilter.SYMBOLIC));
+ Assert.assertEquals(0, files.length);
+ }
+
+}
+// CHECKSTYLE:ON
diff --git a/commons-vfs2/src/test/java/org/apache/commons/vfs2/test/ProviderReadTests.java b/commons-vfs2/src/test/java/org/apache/commons/vfs2/test/ProviderReadTests.java
index ec750fc..896d30f 100644
--- a/commons-vfs2/src/test/java/org/apache/commons/vfs2/test/ProviderReadTests.java
+++ b/commons-vfs2/src/test/java/org/apache/commons/vfs2/test/ProviderReadTests.java
@@ -210,6 +210,14 @@ public class ProviderReadTests extends AbstractProviderTestCase {
}
/**
+ * Tests that test read folder is not a symbolic link.
+ */
+ public void testFolderIsSymbolicLink() throws Exception {
+ final FileObject folder = getReadFolderDir1();
+ Assert.assertFalse(folder.isSymbolicLink());
+ }
+
+ /**
* Tests that test read folder is readable.
*/
public void testFolderIsReadable() throws Exception {
diff --git a/commons-vfs2/src/test/java/org/apache/commons/vfs2/test/ProviderWriteTests.java b/commons-vfs2/src/test/java/org/apache/commons/vfs2/test/ProviderWriteTests.java
index 3677fe5..9a8e0fe 100644
--- a/commons-vfs2/src/test/java/org/apache/commons/vfs2/test/ProviderWriteTests.java
+++ b/commons-vfs2/src/test/java/org/apache/commons/vfs2/test/ProviderWriteTests.java
@@ -111,6 +111,7 @@ public class ProviderWriteTests extends AbstractProviderTestCase {
assertTrue(file.isFile());
assertEquals(0, file.getContent().getSize());
assertFalse(file.isHidden());
+ assertFalse(file.isSymbolicLink());
assertTrue(file.isReadable());
assertTrue(file.isWriteable());
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index f3c00f5..3be7076 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -137,6 +137,9 @@ The <action> type attribute can be add,update,fix,remove.
<action issue="VFS-720" dev="ggregory" type="add" due-to="Boris Petrov">
Implement Closeable for RandomAccessContent #66.
</action>
+ <action issue="VFS-721" dev="ggregory" type="add" due-to="Gary Gregory">
+ Add support for symbolic links for the local file system and add FileObject#isSymbolicLink().
+ </action>
</release>
<release version="2.3" date="2019-02-01" description="New features and bug fix release.">
<action issue="VFS-645" dev="ggregory" type="fix">