summaryrefslogtreecommitdiff
path: root/src/graph.cc
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2015-03-19 08:42:46 -0700
committerNico Weber <nicolasweber@gmx.de>2015-03-19 09:45:58 -0700
commitb334523f1da03adfcd23b6e7e7a66c8fcbf87840 (patch)
treeaa073a311c1e3380e26592b85e437322757f2921 /src/graph.cc
parentbc38ef76ebfabe503b1b56a1e32827a851037766 (diff)
downloadninja-b334523f1da03adfcd23b6e7e7a66c8fcbf87840.tar.gz
Make failing stat() calls abort the build.
Fixes #830, fixes #904. In practice, this either happens with 64-bit inodes and a 32-bit userspace when building without -D_FILE_OFFSET_BITS=64 in CFLAGS, or when a filename is longer than the system file length limit. Since DiskInterface::Stat() returns -1 on error, and Node used -1 on "stat state unknown", not aborting the build lead to ninja stat()ing the same file over and over again, until it finally ran out of stack. That's now fixed. * Change RecomputeOutputsDirty() to return success instead of dirty state (like RecomputeDirty()) and return the dirty state in a bool outparam * Node::Stat()s old return value wasn't used anywhere, change the function to return success instead and add an |err| outparam * Node::StatIfNecessary()'s old return value was used only in one place. Change that place to explicitly check status_known() and make StatIfNecessary() return success and add an |err| outparam * Plan::CleanNode() can now fail, make it return bool and add an |err| outparam
Diffstat (limited to 'src/graph.cc')
-rw-r--r--src/graph.cc32
1 files changed, 22 insertions, 10 deletions
diff --git a/src/graph.cc b/src/graph.cc
index e3253fd..b19dc85 100644
--- a/src/graph.cc
+++ b/src/graph.cc
@@ -27,10 +27,15 @@
#include "state.h"
#include "util.h"
-bool Node::Stat(DiskInterface* disk_interface) {
+bool Node::Stat(DiskInterface* disk_interface, string* err) {
METRIC_RECORD("node stat");
mtime_ = disk_interface->Stat(path_);
- return mtime_ > 0;
+ if (mtime_ == -1) {
+ // TODO: Let DiskInterface::Stat() take err instead of it calling Error().
+ *err = "stat failed";
+ return false;
+ }
+ return true;
}
bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
@@ -48,7 +53,8 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
// graphs.
for (vector<Node*>::iterator o = edge->outputs_.begin();
o != edge->outputs_.end(); ++o) {
- (*o)->StatIfNecessary(disk_interface_);
+ if (!(*o)->StatIfNecessary(disk_interface_, err))
+ return false;
}
if (!dep_loader_.LoadDeps(edge, err)) {
@@ -62,7 +68,9 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
Node* most_recent_input = NULL;
for (vector<Node*>::iterator i = edge->inputs_.begin();
i != edge->inputs_.end(); ++i) {
- if ((*i)->StatIfNecessary(disk_interface_)) {
+ if (!(*i)->status_known()) {
+ if (!(*i)->StatIfNecessary(disk_interface_, err))
+ return false;
if (Edge* in_edge = (*i)->in_edge()) {
if (!RecomputeDirty(in_edge, err))
return false;
@@ -97,7 +105,8 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
// We may also be dirty due to output state: missing outputs, out of
// date outputs, etc. Visit all outputs and determine whether they're dirty.
if (!dirty)
- dirty = RecomputeOutputsDirty(edge, most_recent_input);
+ if (!RecomputeOutputsDirty(edge, most_recent_input, &dirty, err))
+ return false;
// Finally, visit each output and update their dirty state if necessary.
for (vector<Node*>::iterator o = edge->outputs_.begin();
@@ -117,16 +126,19 @@ bool DependencyScan::RecomputeDirty(Edge* edge, string* err) {
return true;
}
-bool DependencyScan::RecomputeOutputsDirty(Edge* edge,
- Node* most_recent_input) {
+bool DependencyScan::RecomputeOutputsDirty(Edge* edge, Node* most_recent_input,
+ bool* outputs_dirty, string* err) {
string command = edge->EvaluateCommand(/*incl_rsp_file=*/true);
for (vector<Node*>::iterator o = edge->outputs_.begin();
o != edge->outputs_.end(); ++o) {
- (*o)->StatIfNecessary(disk_interface_);
- if (RecomputeOutputDirty(edge, most_recent_input, command, *o))
+ if (!(*o)->StatIfNecessary(disk_interface_, err))
+ return false;
+ if (RecomputeOutputDirty(edge, most_recent_input, command, *o)) {
+ *outputs_dirty = true;
return true;
+ }
}
- return false;
+ return true;
}
bool DependencyScan::RecomputeOutputDirty(Edge* edge,