# HG changeset patch # Parent 4fefcedaef32f32eb932e4fee8186ff559ee3a15 diff --git a/masterfs/nbproject/project.properties b/masterfs/nbproject/project.properties --- a/masterfs/nbproject/project.properties +++ b/masterfs/nbproject/project.properties @@ -59,4 +59,4 @@ **/SlowRefreshAndPriorityIOTest.class,\ **/SlowRefreshSuspendableTest.class,\ **/StatFilesTest.class -spec.version.base=2.51.0 +spec.version.base=2.52 diff --git a/masterfs/nbproject/project.xml b/masterfs/nbproject/project.xml --- a/masterfs/nbproject/project.xml +++ b/masterfs/nbproject/project.xml @@ -87,7 +87,7 @@ - 8.0 + 8.10 diff --git a/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/BaseFileObj.java b/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/BaseFileObj.java --- a/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/BaseFileObj.java +++ b/masterfs/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/BaseFileObj.java @@ -62,6 +62,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Date; @@ -1084,6 +1087,86 @@ FolderObj getExistingParent() { return getExistingParentFor(getFileName().getFile(), getFactory()); } + + /** + * Get {@link Path} object for this BaseFileObj. + */ + private Path getNativePath() throws IOException { + File file = getFileName().getFile(); + final Path path; + try { + path = file.toPath(); + } catch (RuntimeException e) { + throw new IOException("Cannot get Path for " + this, e); //NOI18N + } + return path; + } + + @Override + public boolean isSymbolicLink() throws IOException { + Path p = getNativePath(); + return Files.isSymbolicLink(p); + } + + @Override + public FileObject readSymbolicLink() throws IOException { + final Path path = getNativePath(); + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction() { + + @Override + public FileObject run() throws Exception { + Path target = Files.readSymbolicLink(path); + Path absoluteTarget = target.isAbsolute() + ? target + : path.getParent().resolve(target); + File file = absoluteTarget.toFile(); + File normFile = FileUtil.normalizeFile(file); + return FileBasedFileSystem.getFileObject(normFile); + } + }); + } catch (PrivilegedActionException ex) { + throw new IOException(ex); + } + } + + @Override + public String readSymbolicLinkPath() throws IOException { + final Path path = getNativePath(); + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction() { + + @Override + public String run() throws Exception { + Path target = Files.readSymbolicLink(path); + return target.toString(); + } + }); + } catch (PrivilegedActionException ex) { + throw new IOException(ex); + } + } + + @Override + public FileObject getCanonicalFileObject() throws IOException { + final Path path = getNativePath(); + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction() { + + @Override + public FileObject run() throws Exception { + Path realPath = path.toRealPath(); + File realFile = realPath.toFile(); + return FileBasedFileSystem.getFileObject(realFile); + } + }); + } catch (PrivilegedActionException ex) { + throw new IOException(ex); + } + } private static class FileEventImpl extends FileEvent implements Enumeration { static { 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 new file mode 100644 --- /dev/null +++ b/masterfs/test/unit/src/org/netbeans/modules/masterfs/filebasedfs/fileobjects/FileObjSymlinkTest.java @@ -0,0 +1,285 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2013 Sun Microsystems, Inc. + */ +package org.netbeans.modules.masterfs.filebasedfs.fileobjects; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.netbeans.junit.NbTestCase; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; + +/** + * Test support for detection and reading of symbolic links. + * + * @author jhavlin + */ +public class FileObjSymlinkTest extends NbTestCase { + + public FileObjSymlinkTest(String name) { + super(name); + } + + @Override + protected void setUp() throws Exception { + deleteSymlinks(getWorkDir()); + clearWorkDir(); + } + + public void testIsSymbolicLink() throws IOException { + if (!checkSymlinksSupported()) { + return; + } + File dir = getWorkDir(); + Path p = dir.toPath(); + Path data = p.resolve("data.dat"); + Path link = p.resolve("link.lk"); + data.toFile().createNewFile(); + Files.createSymbolicLink(link, data); + FileObject dirFO = FileUtil.toFileObject(dir); + dirFO.refresh(); + FileObject dataFO = dirFO.getFileObject("data.dat"); + FileObject linkFO = dirFO.getFileObject("link.lk"); + assertFalse(dataFO.isSymbolicLink()); + assertTrue(linkFO.isSymbolicLink()); + } + + /** + * Test isRecursiveSymbolicLink method. Use this folder tree: + *
+     * - workdir
+     *   - a
+     *     - b
+     *       - c (symlink to a)
+     *       - d (symlink to e)
+     *   - e
+     * 
+ * + * @throws java.io.IOException + */ + public void testIsRecursiveSymbolicLink() throws IOException { + if (!checkSymlinksSupported()) { + return; + } + File dir = getWorkDir(); + File a = new File(dir, "a"); + File b = new File(a, "b"); + File c = new File(b, "c"); + File d = new File(b, "d"); + File e = new File(dir, "e"); + b.mkdirs(); + e.mkdirs(); + Files.createSymbolicLink(c.toPath(), a.toPath()); + Files.createSymbolicLink(d.toPath(), e.toPath()); + FileObject dirFO = FileUtil.toFileObject(dir); + dirFO.refresh(); + FileObject cFO = dirFO.getFileObject("a/b/c"); + FileObject dFO = dirFO.getFileObject("a/b/d"); + assertTrue(FileUtil.isRecursiveSymbolicLink(cFO)); + assertFalse(FileUtil.isRecursiveSymbolicLink(dFO)); + assertFalse(FileUtil.isRecursiveSymbolicLink(dirFO)); + } + + /** + * Test isRecursiveSymbolicLink method. Use this folder tree: + *
+     * - workdir
+     *   - a
+     *     - b
+     *       - c (symlink to d)
+     *   - d (symlink to a)
+     * 
+ * + * @throws java.io.IOException + */ + public void testIsRecursiveSymbolicLinkIndirect() throws IOException { + if (!checkSymlinksSupported()) { + return; + } + File dir = getWorkDir(); + File a = new File(dir, "a"); + File b = new File(a, "b"); + File c = new File(b, "c"); + File d = new File(dir, "d"); + b.mkdirs(); + Files.createSymbolicLink(d.toPath(), a.toPath()); + Files.createSymbolicLink(c.toPath(), d.toPath()); + FileObject dirFO = FileUtil.toFileObject(dir); + FileObject cFO = dirFO.getFileObject("a/b/c"); + assertTrue(FileUtil.isRecursiveSymbolicLink(cFO)); + } + + public void testReadSymbolicLinkAbsolute() throws IOException { + if (!checkSymlinksSupported()) { + return; + } + File dir = getWorkDir(); + File data = new File(dir, "data.dat"); + File link = new File(dir, "link.lnk"); + data.createNewFile(); + Files.createSymbolicLink(link.toPath(), data.toPath()); + FileObject linkFO = FileUtil.toFileObject(link); + FileObject dataFO = linkFO.readSymbolicLink(); + assertNotSame(linkFO, dataFO); + assertNotNull(dataFO); + assertEquals("data.dat", dataFO.getNameExt()); + } + + public void testReadSymbolicLinkRelative() throws IOException { + if (!checkSymlinksSupported()) { + return; + } + File dir = getWorkDir(); + File folder = new File(dir, "folder"); + File link = new File(dir, "link"); + folder.mkdir(); + Path lp = Files.createSymbolicLink(link.toPath(), Paths.get("folder")); + assertNotNull(lp); + FileObject linkFO = FileUtil.toFileObject(link); + assertNotNull(linkFO); + FileObject dataFO = linkFO.readSymbolicLink(); + assertNotSame(linkFO, dataFO); + assertNotNull(dataFO); + assertEquals("folder", dataFO.getNameExt()); + } + + public void testReadSymbolicLinkPath() throws IOException { + if (!checkSymlinksSupported()) { + return; + } + File dir = getWorkDir(); + File data = new File(dir, "data.dat"); + File link = new File(dir, "link.lnk"); + data.createNewFile(); + Files.createSymbolicLink(link.toPath(), data.toPath()); + FileObject linkFO = FileUtil.toFileObject(link); + assertTrue(linkFO.readSymbolicLinkPath().endsWith("data.dat")); + } + + /** + * Test getCanonicalFileObject method. + * + * Use this directory tree: + *
+     * - workdir
+     *   - a
+     *     - data.dat
+     *   - b
+     *     - link.lnk (symlink to data.dat)
+     *   - c
+     *     - link2.lnk (symlink to link.link)
+     *   - d
+     *     - folderLink (symlink to c)
+     * 
+ * @throws java.io.IOException + */ + public void testGetRealFileObject() throws IOException { + if (!checkSymlinksSupported()) { + return; + } + File dir = getWorkDir(); + File a = new File(dir, "a"); + File dataDat = new File(a, "data.dat"); + File b = new File(dir, "b"); + File linkLnk = new File(b, "link.lnk"); + File c = new File(dir, "c"); + File link2Lnk = new File(c, "link2.lnk"); + File d = new File(dir, "d"); + File folderLink = new File(d, "folderLink"); + a.mkdir(); + dataDat.createNewFile(); + b.mkdir(); + Files.createSymbolicLink(linkLnk.toPath(), dataDat.toPath()); + c.mkdir(); + Files.createSymbolicLink(link2Lnk.toPath(), linkLnk.toPath()); + d.mkdir(); + Files.createSymbolicLink(folderLink.toPath(), c.toPath()); + FileObject dirFO = FileUtil.toFileObject(dir); + dirFO.refresh(); + FileObject fo = dirFO.getFileObject("d/folderLink/link2.lnk"); + assertNotNull(fo); + FileObject realFO = fo.getCanonicalFileObject(); + assertNotNull(realFO); + assertTrue(realFO.getPath().endsWith("a/data.dat")); + } + + /** + * Recursively delete all symlinks in a directory. + */ + private void deleteSymlinks(File root) { + for (File f : root.listFiles()) { + if (Files.isSymbolicLink(f.toPath())) { + f.delete(); + } else if (f.isDirectory()) { + deleteSymlinks(f); + } + } + } + + private boolean checkSymlinksSupported() { + File dir; + try { + dir = getWorkDir(); + } catch (IOException ex) { + printSkipping(); + return false; + } + File a = new File(dir, "a"); + try { + File lk = new File(dir, "lk"); + Files.createSymbolicLink(lk.toPath(), a.toPath()); + lk.delete(); + return true; + } catch (RuntimeException e) { + } catch (IOException ex) { + } + printSkipping(); + return false; + } + + private void printSkipping() { + System.out.println( + "Symbolic links are not supported, skipping test " + getName()); + } +} diff --git a/openide.filesystems/apichanges.xml b/openide.filesystems/apichanges.xml --- a/openide.filesystems/apichanges.xml +++ b/openide.filesystems/apichanges.xml @@ -49,6 +49,36 @@ Filesystems API + + + Support detection and reading of symbolic links. + + + + + +

+ Add methods to FileObject for handling of + symbolic links: +

+
    +
  • isSymbolicLink()
  • +
  • readSymbolicLink()
  • +
  • readSymbolicLinkPath()
  • +
  • getCanonicalFileObject()
  • +
+

+ Add utility method to FileUtil for dealing with + recursive symbolic links. +

+
    +
  • isRecursiveSymbolicLink()
  • +
+
+ + + +
FileLock implements AutoCloseable diff --git a/openide.filesystems/manifest.mf b/openide.filesystems/manifest.mf --- a/openide.filesystems/manifest.mf +++ b/openide.filesystems/manifest.mf @@ -2,6 +2,6 @@ OpenIDE-Module: org.openide.filesystems OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml -OpenIDE-Module-Specification-Version: 9.3 +OpenIDE-Module-Specification-Version: 9.4 diff --git a/openide.filesystems/src/org/openide/filesystems/AbstractFileSystem.java b/openide.filesystems/src/org/openide/filesystems/AbstractFileSystem.java --- a/openide.filesystems/src/org/openide/filesystems/AbstractFileSystem.java +++ b/openide.filesystems/src/org/openide/filesystems/AbstractFileSystem.java @@ -659,6 +659,61 @@ public void markUnimportant(String name); } + @SuppressWarnings("PublicInnerClass") + public interface Nio2Info extends Serializable { + + /** + * Check whether a file represents a symbolic link. + * + * @param name Name of the file. + * + * @return True if this file represents a symbolic link, false + * otherwise. + * @throws java.io.IOException If some I/O problem occurs. + * @since openide.filesystem/9.4 + * + * @see #readSymbolicLink(java.lang.String) + * @see #getCanonicalName(java.lang.String) + */ + boolean isSymbolicLink(String name) throws IOException; + + /** + * Read symbolic link. + * + * If the file represents a symbolic link, return its target path. + * Otherwise the return value is undefined, or + * {@link IllegalArgumentException} can be thrown. + * + * This method does not perform any normalization. If the target of + * symbolic link is defined using relative path, this relative path will + * be returned. + * + * @param name Name of the file. + * + * @throws java.io.IOException If some I/O problem occurs. + * @since openide.filesystem/9.4 + * + * @return Target of the symbolic link (as absolute or relative path), + * or some undefined value if {@code name} does not represent symbolic + * link. + * + * @see #isSymbolicLink(java.lang.String) + */ + String readSymbolicLink(String name) throws IOException; + + /** + * Get canonical file name (resolve all symbolic links). + * + * @param name Name of the file. + * + * @return File name that represents the same file as {@code name} and + * where all symbolic links are resolved. + * @throws java.io.IOException If some I/O problem occurs. + * @since openide.filesystem/9.4 + */ + String getCanonicalName(String name) throws IOException; + } + /** Handle attributes of files. */ public interface Attr extends Serializable { 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 @@ -902,8 +902,12 @@ public FileObject process(FileObject fo, Collection toAdd) { if (rec && fo.isFolder()) { for (FileObject child : fo.getChildren()) { - if (!FileUtil.isRecursiveSymlink(child)) { // #218795 - toAdd.add(child); + try { + if (!FileUtil.isRecursiveSymbolicLink(child)) { // #218795 + toAdd.add(child); + } + } catch (IOException ex) { + ExternalUtil.LOG.log(Level.INFO, null, ex); } } } @@ -1253,6 +1257,73 @@ return false; } + /** + * Check whether this FileObject is a symbolic link. + * + * The default implementation returns false, but on filesystems that support + * symbolic links this method should be overriden. + * + * @return True if this FileObject represents a symbolic link, false + * otherwise. + * @throws java.io.IOException If some I/O problem occurs. + * @since openide.filesystem/9.4 + */ + public boolean isSymbolicLink() throws IOException { + return false; + } + + /** + * Read symbolic link. + * + * If this FileObject represents a symbolic link, return a FileObject it + * refers to, or null if the referred file or directory does not exist. If + * this FileObject doesn't represent a symbolic link, the return value is + * undefined. + * + * The default implementation returns null, but on filesystems that support + * symbolic links this method should be overriden. + * + * @return The referred FileObject, or null if it is not available. + * @throws java.io.IOException If some I/O problem occurs. + * @since openide.filesystem/9.4 + */ + public FileObject readSymbolicLink() throws IOException { + return null; + } + + /** + * Read symbolic link path. + * + * If this FileObject represents a symbolic link, return the path it refers + * to, which can be absolute or relative. If this FileObject doesn't + * represent a symbolic link, the return value is undefined. + * + * The default implementation returns this FileObject's path, but on + * filesystems that support symbolic links this method should be overriden. + * + * @return The referred FileObject path. + * @throws java.io.IOException If some I/O problem occurs. + * @since openide.filesystem/9.4 + */ + public String readSymbolicLinkPath() throws IOException { + return this.getPath(); + } + + /** + * Return a FileObject with path where all symbolic links are resolved. + * + * The default implementation returns this object, but on filesystems that + * support symbolic links this method should be overriden. + * + * @return The FileObject with path where all symlinks are resolved, or null + * if it doesn't exist. + * @throws java.io.IOException If some I/O problem occurs. + * @since openide.filesystem/9.4 + */ + public FileObject getCanonicalFileObject() throws IOException { + return this; + } + /** Listeners registered from MultiFileObject are considered as priority * listeners. */ diff --git a/openide.filesystems/src/org/openide/filesystems/FileUtil.java b/openide.filesystems/src/org/openide/filesystems/FileUtil.java --- a/openide.filesystems/src/org/openide/filesystems/FileUtil.java +++ b/openide.filesystems/src/org/openide/filesystems/FileUtil.java @@ -58,11 +58,6 @@ import java.net.URI; import java.net.URL; import java.net.URLStreamHandler; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -1446,6 +1441,41 @@ return false; } + /** + * Check whether some FileObject is a recursive symbolic link. + * + * @param fo FileObject to check. + * + * @return True if the FileObject represents a symbolic link referring to a + * directory that is parent of this FileObject, false otherwise. + * @throws java.io.IOException If some I/O problem occurs. + * @since openide.filesystem/9.4 + */ + public static boolean isRecursiveSymbolicLink(FileObject fo) + throws IOException { + + if (!fo.isFolder()) { + return false; + } else if (fo.isSymbolicLink()) { + FileObject parent = fo.getParent(); + if (parent == null) { + return false; + } + FileObject target = fo.readSymbolicLink(); + if (target != null) { + FileObject realParent = parent.getCanonicalFileObject(); + FileObject realTarget = target.getCanonicalFileObject(); + return realParent != null && realTarget != null + && (realTarget.equals(realParent) + || FileUtil.isParentOf(realTarget, realParent)); + } else { + return false; + } + } else { + return false; + } + } + /** Creates a weak implementation of FileChangeListener. * * @param l the listener to delegate to @@ -2232,57 +2262,4 @@ int index = path.lastIndexOf('.'); //NOI18N return (index != -1) && (index > path.lastIndexOf('/') + 1); //NOI18N } - - /** - * Check whether this file is a symbolic link that targets to a folder - * higher in the path. Such link, in case of recursive folder traversing, - * would cause infinite recursion. The method should not be called from - * Event Dispatch Thread. - * - * @param fileObject FileObject to check. - * @return True if the file is a link that could cause infinite recursion, - * false otherwise. - */ - static boolean isRecursiveSymlink(FileObject fileObject) { - File file = (File) fileObject.getAttribute("java.io.File"); // NOI18N - if (file == null) { - return false; - } - final Path path; - try { - path = file.toPath(); - } catch (RuntimeException e) { - LOG.log(Level.INFO, "Cannot get path for {0}", file); //NOI18N - LOG.log(Level.FINE, null, e); - return false; - } - if (Files.isSymbolicLink(path)) { - try { - return AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public Boolean run () throws IOException { - Path target = Files.readSymbolicLink(path); - if (!target.isAbsolute()) { - target = path.resolve(target); - } - target = target.toRealPath(); - for (Path ancestor = path.getParent(); - ancestor != null; ancestor = ancestor.getParent()) { - if (target.equals(ancestor)) { - return true; - } - } - return false; - } - }); - } catch (PrivilegedActionException ex) { - LOG.log(Level.INFO, "Cannot read symbolic link {0}",//NOI18N - path); - LOG.log(Level.FINE, null, ex.getException()); - } catch (SecurityException ex) { - LOG.log(Level.INFO, null, ex); - } - } - return false; - } } diff --git a/openide.filesystems/src/org/openide/filesystems/LocalFileSystem.java b/openide.filesystems/src/org/openide/filesystems/LocalFileSystem.java --- a/openide.filesystems/src/org/openide/filesystems/LocalFileSystem.java +++ b/openide.filesystems/src/org/openide/filesystems/LocalFileSystem.java @@ -57,9 +57,11 @@ import java.io.ObjectInputValidation; import java.io.OutputStream; import java.io.SyncFailedException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Random; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.openide.util.BaseUtilities; @@ -485,6 +487,22 @@ protected void markUnimportant(String name) { } + protected boolean isSymbolicLink(String name) throws IOException { + return Files.isSymbolicLink(getPath(name)); + } + + protected String readSymbolicLink(String name) throws IOException { + return Files.readSymbolicLink(getPath(name)).toString(); + } + + protected String getCanonicalName(String name) throws IOException { + return getPath(name).toRealPath().toString(); + } + + private Path getPath(String name) { + return Paths.get(rootFile.getPath(), name); + } + /** Creates file for given string name. * @param name the name * @return the file @@ -519,8 +537,10 @@ * and Change interfaces and delegates all the methods * to appropriate methods of LocalFileSystem. */ - public static class Impl extends Object implements AbstractFileSystem.List, AbstractFileSystem.Info, - AbstractFileSystem.Change { + public static class Impl extends Object implements AbstractFileSystem.List, + AbstractFileSystem.Info, AbstractFileSystem.Nio2Info, + AbstractFileSystem.Change { + /** generated Serialized Version UID */ static final long serialVersionUID = -8432015909317698511L; @@ -690,6 +710,21 @@ public void markUnimportant(String name) { fs.markUnimportant(name); } + + @Override + public boolean isSymbolicLink(String name) throws IOException { + return fs.isSymbolicLink(name); + } + + @Override + public String readSymbolicLink(String name) throws IOException { + return fs.readSymbolicLink(name); + } + + @Override + public String getCanonicalName(String name) throws IOException { + return fs.getCanonicalName(name); + } } /** This class adds new virtual attribute "java.io.File". diff --git a/openide.filesystems/test/unit/src/org/openide/filesystems/FileUtilTest.java b/openide.filesystems/test/unit/src/org/openide/filesystems/FileUtilTest.java --- a/openide.filesystems/test/unit/src/org/openide/filesystems/FileUtilTest.java +++ b/openide.filesystems/test/unit/src/org/openide/filesystems/FileUtilTest.java @@ -370,7 +370,7 @@ new File("a:\\dummy").getCanonicalPath(); paths.put("a:\\dummy", "A:\\dummy"); } catch (IOException e) { - // if getCanonicalPath fails, normalization returns File.getAbsolutePath + // if getCanonicalName fails, normalization returns File.getAbsolutePath paths.put("a:\\dummy", "a:\\dummy"); } paths.put("C:\\", "C:\\");