From e3e6d570f7065fb2d55287a98ef3b24b6a0b2e6a Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 21 Feb 2018 15:55:38 -0500 Subject: [PATCH] VirtualFile.readLink --- core/src/main/java/hudson/Util.java | 4 +-- .../main/java/jenkins/util/VirtualFile.java | 25 +++++++++++++++++++ .../java/jenkins/util/VirtualFileTest.java | 17 +++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/Util.java b/core/src/main/java/hudson/Util.java index ce381d7a0a..2f7ea8fcc6 100644 --- a/core/src/main/java/hudson/Util.java +++ b/core/src/main/java/hudson/Util.java @@ -1403,7 +1403,7 @@ public class Util { * The relative path is meant to be resolved from the location of the symlink. */ @CheckForNull - public static String resolveSymlink(@Nonnull File link) throws InterruptedException, IOException { + public static String resolveSymlink(@Nonnull File link) throws IOException { try { Path path = link.toPath(); return Files.readSymbolicLink(path).toString(); @@ -1415,7 +1415,7 @@ public class Util { } catch (IOException x) { throw x; } catch (Exception x) { - throw (IOException) new IOException(x.toString()).initCause(x); + throw new IOException(x); } } diff --git a/core/src/main/java/jenkins/util/VirtualFile.java b/core/src/main/java/jenkins/util/VirtualFile.java index 6cf765f398..434fefd827 100644 --- a/core/src/main/java/jenkins/util/VirtualFile.java +++ b/core/src/main/java/jenkins/util/VirtualFile.java @@ -139,8 +139,20 @@ public abstract class VirtualFile implements Comparable, Serializab */ public abstract boolean isFile() throws IOException; + /** + * If this file is a symlink, returns the link target. + *

The default implementation always returns null. + * Some implementations may not support symlinks under any conditions. + * @return a target (typically a relative path in some format), or null if this is not a link + * @throws IOException if reading the link, or even determining whether this file is a link, failed + */ + public @CheckForNull String readLink() throws IOException { + return null; + } + /** * Checks whether this file exists. + * The behavior is undefined for symlinks; if in doubt, check {@link #readLink} first. * @return true if it is a plain file or directory, false if nonexistent * @throws IOException in case checking status failed */ @@ -378,6 +390,12 @@ public abstract class VirtualFile implements Comparable, Serializab } return f.exists(); } + @Override public String readLink() throws IOException { + if (isIllegalSymlink()) { + return null; // best to just ignore link -> ../whatever + } + return Util.resolveSymlink(f); + } @Override public VirtualFile[] list() throws IOException { if (isIllegalSymlink()) { return new VirtualFile[0]; @@ -497,6 +515,13 @@ public abstract class VirtualFile implements Comparable, Serializab throw new IOException(x); } } + @Override public String readLink() throws IOException { + try { + return f.readLink(); + } catch (InterruptedException x) { + throw new IOException(x); + } + } @Override public VirtualFile[] list() throws IOException { try { List kids = f.list(); diff --git a/core/src/test/java/jenkins/util/VirtualFileTest.java b/core/src/test/java/jenkins/util/VirtualFileTest.java index 8be31af5a7..d704cf8a8c 100644 --- a/core/src/test/java/jenkins/util/VirtualFileTest.java +++ b/core/src/test/java/jenkins/util/VirtualFileTest.java @@ -175,4 +175,21 @@ public class VirtualFileTest { } } + @Issue("JENKINS-26810") + @Test public void readLink() throws Exception { + assumeFalse("Symlinks do not work well on Windows", Functions.isWindows()); + File root = tmp.getRoot(); + FilePath rootF = new FilePath(root); + rootF.child("plain").write("", null); + rootF.child("link").symlinkTo("physical", TaskListener.NULL); + for (VirtualFile vf : new VirtualFile[] {VirtualFile.forFile(root), VirtualFile.forFilePath(rootF)}) { + assertNull(vf.readLink()); + assertNull(vf.child("plain").readLink()); + VirtualFile link = vf.child("link"); + assertEquals("physical", link.readLink()); + assertFalse(link.isFile()); + assertFalse(link.isDirectory()); + } + } + }