+/* Read the next entry from the old statcache file and cache it in memory. */
+void StatCache::ReadNext()
+{
+ if (oldcache == NULL) {
+ end_of_cache = true;
+ return;
+ }
+
+ std::istream &cache = *oldcache;
+ map<string, string> fields;
+
+ old_is_validated = false;
+ old_mtime = -1;
+ old_ctime = -1;
+ old_inode = -1;
+ old_size = -1;
+ old_checksum = "";
+ old_contents.clear();
+
+ /* First, read in the filename. */
+ getline(cache, old_name);
+ if (!cache) {
+ end_of_cache = true;
+ return;
+ }
+ old_name = uri_decode(old_name);
+
+ /* Start reading in the fields which follow the filename. */
+ string field = "";
+ while (!cache.eof()) {
+ string line;
+ getline(cache, line);
+ const char *s = line.c_str();
+
+ /* Is the line blank? If so, we have reached the end of this entry. */
+ if (s[0] == '\0' || s[0] == '\n')
+ break;
+
+ /* Is this a continuation line? (Does it start with whitespace?) */
+ if (isspace(s[0]) && field != "") {
+ fields[field] += line;
+ continue;
+ }
+
+ /* For lines of the form "Key: Value" look for ':' and split the line
+ * apart. */
+ const char *value = strchr(s, ':');
+ if (value == NULL)
+ continue;
+ field = string(s, value - s);
+
+ value++;
+ while (isspace(*value))
+ value++;
+
+ fields[field] = value;
+ }
+
+ /* Parse the easy fields: mtime, ctime, inode, checksum, ... */
+ if (fields.count("validated"))
+ old_is_validated = true;
+ if (fields.count("mtime"))
+ old_mtime = parse_int(fields["mtime"]);
+ if (fields.count("ctime"))
+ old_ctime = parse_int(fields["ctime"]);
+ if (fields.count("inode"))
+ old_inode = parse_int(fields["inode"]);
+ if (fields.count("size"))
+ old_size = parse_int(fields["size"]);
+
+ old_checksum = fields["checksum"];
+
+ /* Parse the list of blocks. */
+ const char *s = fields["blocks"].c_str();
+ while (*s != '\0') {
+ if (isspace(*s)) {
+ s++;
+ continue;
+ }
+
+ string ref = "";
+ while (*s != '\0' && !isspace(*s)) {
+ char buf[2];
+ buf[0] = *s;
+ buf[1] = '\0';
+ ref += buf;
+ s++;
+ }
+
+ ObjectReference *r = ObjectReference::parse(ref);
+ if (r != NULL) {
+ old_contents.push_back(*r);
+ delete r;
+ }
+ }
+
+ end_of_cache = false;
+}
+
+/* Find information about the given filename in the old stat cache, if it
+ * exists. */
+bool StatCache::Find(const string &path, const struct stat *stat_buf)
+{
+ while (!end_of_cache && pathcmp(old_name.c_str(), path.c_str()) < 0)
+ ReadNext();
+
+ /* Could the file be found at all? */
+ if (end_of_cache)
+ return false;
+ if (old_name != path)
+ return false;
+
+ /* Do we trust cached stat information? */
+ if (!old_is_validated)
+ return false;
+
+ /* Check to see if the file is unchanged. */
+ if (stat_buf->st_mtime != old_mtime)
+ return false;
+ if (stat_buf->st_ctime != old_ctime)
+ return false;
+ if ((long long)stat_buf->st_ino != old_inode)
+ return false;
+ if (stat_buf->st_size != old_size)
+ return false;
+
+ /* File looks to be unchanged. */
+ return true;
+}
+