diff options
author | 2016-09-08 15:08:00 +0000 | |
---|---|---|
committer | 2016-09-09 09:02:43 +0000 | |
commit | 94d905836c167a21d2321d26c646fde07f5fc522 (patch) | |
tree | 9b1608eebf40a74fc475b1f153b37d15714ab855 /src/main/java/com/google/devtools/build/lib | |
parent | 4a45d92130a6b1306a3840d006df165b8040a6cf (diff) |
Windows: add a Java-native isJunction method
Also add tests for WindowsFileSystem and some for
WindowsFileOperations, so we test both the
JNI-based and Java-native isJunction function, as
well as handling of dangling symlinks/junctions.
Having a Java-native version of this method means
we don't need to use windows_jni.dll for any tests
or for bootstrapping.
This change could help with
https://github.com/bazelbuild/bazel/issues/1735
--
MOS_MIGRATED_REVID=132556440
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java | 144 |
1 files changed, 89 insertions, 55 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java index 325176cb66..da04735831 100644 --- a/src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java +++ b/src/main/java/com/google/devtools/build/lib/vfs/WindowsFileSystem.java @@ -13,6 +13,7 @@ // limitations under the License. package com.google.devtools.build.lib.vfs; +import com.google.common.annotations.VisibleForTesting; import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; import java.io.File; import java.io.FileNotFoundException; @@ -20,19 +21,17 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.DosFileAttributes; -/** - * Jury-rigged file system for Windows. - */ +/** Jury-rigged file system for Windows. */ @ThreadSafe public class WindowsFileSystem extends JavaIoFileSystem { public static final LinkOption[] NO_OPTIONS = new LinkOption[0]; - public static final LinkOption[] NO_FOLLOW = new LinkOption[]{LinkOption.NOFOLLOW_LINKS}; + public static final LinkOption[] NO_FOLLOW = new LinkOption[] {LinkOption.NOFOLLOW_LINKS}; @Override - protected void createSymbolicLink(Path linkPath, PathFragment targetFragment) - throws IOException { + protected void createSymbolicLink(Path linkPath, PathFragment targetFragment) throws IOException { // TODO(lberki): Add some JNI to create hard links/junctions instead of calling out to // cmd.exe File file = getIoFile(linkPath); @@ -96,7 +95,7 @@ public class WindowsFileSystem extends JavaIoFileSystem { return super.fileIsSymbolicLink(file); } - private LinkOption[] linkOpts(boolean followSymlinks) { + public static LinkOption[] symlinkOpts(boolean followSymlinks) { return followSymlinks ? NO_OPTIONS : NO_FOLLOW; } @@ -105,56 +104,58 @@ public class WindowsFileSystem extends JavaIoFileSystem { File file = getIoFile(path); final BasicFileAttributes attributes; try { - attributes = Files.readAttributes( - file.toPath(), BasicFileAttributes.class, linkOpts(followSymlinks)); + attributes = + Files.readAttributes( + file.toPath(), BasicFileAttributes.class, symlinkOpts(followSymlinks)); } catch (java.nio.file.FileSystemException e) { throw new FileNotFoundException(path + ERR_NO_SUCH_FILE_OR_DIR); } final boolean isSymbolicLink = !followSymlinks && fileIsSymbolicLink(file); - FileStatus status = new FileStatus() { - @Override - public boolean isFile() { - return attributes.isRegularFile() || (isSpecialFile() && !isDirectory()); - } - - @Override - public boolean isSpecialFile() { - return attributes.isOther(); - } - - @Override - public boolean isDirectory() { - return attributes.isDirectory(); - } - - @Override - public boolean isSymbolicLink() { - return isSymbolicLink; - } - - @Override - public long getSize() throws IOException { - return attributes.size(); - } - - @Override - public long getLastModifiedTime() throws IOException { - return attributes.lastModifiedTime().toMillis(); - } - - @Override - public long getLastChangeTime() { - // This is the best we can do with Java NIO... - return attributes.lastModifiedTime().toMillis(); - } - - @Override - public long getNodeId() { - // TODO(bazel-team): Consider making use of attributes.fileKey(). - return -1; - } - }; + FileStatus status = + new FileStatus() { + @Override + public boolean isFile() { + return attributes.isRegularFile() || (isSpecialFile() && !isDirectory()); + } + + @Override + public boolean isSpecialFile() { + return attributes.isOther(); + } + + @Override + public boolean isDirectory() { + return attributes.isDirectory(); + } + + @Override + public boolean isSymbolicLink() { + return isSymbolicLink; + } + + @Override + public long getSize() throws IOException { + return attributes.size(); + } + + @Override + public long getLastModifiedTime() throws IOException { + return attributes.lastModifiedTime().toMillis(); + } + + @Override + public long getLastChangeTime() { + // This is the best we can do with Java NIO... + return attributes.lastModifiedTime().toMillis(); + } + + @Override + public long getNodeId() { + // TODO(bazel-team): Consider making use of attributes.fileKey(). + return -1; + } + }; return status; } @@ -173,10 +174,43 @@ public class WindowsFileSystem extends JavaIoFileSystem { return super.isDirectory(path, followSymlinks); } + /** + * Returns true if the path refers to a directory junction, directory symlink, or regular symlink. + * + * <p>Directory junctions are symbolic links created with "mklink /J" where the target is a + * directory or another directory junction. Directory junctions can be created without any user + * privileges. + * + * <p>Directory symlinks are symbolic links created with "mklink /D" where the target is a + * directory or another directory symlink. Note that directory symlinks can only be created by + * Administrators. + * + * <p>Normal symlinks are symbolic links created with "mklink". Normal symlinks should not point + * at directories, because even though "mklink" can create the link, it will not be a functional + * one (the linked directory's contents cannot be listed). Only Administrators may create regular + * symlinks. + * + * <p>This method returns true for all three types as long as their target is a directory (even if + * they are dangling), though only directory junctions and directory symlinks are useful. + */ // TODO(laszlocsomor): fix https://github.com/bazelbuild/bazel/issues/1735 and use the JNI method // in WindowsFileOperations. - private static boolean isJunction(java.nio.file.Path p) throws IOException { - // Jury-rigged - return p.compareTo(p.toRealPath()) != 0; + @VisibleForTesting + static boolean isJunction(java.nio.file.Path p) throws IOException { + if (Files.exists(p, symlinkOpts(/* followSymlinks */ false))) { + DosFileAttributes attributes = + Files.readAttributes(p, DosFileAttributes.class, symlinkOpts(/* followSymlinks */ false)); + + if (attributes.isRegularFile()) { + return false; + } + + if (attributes.isDirectory()) { + return attributes.isOther(); + } else { + return attributes.isSymbolicLink(); + } + } + return false; } } |