* Don't allow derivations with fixed and non-fixed outputs.

This commit is contained in:
Eelco Dolstra 2011-07-20 18:26:00 +00:00
parent b2027f70d9
commit c8606664ab

View file

@ -394,23 +394,11 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
throw EvalError(format("derivation names are not allowed to end in `%1%'") throw EvalError(format("derivation names are not allowed to end in `%1%'")
% drvExtension); % drvExtension);
/* Construct the "masked" store derivation, which is the final one if (outputHash != "") {
except that in the list of outputs, the output paths are empty, /* Handle fixed-output derivations. */
and the corresponding environment variables have an empty if (outputs.size() != 1 || *(outputs.begin()) != "out")
value. This ensures that changes in the set of output names do throw Error("multiple outputs are not supported in fixed-output derivations");
get reflected in the hash.
However, for fixed-output derivations, we can compute the
output path directly, so we don't need this. */
bool fixedOnly = true;
foreach (StringSet::iterator, i, outputs) {
if (*i != "out" || outputHash == "") {
drv.env[*i] = "";
drv.outputs[*i] = DerivationOutput("", "", "");
fixedOnly = false;
} else {
/* If an output hash was given, check it, and compute the
output path. */
HashType ht = parseHashType(outputHashAlgo); HashType ht = parseHashType(outputHashAlgo);
if (ht == htUnknown) if (ht == htUnknown)
throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo); throw EvalError(format("unknown hash algorithm `%1%'") % outputHashAlgo);
@ -427,20 +415,27 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
string s = outputHash; string s = outputHash;
outputHash = printHash(h); outputHash = printHash(h);
if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo; if (outputHashRecursive) outputHashAlgo = "r:" + outputHashAlgo;
Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName); Path outPath = makeFixedOutputPath(outputHashRecursive, ht, h, drvName);
drv.env[*i] = outPath; drv.env["out"] = outPath;
drv.outputs[*i] = DerivationOutput(outPath, outputHashAlgo, outputHash); drv.outputs["out"] = DerivationOutput(outPath, outputHashAlgo, outputHash);
} }
else {
/* Construct the "masked" store derivation, which is the final
one except that in the list of outputs, the output paths
are empty, and the corresponding environment variables have
an empty value. This ensures that changes in the set of
output names do get reflected in the hash. */
foreach (StringSet::iterator, i, outputs) {
drv.env[*i] = "";
drv.outputs[*i] = DerivationOutput("", "", "");
} }
/* Use the masked derivation expression to compute the output /* Use the masked derivation expression to compute the output
path. !!! Isn't it a potential security problem that the name path. */
of each output path (including the suffix) isn't taken into
account? For instance, changing the suffix for one path
(i->first == "out" ...) doesn't affect the hash of the
others. Is that exploitable? */
if (!fixedOnly) {
Hash h = hashDerivationModulo(drv); Hash h = hashDerivationModulo(drv);
foreach (DerivationOutputs::iterator, i, drv.outputs) foreach (DerivationOutputs::iterator, i, drv.outputs)
if (i->second.path == "") { if (i->second.path == "") {
Path outPath = makeOutputPath(i->first, h, drvName); Path outPath = makeOutputPath(i->first, h, drvName);