aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/sandbox
diff options
context:
space:
mode:
authorGravatar dannark <dannark@google.com>2018-04-04 14:02:13 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-04-04 14:03:33 -0700
commit2a5512fa3041df96b140e96a30112d5137be8b63 (patch)
tree3e73629ba36153f846b6ab125308c1779c013d94 /src/main/java/com/google/devtools/build/lib/sandbox
parent7520dcce42217c8076b06ed88c0e4e04ed99a0f4 (diff)
Internal change
PiperOrigin-RevId: 191642942
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/sandbox')
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java23
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java27
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedStrategy.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java27
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java26
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java33
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/SandboxedSpawn.java37
-rw-r--r--src/main/java/com/google/devtools/build/lib/sandbox/SymlinkedSandboxedSpawn.java97
10 files changed, 157 insertions, 119 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java
index 9fee6544dd..33b21209da 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/AbstractSandboxSpawnRunner.java
@@ -50,11 +50,13 @@ abstract class AbstractSandboxSpawnRunner implements SpawnRunner {
private static final String SANDBOX_DEBUG_SUGGESTION =
"\n\nUse --sandbox_debug to see verbose messages from the sandbox";
+ private final Path sandboxBase;
private final SandboxOptions sandboxOptions;
private final boolean verboseFailures;
private final ImmutableSet<Path> inaccessiblePaths;
- public AbstractSandboxSpawnRunner(CommandEnvironment cmdEnv) {
+ public AbstractSandboxSpawnRunner(CommandEnvironment cmdEnv, Path sandboxBase) {
+ this.sandboxBase = sandboxBase;
this.sandboxOptions = cmdEnv.getOptions().getOptions(SandboxOptions.class);
this.verboseFailures = cmdEnv.getOptions().getOptions(ExecutionOptions.class).verboseFailures;
this.inaccessiblePaths =
@@ -86,6 +88,7 @@ abstract class AbstractSandboxSpawnRunner implements SpawnRunner {
SandboxedSpawn sandbox,
SpawnExecutionPolicy policy,
Path execRoot,
+ Path tmpDir,
Duration timeout,
Path statisticsPath)
throws IOException, InterruptedException {
@@ -94,7 +97,8 @@ abstract class AbstractSandboxSpawnRunner implements SpawnRunner {
OutErr outErr = policy.getFileOutErr();
policy.prefetchInputs();
- SpawnResult result = run(originalSpawn, sandbox, outErr, timeout, execRoot, statisticsPath);
+ SpawnResult result =
+ run(originalSpawn, sandbox, outErr, timeout, execRoot, tmpDir, statisticsPath);
policy.lockOutputFiles();
try {
@@ -117,6 +121,7 @@ abstract class AbstractSandboxSpawnRunner implements SpawnRunner {
OutErr outErr,
Duration timeout,
Path execRoot,
+ Path tmpDir,
Path statisticsPath)
throws IOException, InterruptedException {
Command cmd = new Command(
@@ -140,6 +145,9 @@ abstract class AbstractSandboxSpawnRunner implements SpawnRunner {
long startTime = System.currentTimeMillis();
CommandResult commandResult;
try {
+ if (!tmpDir.exists() && !tmpDir.createDirectory()) {
+ throw new IOException(String.format("Could not create temp directory '%s'", tmpDir));
+ }
commandResult = cmd.execute(outErr.getOutputStream(), outErr.getErrorStream());
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException();
@@ -206,6 +214,17 @@ abstract class AbstractSandboxSpawnRunner implements SpawnRunner {
}
/**
+ * Returns a temporary directory that should be used as the sandbox directory for a single action.
+ */
+ protected Path getSandboxRoot() throws IOException {
+ return sandboxBase.getRelative(
+ java.nio.file.Files.createTempDirectory(
+ java.nio.file.Paths.get(sandboxBase.getPathString()), "")
+ .getFileName()
+ .toString());
+ }
+
+ /**
* Gets the list of directories that the spawn will assume to be writable.
*
* @throws IOException because we might resolve symlinks, which throws {@link IOException}.
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
index d20eec70b1..1060034ccc 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedSpawnRunner.java
@@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
+import com.google.devtools.build.lib.actions.ExecException;
import com.google.devtools.build.lib.actions.ExecutionStrategy;
import com.google.devtools.build.lib.actions.Spawn;
import com.google.devtools.build.lib.actions.SpawnActionContext;
@@ -95,7 +96,6 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
private final Path execRoot;
private final boolean allowNetwork;
private final Path processWrapper;
- private final Path sandboxBase;
private final Duration timeoutKillDelay;
private final @Nullable SandboxfsProcess sandboxfsProcess;
@@ -123,14 +123,13 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
Duration timeoutKillDelay,
@Nullable SandboxfsProcess sandboxfsProcess)
throws IOException {
- super(cmdEnv);
+ super(cmdEnv, sandboxBase);
this.execRoot = cmdEnv.getExecRoot();
this.allowNetwork = SandboxHelpers.shouldAllowNetwork(cmdEnv.getOptions());
this.alwaysWritableDirs = getAlwaysWritableDirs(cmdEnv.getRuntime().getFileSystem());
this.processWrapper = ProcessWrapperUtil.getProcessWrapper(cmdEnv);
this.localEnvProvider =
new XcodeLocalEnvProvider(cmdEnv.getRuntime().getProductName(), cmdEnv.getClientEnv());
- this.sandboxBase = sandboxBase;
this.timeoutKillDelay = timeoutKillDelay;
this.sandboxfsProcess = sandboxfsProcess;
}
@@ -194,19 +193,21 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
@Override
protected SpawnResult actuallyExec(Spawn spawn, SpawnExecutionPolicy policy)
- throws IOException, InterruptedException {
+ throws ExecException, IOException, InterruptedException {
// Each invocation of "exec" gets its own sandbox.
- Path sandboxPath = sandboxBase.getRelative(Integer.toString(policy.getId()));
- sandboxPath.createDirectory();
-
- // b/64689608: The execroot of the sandboxed process must end with the workspace name, just like
- // the normal execroot does.
+ Path sandboxPath = getSandboxRoot();
Path sandboxExecRoot = sandboxPath.getRelative("execroot").getRelative(execRoot.getBaseName());
- sandboxExecRoot.getParentDirectory().createDirectory();
- sandboxExecRoot.createDirectory();
+
+ // Each sandboxed action runs in its own directory so we don't need to make the temp directory's
+ // name unique (like we have to with standalone execution strategy).
+ //
+ // Note that, for sandboxfs-based executions, this temp directory lives outside of the sandboxfs
+ // instance. This is perfectly fine (because sandbox-exec controls accesses to this directory)
+ // and is actually desirable for performance reasons.
+ Path tmpDir = sandboxPath.getRelative("tmp");
Map<String, String> environment =
- localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, "/tmp");
+ localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, tmpDir.getPathString());
final HashSet<Path> writableDirs = new HashSet<>(alwaysWritableDirs);
ImmutableSet<Path> extraWritableDirs = getWritableDirs(sandboxExecRoot, environment);
@@ -287,7 +288,7 @@ final class DarwinSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
}
};
}
- return runSpawn(spawn, sandbox, policy, execRoot, timeout, statisticsPath);
+ return runSpawn(spawn, sandbox, policy, execRoot, tmpDir, timeout, statisticsPath);
}
private void writeConfig(
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedStrategy.java
index a4c05ea5a7..fc8a3c3fad 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedStrategy.java
@@ -33,6 +33,6 @@ final class DarwinSandboxedStrategy extends AbstractSpawnStrategy {
@Override
public String toString() {
- return "darwin-sandbox";
+ return "sandboxed";
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java
index 0d6c7e1410..e4c5ba6524 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java
@@ -76,7 +76,6 @@ final class LinuxSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
private final Path execRoot;
private final boolean allowNetwork;
private final Path linuxSandbox;
- private final Path sandboxBase;
private final Path inaccessibleHelperFile;
private final Path inaccessibleHelperDir;
private final LocalEnvProvider localEnvProvider;
@@ -97,13 +96,12 @@ final class LinuxSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
Path inaccessibleHelperFile,
Path inaccessibleHelperDir,
Duration timeoutKillDelay) {
- super(cmdEnv);
+ super(cmdEnv, sandboxBase);
this.fileSystem = cmdEnv.getRuntime().getFileSystem();
this.blazeDirs = cmdEnv.getDirectories();
this.execRoot = cmdEnv.getExecRoot();
this.allowNetwork = SandboxHelpers.shouldAllowNetwork(cmdEnv.getOptions());
this.linuxSandbox = LinuxSandboxUtil.getLinuxSandbox(cmdEnv);
- this.sandboxBase = sandboxBase;
this.inaccessibleHelperFile = inaccessibleHelperFile;
this.inaccessibleHelperDir = inaccessibleHelperDir;
this.timeoutKillDelay = timeoutKillDelay;
@@ -113,18 +111,16 @@ final class LinuxSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
@Override
protected SpawnResult actuallyExec(Spawn spawn, SpawnExecutionPolicy policy)
throws IOException, ExecException, InterruptedException {
- // Each invocation of "exec" gets its own sandbox base, execroot and temporary directory.
- Path sandboxPath = sandboxBase.getRelative(Integer.toString(policy.getId()));
- sandboxPath.createDirectory();
-
- // b/64689608: The execroot of the sandboxed process must end with the workspace name, just like
- // the normal execroot does.
+ // Each invocation of "exec" gets its own sandbox.
+ Path sandboxPath = getSandboxRoot();
Path sandboxExecRoot = sandboxPath.getRelative("execroot").getRelative(execRoot.getBaseName());
- sandboxExecRoot.getParentDirectory().createDirectory();
- sandboxExecRoot.createDirectory();
+
+ // Each sandboxed action runs in its own execroot, so we don't need to make the temp directory's
+ // name unique (like we have to with standalone execution strategy).
+ Path tmpDir = sandboxExecRoot.getRelative("tmp");
Map<String, String> environment =
- localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, "/tmp");
+ localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, tmpDir.getPathString());
ImmutableSet<Path> writableDirs = getWritableDirs(sandboxExecRoot, environment);
ImmutableSet<PathFragment> outputs = SandboxHelpers.getOutputFiles(spawn);
@@ -137,13 +133,12 @@ final class LinuxSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
.setBindMounts(getReadOnlyBindMounts(blazeDirs, sandboxExecRoot))
.setUseFakeHostname(getSandboxOptions().sandboxFakeHostname)
.setCreateNetworkNamespace(!(allowNetwork || Spawns.requiresNetwork(spawn)))
- .setUseDebugMode(getSandboxOptions().sandboxDebug)
- .setKillDelay(timeoutKillDelay);
+ .setUseDebugMode(getSandboxOptions().sandboxDebug);
if (!timeout.isZero()) {
commandLineBuilder.setTimeout(timeout);
}
-
+ commandLineBuilder.setKillDelay(timeoutKillDelay);
if (spawn.getExecutionInfo().containsKey(ExecutionRequirements.REQUIRES_FAKEROOT)) {
commandLineBuilder.setUseFakeRoot(true);
} else if (getSandboxOptions().sandboxFakeUsername) {
@@ -166,7 +161,7 @@ final class LinuxSandboxedSpawnRunner extends AbstractSandboxSpawnRunner {
outputs,
writableDirs);
- return runSpawn(spawn, sandbox, policy, execRoot, timeout, statisticsPath);
+ return runSpawn(spawn, sandbox, policy, execRoot, tmpDir, timeout, statisticsPath);
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java
index 1993fb8c20..bbebefa81d 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java
@@ -37,7 +37,7 @@ public final class LinuxSandboxedStrategy extends AbstractSpawnStrategy {
@Override
public String toString() {
- return "linux-sandbox";
+ return "sandboxed";
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
index e79b2abcd7..fdc4abfdd7 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedSpawnRunner.java
@@ -35,9 +35,8 @@ final class ProcessWrapperSandboxedSpawnRunner extends AbstractSandboxSpawnRunne
return OS.isPosixCompatible() && ProcessWrapperUtil.isSupported(cmdEnv);
}
- private final Path processWrapper;
private final Path execRoot;
- private final Path sandboxBase;
+ private final Path processWrapper;
private final LocalEnvProvider localEnvProvider;
private final Duration timeoutKillDelay;
@@ -51,32 +50,29 @@ final class ProcessWrapperSandboxedSpawnRunner extends AbstractSandboxSpawnRunne
*/
ProcessWrapperSandboxedSpawnRunner(
CommandEnvironment cmdEnv, Path sandboxBase, String productName, Duration timeoutKillDelay) {
- super(cmdEnv);
- this.processWrapper = ProcessWrapperUtil.getProcessWrapper(cmdEnv);
+ super(cmdEnv, sandboxBase);
this.execRoot = cmdEnv.getExecRoot();
+ this.timeoutKillDelay = timeoutKillDelay;
+ this.processWrapper = ProcessWrapperUtil.getProcessWrapper(cmdEnv);
this.localEnvProvider =
OS.getCurrent() == OS.DARWIN
? new XcodeLocalEnvProvider(productName, cmdEnv.getClientEnv())
: new PosixLocalEnvProvider(cmdEnv.getClientEnv());
- this.sandboxBase = sandboxBase;
- this.timeoutKillDelay = timeoutKillDelay;
}
@Override
protected SpawnResult actuallyExec(Spawn spawn, SpawnExecutionPolicy policy)
throws ExecException, IOException, InterruptedException {
// Each invocation of "exec" gets its own sandbox.
- Path sandboxPath = sandboxBase.getRelative(Integer.toString(policy.getId()));
- sandboxPath.createDirectory();
-
- // b/64689608: The execroot of the sandboxed process must end with the workspace name, just like
- // the normal execroot does.
+ Path sandboxPath = getSandboxRoot();
Path sandboxExecRoot = sandboxPath.getRelative("execroot").getRelative(execRoot.getBaseName());
- sandboxExecRoot.getParentDirectory().createDirectory();
- sandboxExecRoot.createDirectory();
+
+ // Each sandboxed action runs in its own execroot, so we don't need to make the temp directory's
+ // name unique (like we have to with standalone execution strategy).
+ Path tmpDir = sandboxExecRoot.getRelative("tmp");
Map<String, String> environment =
- localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, "/tmp");
+ localEnvProvider.rewriteLocalEnv(spawn.getEnvironment(), execRoot, tmpDir.getPathString());
Duration timeout = policy.getTimeout();
ProcessWrapperUtil.CommandLineBuilder commandLineBuilder =
@@ -101,7 +97,7 @@ final class ProcessWrapperSandboxedSpawnRunner extends AbstractSandboxSpawnRunne
SandboxHelpers.getOutputFiles(spawn),
getWritableDirs(sandboxExecRoot, environment));
- return runSpawn(spawn, sandbox, policy, execRoot, timeout, statisticsPath);
+ return runSpawn(spawn, sandbox, policy, execRoot, tmpDir, timeout, statisticsPath);
}
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java
index 096f564ad8..83c279a726 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java
@@ -33,6 +33,6 @@ final class ProcessWrapperSandboxedStrategy extends AbstractSpawnStrategy {
@Override
public String toString() {
- return "processwrapper-sandbox";
+ return "sandboxed";
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java
index a8fb190e48..3065393a96 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxModule.java
@@ -19,7 +19,6 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.collect.ImmutableList;
import com.google.common.eventbus.Subscribe;
-import com.google.devtools.build.lib.actions.ExecutorInitException;
import com.google.devtools.build.lib.buildtool.BuildRequest;
import com.google.devtools.build.lib.buildtool.buildevent.BuildCompleteEvent;
import com.google.devtools.build.lib.buildtool.buildevent.BuildInterruptedEvent;
@@ -29,6 +28,8 @@ import com.google.devtools.build.lib.exec.ExecutorBuilder;
import com.google.devtools.build.lib.runtime.BlazeModule;
import com.google.devtools.build.lib.runtime.Command;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
+import com.google.devtools.build.lib.util.AbruptExitException;
+import com.google.devtools.build.lib.util.ExitCode;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -66,16 +67,14 @@ public final class SandboxModule extends BlazeModule {
}
/** Computes the path to the sandbox base tree for the given running command. */
- private static Path computeSandboxBase(SandboxOptions options, CommandEnvironment env)
- throws IOException {
+ private static Path computeSandboxBase(SandboxOptions options, CommandEnvironment env) {
if (options.sandboxBase.isEmpty()) {
return env.getOutputBase().getRelative("sandbox");
} else {
String dirName = String.format("%s-sandbox.%s", env.getRuntime().getProductName(),
Fingerprint.md5Digest(env.getOutputBase().toString()));
FileSystem fileSystem = env.getRuntime().getFileSystem();
- Path resolvedSandboxBase = fileSystem.getPath(options.sandboxBase).resolveSymbolicLinks();
- return resolvedSandboxBase.getRelative(dirName);
+ return fileSystem.getPath(options.sandboxBase).getRelative(dirName);
}
}
@@ -92,30 +91,18 @@ public final class SandboxModule extends BlazeModule {
}
@Override
- public void executorInit(CommandEnvironment cmdEnv, BuildRequest request, ExecutorBuilder builder)
- throws ExecutorInitException {
+ public void executorInit(
+ CommandEnvironment cmdEnv, BuildRequest request, ExecutorBuilder builder) {
checkNotNull(env, "env not initialized; was beforeCommand called?");
SandboxOptions options = env.getOptions().getOptions(SandboxOptions.class);
checkNotNull(options, "We were told to initialize the executor but the SandboxOptions are "
+ "not present; were they registered for all build commands?");
- try {
- sandboxBase = computeSandboxBase(options, env);
- } catch (IOException e) {
- throw new ExecutorInitException(
- "--experimental_sandbox_base points to an invalid directory", e);
- }
+ sandboxBase = computeSandboxBase(options, env);
ActionContextProvider provider;
try {
- // Ensure that each build starts with a clean sandbox base directory. Otherwise using the `id`
- // that is provided by SpawnExecutionPolicy#getId to compute a base directory for a sandbox
- // might result in an already existing directory.
- if (sandboxBase.exists()) {
- FileSystemUtils.deleteTree(sandboxBase);
- }
-
sandboxBase.createDirectoryAndParents();
if (options.useSandboxfs) {
Path mountPoint = sandboxBase.getRelative("sandboxfs");
@@ -130,7 +117,11 @@ public final class SandboxModule extends BlazeModule {
provider = SandboxActionContextProvider.create(cmdEnv, sandboxBase, null);
}
} catch (IOException e) {
- throw new ExecutorInitException("Failed to initialize sandbox", e);
+ env.getBlazeModuleEnvironment().exit(
+ new AbruptExitException(
+ "Failed to initialize sandbox: " + e,
+ ExitCode.LOCAL_ENVIRONMENTAL_ERROR));
+ return;
}
builder.addActionContextProvider(provider);
builder.addActionContextConsumer(new SandboxActionContextConsumer(cmdEnv));
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxedSpawn.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxedSpawn.java
index aba4454334..e6408dc3cc 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxedSpawn.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxedSpawn.java
@@ -14,11 +14,10 @@
package com.google.devtools.build.lib.sandbox;
-import com.google.devtools.build.lib.vfs.FileStatus;
+import com.google.common.io.Files;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
-import com.google.devtools.build.lib.vfs.Symlinks;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
@@ -77,33 +76,19 @@ interface SandboxedSpawn {
for (PathFragment output : outputs) {
Path source = sourceRoot.getRelative(output);
Path target = targetRoot.getRelative(output);
-
- FileStatus stat = source.statNullable(Symlinks.NOFOLLOW);
- if (stat != null) {
+ if (source.isFile() || source.isSymbolicLink()) {
// Ensure the target directory exists in the target. The directories for the action outputs
// have already been created, but the spawn outputs may be different from the overall action
// outputs. This is the case for test actions.
- Path parentDir = target.getParentDirectory();
- if (parentDir != null) {
- parentDir.createDirectoryAndParents();
- }
-
- if (stat.isSymbolicLink()) {
- try {
- source.renameTo(target);
- } catch (IOException e) {
- target.createSymbolicLink(source.readSymbolicLink());
- }
- } else if (stat.isFile()) {
- FileSystemUtils.moveFile(source, target);
- } else if (stat.isDirectory()) {
- try {
- source.renameTo(target);
- } catch (IOException e) {
- // Failed to move directory directly, thus move it recursively.
- target.createDirectory();
- FileSystemUtils.moveTreesBelow(source, target);
- }
+ target.getParentDirectory().createDirectoryAndParents();
+ Files.move(source.getPathFile(), target.getPathFile());
+ } else if (source.isDirectory()) {
+ try {
+ source.renameTo(target);
+ } catch (IOException e) {
+ // Failed to move directory directly, thus move it recursively.
+ target.createDirectory();
+ FileSystemUtils.moveTreesBelow(source, target);
}
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SymlinkedSandboxedSpawn.java b/src/main/java/com/google/devtools/build/lib/sandbox/SymlinkedSandboxedSpawn.java
index d2806db1a1..f4d41e38a3 100644
--- a/src/main/java/com/google/devtools/build/lib/sandbox/SymlinkedSandboxedSpawn.java
+++ b/src/main/java/com/google/devtools/build/lib/sandbox/SymlinkedSandboxedSpawn.java
@@ -15,13 +15,14 @@
package com.google.devtools.build.lib.sandbox;
import com.google.common.base.Preconditions;
-import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.vfs.FileStatus;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
+import com.google.devtools.build.lib.vfs.Symlinks;
import java.io.IOException;
import java.util.Collection;
-import java.util.LinkedHashSet;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -74,8 +75,36 @@ public class SymlinkedSandboxedSpawn implements SandboxedSpawn {
@Override
public void createFileSystem() throws IOException {
- createDirectories();
+ Set<Path> createdDirs = new HashSet<>();
+ cleanFileSystem(inputs.keySet());
+ createDirectoryAndParentsWithCache(createdDirs, sandboxExecRoot);
+ createParentDirectoriesForInputs(createdDirs, inputs.keySet());
createInputs(inputs);
+ createWritableDirectories(createdDirs, writableDirs);
+ createDirectoriesForOutputs(createdDirs, outputs);
+ }
+
+ private void cleanFileSystem(Set<PathFragment> allowedFiles) throws IOException {
+ if (sandboxExecRoot.exists(Symlinks.NOFOLLOW)) {
+ deleteExceptAllowedFiles(sandboxExecRoot, allowedFiles);
+ }
+ }
+
+ private void deleteExceptAllowedFiles(Path root, Set<PathFragment> allowedFiles)
+ throws IOException {
+ for (Path p : root.getDirectoryEntries()) {
+ FileStatus stat = p.stat(Symlinks.NOFOLLOW);
+ if (!stat.isDirectory()) {
+ if (!allowedFiles.contains(p.relativeTo(sandboxExecRoot))) {
+ p.delete();
+ }
+ } else {
+ deleteExceptAllowedFiles(p, allowedFiles);
+ if (p.readdir(Symlinks.NOFOLLOW).isEmpty()) {
+ p.delete();
+ }
+ }
+ }
}
/**
@@ -90,32 +119,29 @@ public class SymlinkedSandboxedSpawn implements SandboxedSpawn {
* directories, too, because we'll get an IOException with EEXIST if inputs happen to be nested
* once we start creating the symlinks for all inputs.
*/
- private void createDirectories() throws IOException {
- LinkedHashSet<Path> dirsToCreate = new LinkedHashSet<>();
-
- for (PathFragment path : Iterables.concat(inputs.keySet(), outputs)) {
- Preconditions.checkArgument(!path.isAbsolute());
- Preconditions.checkArgument(!path.containsUplevelReferences());
- for (int i = 0; i < path.segmentCount(); i++) {
- dirsToCreate.add(sandboxExecRoot.getRelative(path.subFragment(0, i)));
- }
- }
-
- for (Path path : dirsToCreate) {
- path.createDirectory();
- }
-
- for (Path dir : writableDirs) {
- if (dir.startsWith(sandboxExecRoot)) {
- dir.createDirectoryAndParents();
- }
+ private void createParentDirectoriesForInputs(Set<Path> createdDirs, Set<PathFragment> inputs)
+ throws IOException {
+ for (PathFragment inputPath : inputs) {
+ Path dir = sandboxExecRoot.getRelative(inputPath).getParentDirectory();
+ Preconditions.checkArgument(
+ dir.startsWith(sandboxExecRoot), "Bad relative path: '%s'", inputPath);
+ createDirectoryAndParentsWithCache(createdDirs, dir);
}
}
- protected void createInputs(Map<PathFragment, Path> inputs) throws IOException {
+ private void createInputs(Map<PathFragment, Path> inputs) throws IOException {
// All input files are relative to the execroot.
for (Entry<PathFragment, Path> entry : inputs.entrySet()) {
Path key = sandboxExecRoot.getRelative(entry.getKey());
+ FileStatus keyStat = key.statNullable(Symlinks.NOFOLLOW);
+ if (keyStat != null) {
+ if (keyStat.isSymbolicLink()
+ && entry.getValue() != null
+ && key.readSymbolicLink().equals(entry.getValue().asFragment())) {
+ continue;
+ }
+ key.delete();
+ }
// A null value means that we're supposed to create an empty file as the input.
if (entry.getValue() != null) {
key.createSymbolicLink(entry.getValue());
@@ -125,6 +151,24 @@ public class SymlinkedSandboxedSpawn implements SandboxedSpawn {
}
}
+ private void createWritableDirectories(Set<Path> createdDirs, Set<Path> writableDirs)
+ throws IOException {
+ for (Path writablePath : writableDirs) {
+ if (writablePath.startsWith(sandboxExecRoot)) {
+ createDirectoryAndParentsWithCache(createdDirs, writablePath);
+ }
+ }
+ }
+
+ /** Prepare the output directories in the sandbox. */
+ private void createDirectoriesForOutputs(Set<Path> createdDirs, Collection<PathFragment> outputs)
+ throws IOException {
+ for (PathFragment output : outputs) {
+ createDirectoryAndParentsWithCache(
+ createdDirs, sandboxExecRoot.getRelative(output.getParentDirectory()));
+ }
+ }
+
@Override
public void copyOutputs(Path execRoot) throws IOException {
SandboxedSpawn.moveOutputs(outputs, sandboxExecRoot, execRoot);
@@ -144,4 +188,11 @@ public class SymlinkedSandboxedSpawn implements SandboxedSpawn {
// on here.
}
}
+
+ private static void createDirectoryAndParentsWithCache(Set<Path> cache, Path dir)
+ throws IOException {
+ if (cache.add(dir)) {
+ dir.createDirectoryAndParents();
+ }
+ }
}