Skip to content

Commit

Permalink
VirtualFile.readLink
Browse files Browse the repository at this point in the history
  • Loading branch information
jglick committed Feb 21, 2018
1 parent 4911c5c commit e3e6d57
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
4 changes: 2 additions & 2 deletions core/src/main/java/hudson/Util.java
Expand Up @@ -1403,7 +1403,7 @@ public static File resolveSymlinkToFile(@Nonnull File link) throws InterruptedEx
* 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();
Expand All @@ -1415,7 +1415,7 @@ public static String resolveSymlink(@Nonnull File link) throws InterruptedExcept
} catch (IOException x) {
throw x;
} catch (Exception x) {
throw (IOException) new IOException(x.toString()).initCause(x);
throw new IOException(x);
}
}

Expand Down
25 changes: 25 additions & 0 deletions core/src/main/java/jenkins/util/VirtualFile.java
Expand Up @@ -139,8 +139,20 @@ public abstract class VirtualFile implements Comparable<VirtualFile>, Serializab
*/
public abstract boolean isFile() throws IOException;

/**
* If this file is a symlink, returns the link target.
* <p>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
*/
Expand Down Expand Up @@ -378,6 +390,12 @@ private static final class FileVF extends VirtualFile {
}
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];
Expand Down Expand Up @@ -497,6 +515,13 @@ private static final class FilePathVF extends VirtualFile {
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<FilePath> kids = f.list();
Expand Down
17 changes: 17 additions & 0 deletions core/src/test/java/jenkins/util/VirtualFileTest.java
Expand Up @@ -175,4 +175,21 @@ public InputStream open() throws IOException {
}
}

@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());
}
}

}

0 comments on commit e3e6d57

Please sign in to comment.