# HG changeset patch # Parent 837bba5fec5b7695a4652fbccf374a5bc1f903c4 diff --git a/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileObjSymlinkTest.java b/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileObjSymlinkTest.java --- a/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileObjSymlinkTest.java +++ b/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileObjSymlinkTest.java @@ -278,6 +278,52 @@ return false; } + /** + * Test that copy operations skips recursive symbolic links. See bug 225991. + * + * Use this directory tree for testing. + *
+     *  - source
+     *    - a
+     *      - b (symbolic link to a)
+     *    - c
+     *      - data.txt
+     *  - target
+     * 
+ * + * @throws java.io.IOException + */ + public void testCopySkipsRecursiveSymlinks() throws IOException { + if (!checkSymlinksSupported()) { + return; + } + File dir = getWorkDir(); + FileObject dirFO = FileUtil.toFileObject(dir); + File source, a, b = null, c, dataTxt; + try { + source = new File(dir, "source"); + a = new File(source, "a"); + b = new File(a, "b"); + c = new File(source, "c"); + dataTxt = new File(c, "data.txt"); + a.mkdirs(); + c.mkdir(); + dataTxt.createNewFile(); + Files.createSymbolicLink(b.toPath(), a.toPath()); + + dirFO.refresh(); + dirFO.getFileObject("source").copy(dirFO, "target", null); + + assertNotNull(dirFO.getFileObject("target/a")); + assertNotNull(dirFO.getFileObject("target/c/data.txt")); + assertNull(dirFO.getFileObject("target/a/b")); + } finally { + if (b != null) { + b.delete(); + } + } + } + private void printSkipping() { System.out.println( "Symbolic links are not supported, skipping test " + getName()); diff --git a/openide.filesystems/src/org/openide/filesystems/FileObject.java b/openide.filesystems/src/org/openide/filesystems/FileObject.java --- a/openide.filesystems/src/org/openide/filesystems/FileObject.java +++ b/openide.filesystems/src/org/openide/filesystems/FileObject.java @@ -147,7 +147,12 @@ FileObject peer = target.createFolder(name); FileUtil.copyAttributes(this, peer); for (FileObject fo : getChildren()) { - fo.copy(peer, fo.getName(), fo.getExt()); + if (fo.isData() || !fo.isRecursiveSymbolicLink()) { + fo.copy(peer, fo.getName(), fo.getExt()); + } else { + ExternalUtil.LOG.log(Level.INFO, + "Skipping recursive symlink {0}", fo); //NOI18N + } } return peer; } diff --git a/openide.loaders/nbproject/project.xml b/openide.loaders/nbproject/project.xml --- a/openide.loaders/nbproject/project.xml +++ b/openide.loaders/nbproject/project.xml @@ -122,7 +122,7 @@ - 7.58 + 8.10 diff --git a/openide.loaders/src/org/openide/loaders/DataFolder.java b/openide.loaders/src/org/openide/loaders/DataFolder.java --- a/openide.loaders/src/org/openide/loaders/DataFolder.java +++ b/openide.loaders/src/org/openide/loaders/DataFolder.java @@ -594,7 +594,8 @@ while (en.hasMoreElements ()) { try { DataObject obj = en.nextElement (); - if (obj.isCopyAllowed()) { + FileObject pf = obj.getPrimaryFile(); + if (obj.isCopyAllowed() && (pf.isData() || !pf.isRecursiveSymbolicLink())) { obj.copy(newFolderDF); } else { // data object can not be copied, inform user diff --git a/openide.loaders/test/unit/src/org/openide/loaders/DataFolderTest.java b/openide.loaders/test/unit/src/org/openide/loaders/DataFolderTest.java --- a/openide.loaders/test/unit/src/org/openide/loaders/DataFolderTest.java +++ b/openide.loaders/test/unit/src/org/openide/loaders/DataFolderTest.java @@ -50,6 +50,7 @@ import java.beans.*; import java.io.File; import java.io.IOException; +import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.logging.Handler; @@ -79,6 +80,7 @@ @Override protected void setUp () throws Exception { + clearSymlinks(getWorkDir()); clearWorkDir (); } @@ -912,4 +914,69 @@ log.removeHandler(handler); } } + + /** + * Test that copy operations skips recursive symbolic links. See bug 225991. + * + * Use this directory tree for testing. + *
+     *  - source
+     *    - a
+     *      - b (symbolic link to a)
+     *    - c
+     *      - data.txt
+     *  - target
+     * 
+ * @throws java.io.IOException + */ + public void testCopySkipsRecursiveSymlinks() throws IOException { + File dir = getWorkDir(); + FileObject dirFO = FileUtil.toFileObject(dir); + File source, target, a, b = null, c, dataTxt; + try { + source = new File(dir, "source"); + a = new File(source, "a"); + b = new File(a, "b"); + c = new File(source, "c"); + dataTxt = new File(c, "data.txt"); + target = new File(dir, "target"); + a.mkdirs(); + c.mkdir(); + target.mkdir(); + dataTxt.createNewFile(); + try { + Files.createSymbolicLink(b.toPath(), a.toPath()); + } catch (IOException e) { + System.out.println("Skipping test " + getName() + + ", symlinks are not supported."); + return; + } + dirFO.refresh(); + DataObject sourceDOB = DataObject.find(dirFO.getFileObject("source")); + DataObject targetDOB = DataObject.find(dirFO.getFileObject("target")); + sourceDOB.copy((DataFolder) targetDOB); + assertNotNull(dirFO.getFileObject("target/source/a")); + assertNotNull(dirFO.getFileObject("target/source/c/data.txt")); + assertNull(dirFO.getFileObject("target/source/a/b")); + } finally { + if (b != null) { + b.delete(); + } + } + } + + /** + * Recursively delete all symbolic links in a directory. It's safer to call + * this method before {@link #clearWorkDir()} if there is risk that some + * tests can leave (recursive) symbolic links in workdir. + */ + private void clearSymlinks(File root) { + for (File f : root.listFiles()) { + if (Files.isSymbolicLink(f.toPath())) { + f.delete(); + } else if (f.isDirectory()) { + clearSymlinks(f); + } + } + } }