On invalid depslog header, restart build instead of showing an error.
[platform/upstream/ninja.git] / src / deps_log.cc
1 // Copyright 2012 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "deps_log.h"
16
17 #include <assert.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #include <string.h>
21 #include <unistd.h>
22
23 #include "graph.h"
24 #include "metrics.h"
25 #include "state.h"
26 #include "util.h"
27
28 // The version is stored as 4 bytes after the signature and also serves as a
29 // byte order mark. Signature and version combined are 16 bytes long.
30 const char kFileSignature[] = "# ninjadeps\n";
31 const int kCurrentVersion = 1;
32
33 DepsLog::~DepsLog() {
34   Close();
35 }
36
37 bool DepsLog::OpenForWrite(const string& path, string* err) {
38   file_ = fopen(path.c_str(), "ab");
39   if (!file_) {
40     *err = strerror(errno);
41     return false;
42   }
43   SetCloseOnExec(fileno(file_));
44
45   // Opening a file in append mode doesn't set the file pointer to the file's
46   // end on Windows. Do that explicitly.
47   fseek(file_, 0, SEEK_END);
48
49   if (ftell(file_) == 0) {
50     if (fwrite(kFileSignature, sizeof(kFileSignature) - 1, 1, file_) < 1) {
51       *err = strerror(errno);
52       return false;
53     }
54     if (fwrite(&kCurrentVersion, 4, 1, file_) < 1) {
55       *err = strerror(errno);
56       return false;
57     }
58   }
59
60   return true;
61 }
62
63 bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
64                          const vector<Node*>& nodes) {
65   return RecordDeps(node, mtime, nodes.size(),
66                     nodes.empty() ? NULL : (Node**)&nodes.front());
67 }
68
69 bool DepsLog::RecordDeps(Node* node, TimeStamp mtime,
70                          int node_count, Node** nodes) {
71   // Track whether there's any new data to be recorded.
72   bool made_change = false;
73
74   // Assign ids to all nodes that are missing one.
75   if (node->id() < 0) {
76     RecordId(node);
77     made_change = true;
78   }
79   for (int i = 0; i < node_count; ++i) {
80     if (nodes[i]->id() < 0) {
81       RecordId(nodes[i]);
82       made_change = true;
83     }
84   }
85
86   // See if the new data is different than the existing data, if any.
87   if (!made_change) {
88     Deps* deps = GetDeps(node);
89     if (!deps ||
90         deps->mtime != mtime ||
91         deps->node_count != node_count) {
92       made_change = true;
93     } else {
94       for (int i = 0; i < node_count; ++i) {
95         if (deps->nodes[i] != nodes[i]) {
96           made_change = true;
97           break;
98         }
99       }
100     }
101   }
102
103   // Don't write anything if there's no new info.
104   if (!made_change)
105     return true;
106
107   uint16_t size = 4 * (1 + 1 + (uint16_t)node_count);
108   size |= 0x8000;  // Deps record: set high bit.
109   fwrite(&size, 2, 1, file_);
110   int id = node->id();
111   fwrite(&id, 4, 1, file_);
112   int timestamp = mtime;
113   fwrite(&timestamp, 4, 1, file_);
114   for (int i = 0; i < node_count; ++i) {
115     id = nodes[i]->id();
116     fwrite(&id, 4, 1, file_);
117   }
118
119   return true;
120 }
121
122 void DepsLog::Close() {
123   if (file_)
124     fclose(file_);
125   file_ = NULL;
126 }
127
128 bool DepsLog::Load(const string& path, State* state, string* err) {
129   METRIC_RECORD(".ninja_deps load");
130   char buf[32 << 10];
131   FILE* f = fopen(path.c_str(), "rb");
132   if (!f) {
133     if (errno == ENOENT)
134       return true;
135     *err = strerror(errno);
136     return false;
137   }
138
139   bool valid_header = true;
140   int version = 0;
141   if (!fgets(buf, sizeof(buf), f) || fread(&version, 4, 1, f) < 1)
142     valid_header = false;
143   if (!valid_header || strcmp(buf, kFileSignature) != 0 ||
144       version != kCurrentVersion) {
145     *err = "bad deps log signature or version; starting over";
146     fclose(f);
147     unlink(path.c_str());
148     // Don't report this as a failure.  An empty deps log will cause
149     // us to rebuild the outputs anyway.
150     return true;
151   }
152
153   for (;;) {
154     uint16_t size;
155     if (fread(&size, 2, 1, f) < 1)
156       break;
157     bool is_deps = (size >> 15) != 0;
158     size = size & 0x7FFF;
159
160     if (fread(buf, size, 1, f) < 1)
161       break;
162
163     if (is_deps) {
164       assert(size % 4 == 0);
165       int* deps_data = reinterpret_cast<int*>(buf);
166       int out_id = deps_data[0];
167       int mtime = deps_data[1];
168       deps_data += 2;
169       int deps_count = (size / 4) - 2;
170
171       Deps* deps = new Deps;
172       deps->mtime = mtime;
173       deps->node_count = deps_count;
174       deps->nodes = new Node*[deps_count];
175       for (int i = 0; i < deps_count; ++i) {
176         assert(deps_data[i] < (int)nodes_.size());
177         assert(nodes_[deps_data[i]]);
178         deps->nodes[i] = nodes_[deps_data[i]];
179       }
180
181       if (out_id >= (int)deps_.size())
182         deps_.resize(out_id + 1);
183       if (deps_[out_id]) {
184         ++dead_record_count_;
185         delete deps_[out_id];
186       }
187       deps_[out_id] = deps;
188     } else {
189       StringPiece path(buf, size);
190       Node* node = state->GetNode(path);
191       assert(node->id() < 0);
192       node->set_id(nodes_.size());
193       nodes_.push_back(node);
194     }
195   }
196   if (ferror(f)) {
197     *err = strerror(ferror(f));
198     return false;
199   }
200   fclose(f);
201   return true;
202 }
203
204 DepsLog::Deps* DepsLog::GetDeps(Node* node) {
205   if (node->id() < 0)
206     return NULL;
207   return deps_[node->id()];
208 }
209
210 bool DepsLog::Recompact(const string& path, string* err) {
211   METRIC_RECORD(".ninja_deps recompact");
212   printf("Recompacting deps...\n");
213
214   string temp_path = path + ".recompact";
215   DepsLog new_log;
216   if (!new_log.OpenForWrite(temp_path, err))
217     return false;
218
219   // Clear all known ids so that new ones can be reassigned.
220   for (vector<Node*>::iterator i = nodes_.begin();
221        i != nodes_.end(); ++i) {
222     (*i)->set_id(-1);
223   }
224
225   // Write out all deps again.
226   for (int old_id = 0; old_id < (int)deps_.size(); ++old_id) {
227     Deps* deps = deps_[old_id];
228     if (!new_log.RecordDeps(nodes_[old_id], deps->mtime,
229                             deps->node_count, deps->nodes)) {
230       new_log.Close();
231       return false;
232     }
233   }
234
235   new_log.Close();
236
237   if (unlink(path.c_str()) < 0) {
238     *err = strerror(errno);
239     return false;
240   }
241
242   if (rename(temp_path.c_str(), path.c_str()) < 0) {
243     *err = strerror(errno);
244     return false;
245   }
246
247   return true;
248 }
249
250 bool DepsLog::RecordId(Node* node) {
251   uint16_t size = (uint16_t)node->path().size();
252   fwrite(&size, 2, 1, file_);
253   fwrite(node->path().data(), node->path().size(), 1, file_);
254
255   node->set_id(nodes_.size());
256   nodes_.push_back(node);
257
258   return true;
259 }