aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2016-09-08 15:08:00 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2016-09-09 09:02:43 +0000
commit94d905836c167a21d2321d26c646fde07f5fc522 (patch)
tree9b1608eebf40a74fc475b1f153b37d15714ab855 /src/main/java/com/google/devtools/build/lib
parent4a45d92130a6b1306a3840d006df165b8040a6cf (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.java144
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;
}
}