summaryrefslogtreecommitdiffstats
path: root/src/deps_log.cc
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2013-04-27 20:39:04 (GMT)
committerEvan Martin <martine@danga.com>2013-04-27 20:39:04 (GMT)
commitb549d18748a82d2a0e0efccb5ac6d9e3714f5234 (patch)
tree6c4837a75a2bef428c8656cc7b425cc712907b9e /src/deps_log.cc
parent896b81c1fe50b11012a34365a11b8fcaba33350f (diff)
downloadNinja-b549d18748a82d2a0e0efccb5ac6d9e3714f5234.zip
Ninja-b549d18748a82d2a0e0efccb5ac6d9e3714f5234.tar.gz
Ninja-b549d18748a82d2a0e0efccb5ac6d9e3714f5234.tar.bz2
deps log: recover on truncated entry
If a read fails while reading an entry, truncate the log to the last successfully read entry. This prevents corruption when a subsequent run appends another entry.
Diffstat (limited to 'src/deps_log.cc')
-rw-r--r--src/deps_log.cc41
1 files changed, 35 insertions, 6 deletions
diff --git a/src/deps_log.cc b/src/deps_log.cc
index ceb75ce..5e5bba9 100644
--- a/src/deps_log.cc
+++ b/src/deps_log.cc
@@ -152,15 +152,23 @@ bool DepsLog::Load(const string& path, State* state, string* err) {
return true;
}
+ long offset;
+ bool read_failed = false;
for (;;) {
+ offset = ftell(f);
+
uint16_t size;
- if (fread(&size, 2, 1, f) < 1)
+ if (fread(&size, 2, 1, f) < 1) {
+ read_failed = true;
break;
+ }
bool is_deps = (size >> 15) != 0;
size = size & 0x7FFF;
- if (fread(buf, size, 1, f) < 1)
+ if (fread(buf, size, 1, f) < 1) {
+ read_failed = true;
break;
+ }
if (is_deps) {
assert(size % 4 == 0);
@@ -195,16 +203,37 @@ bool DepsLog::Load(const string& path, State* state, string* err) {
nodes_.push_back(node);
}
}
- if (ferror(f)) {
- *err = strerror(ferror(f));
- return false;
+
+ if (read_failed) {
+ // An error occurred while loading; try to recover by truncating the
+ // file to the last fully-read record.
+ if (ferror(f)) {
+ *err = strerror(ferror(f));
+ } else {
+ *err = "premature end of file";
+ }
+ fclose(f);
+
+ if (truncate(path.c_str(), offset) < 0) {
+ *err = strerror(errno);
+ return false;
+ }
+
+ // The truncate succeeded; we'll just report the load error as a
+ // warning because the build can proceed.
+ *err += "; recovering";
+ return true;
}
+
fclose(f);
+
return true;
}
DepsLog::Deps* DepsLog::GetDeps(Node* node) {
- if (node->id() < 0)
+ // Abort if the node has no id (never referenced in the deps) or if
+ // there's no deps recorded for the node.
+ if (node->id() < 0 || node->id() >= deps_.size())
return NULL;
return deps_[node->id()];
}