aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/vfs/UnixFileSystem.java218
2 files changed, 5 insertions, 223 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
index eb3e6a67a1..dc4920d1dc 100644
--- a/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/runtime/BlazeRuntime.java
@@ -16,9 +16,7 @@ package com.google.devtools.build.lib.runtime;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
-import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.eventbus.SubscriberExceptionContext;
import com.google.common.eventbus.SubscriberExceptionHandler;
@@ -905,14 +903,6 @@ public final class BlazeRuntime {
workspaceDirectoryPath = fs.getPath(workspaceDirectory);
}
- if (fs instanceof UnixFileSystem) {
- ((UnixFileSystem) fs).setRootsWithAllowedHardlinks(
- // Some tests pass nulls for these paths, so remove these from the list
- Iterables.filter(
- Arrays.asList(installBasePath, outputBasePath, workspaceDirectoryPath),
- Predicates.notNull()));
- }
-
ServerDirectories serverDirectories =
new ServerDirectories(installBasePath, outputBasePath, startupOptions.installMD5);
Clock clock = BlazeClock.instance();
diff --git a/src/main/java/com/google/devtools/build/lib/vfs/UnixFileSystem.java b/src/main/java/com/google/devtools/build/lib/vfs/UnixFileSystem.java
index 790818ecc9..ce7ee93bab 100644
--- a/src/main/java/com/google/devtools/build/lib/vfs/UnixFileSystem.java
+++ b/src/main/java/com/google/devtools/build/lib/vfs/UnixFileSystem.java
@@ -14,8 +14,6 @@
package com.google.devtools.build.lib.vfs;
import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Throwables;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.profiler.Profiler;
@@ -25,101 +23,17 @@ import com.google.devtools.build.lib.unix.NativePosixFiles;
import com.google.devtools.build.lib.unix.NativePosixFiles.Dirents;
import com.google.devtools.build.lib.unix.NativePosixFiles.ReadTypes;
import com.google.devtools.build.lib.util.Preconditions;
-
import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.Random;
/**
- * This class implements the FileSystem interface using direct calls to the
- * UNIX filesystem.
+ * This class implements the FileSystem interface using direct calls to the UNIX filesystem.
*/
-// Not final only for testing.
@ThreadSafe
public class UnixFileSystem extends AbstractFileSystemWithCustomStat {
- /**
- * What to do with requests to create symbolic links.
- *
- * Currently supports one value: SYMLINK, which simply calls symlink() . It obviously does not
- * work on Windows.
- */
- public enum SymlinkStrategy {
- /**
- * Use symlink(). Does not work on Windows, obviously.
- */
- SYMLINK,
-
- /**
- * Write a log message for symlinks that won't be compatible with how we are planning to pretend
- * that they exist on Windows.
- *
- * <p>The current plan for emulating symlinks on Windows is that in order to create a "symlink",
- * the target needs to exist, that is, we don't do dangling symlinks. Then:
- * </p>
- *
- * <ul>
- * <li>If the target is a directory, we create a junction. This is good because we don't need
- * write access to the target and it Just Works. The link and its target can be on different
- * file systems, which is important, because contrary to the popular belief, *can* do a
- * mount() on Windows
- * </li>
- * <li>If the target is a file in the source tree or under the output base, we use a hard
- * link. Hard links only work within the same file system and you need write access to the
- * target. We assume that the source tree is writable, and we know that the output base is.
- * </li>
- * <li>If the target is a file not in one of these locations, we raise an error. The only
- * places where we need to do this is in the implementation of local repository rules,
- * which will be special-cased.</li>
- * </ul>
- *
- * <p>What does <b>not</b> work is using symbolic links: they need local administrator rights,
- * which would make Bazel only usable as local admin.
- * </p>
- */
- WINDOWS_COMPATIBLE,
- }
-
- private final SymlinkStrategy symlinkStrategy;
- private final String symlinkLogFile;
-
- /**
- * Directories where Bazel tries to hardlink files from instead of copying them.
- *
- * <p>These must be writable to the user.
- */
- private ImmutableList<Path> rootsWithAllowedHardlinks;
-
public UnixFileSystem() {
- SymlinkStrategy symlinkStrategy = SymlinkStrategy.SYMLINK;
- String strategyString = System.getProperty("io.bazel.SymlinkStrategy");
- symlinkLogFile = System.getProperty("io.bazel.SymlinkLogFile");
- if (strategyString != null) {
- try {
- symlinkStrategy = SymlinkStrategy.valueOf(strategyString.toUpperCase());
- } catch (IllegalArgumentException e) {
- // We just go with the default, this is just an experimental option so it's fine.
- }
-
- if (symlinkLogFile != null) {
- writeLogMessage("Logging started");
- }
- }
-
- this.symlinkStrategy = symlinkStrategy;
- rootsWithAllowedHardlinks = ImmutableList.of();
- }
-
- // This method is a little ugly, but it's only for testing for now.
- public void setRootsWithAllowedHardlinks(Iterable<Path> roots) {
- this.rootsWithAllowedHardlinks = ImmutableList.copyOf(roots);
}
/**
@@ -204,7 +118,7 @@ public class UnixFileSystem extends AbstractFileSystemWithCustomStat {
}
/**
- * Converts from {@link NativePosixFiles.Dirents.Type} to
+ * Converts from {@link com.google.devtools.build.lib.unix.NativePosixFiles.Dirents.Type} to
* {@link com.google.devtools.build.lib.vfs.Dirent.Type}.
*/
private static Dirent.Type convertToDirentType(Dirents.Type type) {
@@ -371,7 +285,7 @@ public class UnixFileSystem extends AbstractFileSystemWithCustomStat {
@Override
public boolean supportsSymbolicLinksNatively() {
- return symlinkStrategy != SymlinkStrategy.WINDOWS_COMPATIBLE;
+ return true;
}
@Override
@@ -400,133 +314,11 @@ public class UnixFileSystem extends AbstractFileSystemWithCustomStat {
@Override
protected void createSymbolicLink(Path linkPath, PathFragment targetFragment)
throws IOException {
- SymlinkImplementation strategy = computeSymlinkImplementation(linkPath, targetFragment);
- switch (strategy) {
- case HARDLINK:
- NativePosixFiles.link(targetFragment.toString(), linkPath.toString());
- break;
-
- case JUNCTION: // Junctions are emulated on Linux with symlinks, fall through
- case SYMLINK:
- synchronized (linkPath) {
- NativePosixFiles.symlink(targetFragment.toString(), linkPath.toString());
- }
- break;
-
- case FAIL:
- if (symlinkLogFile == null) {
- // Otherwise, it was logged in computeSymlinkImplementation().
- throw new IOException(String.format("Symlink emulation failed for symlink: %s -> %s",
- linkPath, targetFragment));
- }
- }
- }
-
- private boolean isHardLinkAllowed(Path path) {
- for (Path root : rootsWithAllowedHardlinks) {
- if (path.startsWith(root)) {
- return true;
- }
- }
-
- return false;
- }
-
- private static final int JVM_ID = new Random().nextInt(10000);
-
- private void writeLogMessage(String message) {
- String logLine = String.format("[%04d] %s\n", JVM_ID, message);
- // FileLock does not work for synchronization between threads in the same JVM as per its Javadoc
- synchronized (symlinkLogFile) {
-
- try (FileChannel channel = new RandomAccessFile(symlinkLogFile, "rwd").getChannel()) {
- try (FileLock lock = channel.lock()) {
- channel.position(channel.size());
- ByteBuffer data = Charset.forName("UTF-8").newEncoder().encode(CharBuffer.wrap(logLine));
- channel.write(data);
- }
- } catch (IOException e) {
- // Not much intelligent we can do here
- }
+ synchronized (linkPath) {
+ NativePosixFiles.symlink(targetFragment.toString(), linkPath.toString());
}
}
- /**
- * How to create a particular symbolic link.
- *
- * <p>Necessary because Windows doesn't support symlinks properly, so we have to work around it.
- * No, even though they say <i>"Microsoft has implemented its symbolic links to function just like
- * UNIX links"</i>, it's a lie.
- */
- private enum SymlinkImplementation {
- /**
- * We can't emulate this link. Fail.
- */
- FAIL,
-
- /**
- * Create a hard link. This only works if we have write access to the ultimate destination on
- * the link.
- */
- HARDLINK,
-
- /**
- * Create a junction. This only works if the ultimate target of the "symlink" is a directory.
- */
- JUNCTION,
-
- /**
- * Use a symlink. Always works, but only on Unix-based operating systems.
- */
- SYMLINK,
- }
-
- private SymlinkImplementation emitSymlinkCompatibilityMessage(
- String reason, Path linkPath, PathFragment targetFragment) {
- if (symlinkLogFile == null) {
- return SymlinkImplementation.FAIL;
- }
-
- Exception e = new Exception();
- e.fillInStackTrace();
- String msg = String.format("ILLEGAL (%s): %s -> %s\nStack:\n%s",
- reason, linkPath.getPathString(), targetFragment.getPathString(),
- Throwables.getStackTraceAsString(e));
- writeLogMessage(msg);
- return SymlinkImplementation.SYMLINK; // We are in logging mode, pretend everything is A-OK
- }
-
- private SymlinkImplementation computeSymlinkImplementation(
- Path linkPath, PathFragment targetFragment) throws IOException {
- if (symlinkStrategy != SymlinkStrategy.WINDOWS_COMPATIBLE) {
- return SymlinkImplementation.SYMLINK;
- }
-
- Path targetPath = linkPath.getRelative(targetFragment);
- if (!targetPath.exists(Symlinks.FOLLOW)) {
- return emitSymlinkCompatibilityMessage(
- "Target does not exist", linkPath, targetFragment);
- }
-
- targetPath = targetPath.resolveSymbolicLinks();
- if (targetPath.isDirectory(Symlinks.FOLLOW)) {
- // We can create junctions to any directory.
- return SymlinkImplementation.JUNCTION;
- }
-
- if (isHardLinkAllowed(targetPath)) {
- // We have write access to the destination and it's a file, so we can do this
- return SymlinkImplementation.HARDLINK;
- }
-
- return emitSymlinkCompatibilityMessage(
- "Target is a non-writable file", linkPath, targetFragment);
- }
-
- public SymlinkStrategy getSymlinkStrategy() {
- return symlinkStrategy;
- }
-
@Override
protected PathFragment readSymbolicLink(Path path) throws IOException {
// Note that the default implementation of readSymbolicLinkUnchecked calls this method and thus