summaryrefslogtreecommitdiffstats
path: root/net/tools/dump_cache/dump_files.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/tools/dump_cache/dump_files.cc')
-rw-r--r--net/tools/dump_cache/dump_files.cc300
1 files changed, 300 insertions, 0 deletions
diff --git a/net/tools/dump_cache/dump_files.cc b/net/tools/dump_cache/dump_files.cc
new file mode 100644
index 0000000..67bdad2
--- /dev/null
+++ b/net/tools/dump_cache/dump_files.cc
@@ -0,0 +1,300 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Performs basic inspection of the disk cache files with minimal disruption
+// to the actual files (they still may change if an error is detected on the
+// files).
+
+#include <stdio.h>
+#include <string>
+
+#include "base/file_util.h"
+#include "base/message_loop.h"
+#include "net/base/file_stream.h"
+#include "net/disk_cache/block_files.h"
+#include "net/disk_cache/disk_format.h"
+#include "net/disk_cache/mapped_file.h"
+#include "net/disk_cache/storage_block.h"
+
+namespace {
+
+const wchar_t kIndexName[] = L"index";
+const wchar_t kDataPrefix[] = L"data_";
+
+// Reads the |header_size| bytes from the beginning of file |name|.
+bool ReadHeader(const std::wstring name, char* header, int header_size) {
+ net::FileStream file;
+ file.Open(name, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
+ if (!file.IsOpen()) {
+ printf("Unable to open file %ls\n", name.c_str());
+ return false;
+ }
+
+ int read = file.Read(header, header_size, NULL);
+ if (read != header_size) {
+ printf("Unable to read file %ls\n", name.c_str());
+ return false;
+ }
+ return true;
+}
+
+int GetMajorVersionFromFile(const std::wstring name) {
+ disk_cache::IndexHeader header;
+ if (!ReadHeader(name, reinterpret_cast<char*>(&header), sizeof(header)))
+ return 0;
+
+ return header.version >> 16;
+}
+
+// Dumps the contents of the Index-file header.
+void DumpIndexHeader(const std::wstring name) {
+ disk_cache::IndexHeader header;
+ if (!ReadHeader(name, reinterpret_cast<char*>(&header), sizeof(header)))
+ return;
+
+ printf("Index file:\n");
+ printf("magic: %x\n", header.magic);
+ printf("version: %d.%d\n", header.version >> 16, header.version & 0xffff);
+ printf("entries: %d\n", header.num_entries);
+ printf("total bytes: %d\n", header.num_bytes);
+ printf("last file number: %d\n", header.last_file);
+ printf("current id: %d\n", header.this_id);
+ printf("table length: %d\n", header.table_len);
+ printf("-------------------------\n\n");
+}
+
+// Dumps the contents of a block-file header.
+void DumpBlockHeader(const std::wstring name) {
+ disk_cache::BlockFileHeader header;
+ if (!ReadHeader(name, reinterpret_cast<char*>(&header), sizeof(header)))
+ return;
+
+ std::wstring file_name = file_util::GetFilenameFromPath(name);
+
+ printf("Block file: %ls\n", file_name.c_str());
+ printf("magic: %x\n", header.magic);
+ printf("version: %d.%d\n", header.version >> 16, header.version & 0xffff);
+ printf("file id: %d\n", header.this_file);
+ printf("next file id: %d\n", header.next_file);
+ printf("entry size: %d\n", header.entry_size);
+ printf("current entries: %d\n", header.num_entries);
+ printf("max entries: %d\n", header.max_entries);
+ printf("updating: %d\n", header.updating);
+ printf("empty sz 1: %d\n", header.empty[0]);
+ printf("empty sz 2: %d\n", header.empty[1]);
+ printf("empty sz 3: %d\n", header.empty[2]);
+ printf("empty sz 4: %d\n", header.empty[3]);
+ printf("user 0: 0x%x\n", header.user[0]);
+ printf("user 1: 0x%x\n", header.user[1]);
+ printf("user 2: 0x%x\n", header.user[2]);
+ printf("user 3: 0x%x\n", header.user[3]);
+ printf("-------------------------\n\n");
+}
+
+// Simple class that interacts with the set of cache files.
+class CacheDumper {
+ public:
+ explicit CacheDumper(const std::wstring path)
+ : path_(path), block_files_(path), index_(NULL) {}
+
+ bool Init();
+
+ // Reads an entry from disk. Return false when all entries have been already
+ // returned.
+ bool GetEntry(disk_cache::EntryStore* entry);
+
+ // Loads a specific block from the block files.
+ bool LoadEntry(disk_cache::CacheAddr addr, disk_cache::EntryStore* entry);
+ bool LoadRankings(disk_cache::CacheAddr addr,
+ disk_cache::RankingsNode* rankings);
+
+ private:
+ std::wstring path_;
+ disk_cache::BlockFiles block_files_;
+ scoped_refptr<disk_cache::MappedFile> index_file_;
+ disk_cache::Index* index_;
+ int current_hash_;
+ disk_cache::CacheAddr next_addr_;
+ DISALLOW_COPY_AND_ASSIGN(CacheDumper);
+};
+
+bool CacheDumper::Init() {
+ if (!block_files_.Init(false)) {
+ printf("Unable to init block files\n");
+ return false;
+ }
+
+ std::wstring index_name(path_);
+ file_util::AppendToPath(&index_name, kIndexName);
+ index_file_ = new disk_cache::MappedFile;
+ index_ =
+ reinterpret_cast<disk_cache::Index*>(index_file_->Init(index_name, 0));
+ if (!index_) {
+ printf("Unable to map index\n");
+ return false;
+ }
+
+ current_hash_ = 0;
+ next_addr_ = 0;
+ return true;
+}
+
+bool CacheDumper::GetEntry(disk_cache::EntryStore* entry) {
+ if (next_addr_) {
+ if (LoadEntry(next_addr_, entry)) {
+ next_addr_ = entry->next;
+ if (!next_addr_)
+ current_hash_++;
+ return true;
+ } else {
+ printf("Unable to load entry at address 0x%x\n", next_addr_);
+ next_addr_ = 0;
+ current_hash_++;
+ }
+ }
+
+ for (int i = current_hash_; i < index_->header.table_len; i++) {
+ // Yes, we'll crash if the table is shorter than expected, but only after
+ // dumping every entry that we can find.
+ if (index_->table[i]) {
+ current_hash_ = i;
+ if (LoadEntry(index_->table[i], entry)) {
+ next_addr_ = entry->next;
+ if (!next_addr_)
+ current_hash_++;
+ return true;
+ } else {
+ printf("Unable to load entry at address 0x%x\n", index_->table[i]);
+ }
+ }
+ }
+ return false;
+}
+
+bool CacheDumper::LoadEntry(disk_cache::CacheAddr addr,
+ disk_cache::EntryStore* entry) {
+ disk_cache::Addr address(addr);
+ disk_cache::MappedFile* file = block_files_.GetFile(address);
+ if (!file)
+ return false;
+
+ disk_cache::CacheEntryBlock entry_block(file, address);
+ if (!entry_block.Load())
+ return false;
+
+ memcpy(entry, entry_block.Data(), sizeof(*entry));
+ printf("Entry at 0x%x\n", addr);
+ return true;
+}
+
+bool CacheDumper::LoadRankings(disk_cache::CacheAddr addr,
+ disk_cache::RankingsNode* rankings) {
+ disk_cache::Addr address(addr);
+ disk_cache::MappedFile* file = block_files_.GetFile(address);
+ if (!file)
+ return false;
+
+ disk_cache::CacheRankingsBlock rank_block(file, address);
+ if (!rank_block.Load())
+ return false;
+
+ memcpy(rankings, rank_block.Data(), sizeof(*rankings));
+ printf("Rankings at 0x%x\n", addr);
+ return true;
+}
+
+void DumpEntry(const disk_cache::EntryStore& entry) {
+ std::string key;
+ if (!entry.long_key) {
+ key = entry.key;
+ if (key.size() > 50)
+ key.resize(50);
+ }
+
+ printf("hash: 0x%x\n", entry.hash);
+ printf("next entry: 0x%x\n", entry.next);
+ printf("rankings: 0x%x\n", entry.rankings_node);
+ printf("key length: %d\n", entry.key_len);
+ printf("key: \"%s\"\n", key.c_str());
+ printf("key addr: 0x%x\n", entry.long_key);
+ printf("data size 0: %d\n", entry.data_size[0]);
+ printf("data size 1: %d\n", entry.data_size[1]);
+ printf("data addr 0: 0x%x\n", entry.data_addr[0]);
+ printf("data addr 1: 0x%x\n", entry.data_addr[1]);
+ printf("----------\n\n");
+}
+
+void DumpRankings(const disk_cache::RankingsNode& rankings) {
+ printf("next: 0x%x\n", rankings.next);
+ printf("prev: 0x%x\n", rankings.prev);
+ printf("entry: 0x%x\n", rankings.contents);
+ printf("dirty: %d\n", rankings.dirty);
+ printf("pointer: 0x%x\n", rankings.pointer);
+ printf("----------\n\n");
+}
+
+} // namespace.
+
+// -----------------------------------------------------------------------
+
+int GetMajorVersion(const std::wstring input_path) {
+ std::wstring index_name(input_path);
+ file_util::AppendToPath(&index_name, kIndexName);
+
+ int version = GetMajorVersionFromFile(index_name);
+ if (!version)
+ return 0;
+
+ std::wstring data_name(input_path);
+ file_util::AppendToPath(&data_name, L"data_0");
+ if (version != GetMajorVersionFromFile(data_name))
+ return 0;
+
+ data_name = input_path;
+ file_util::AppendToPath(&data_name, L"data_1");
+ if (version != GetMajorVersionFromFile(data_name))
+ return 0;
+
+ return version;
+}
+
+// Dumps the headers of all files.
+int DumpHeaders(const std::wstring input_path) {
+ std::wstring index_name(input_path);
+ file_util::AppendToPath(&index_name, kIndexName);
+ DumpIndexHeader(index_name);
+
+ std::wstring pattern(kDataPrefix);
+ pattern.append(L"*");
+ file_util::FileEnumerator iter(input_path, false,
+ file_util::FileEnumerator::FILES, pattern);
+ for (std::wstring file = iter.Next(); !file.empty(); file = iter.Next()) {
+ DumpBlockHeader(file);
+ }
+
+ return 0;
+}
+
+// Dumps all entries from the cache.
+int DumpContents(const std::wstring input_path) {
+ DumpHeaders(input_path);
+
+ // We need a message loop, although we really don't run any task.
+ MessageLoop loop(MessageLoop::TYPE_IO);
+ CacheDumper dumper(input_path);
+ if (!dumper.Init())
+ return -1;
+
+ disk_cache::EntryStore entry;
+ while (dumper.GetEntry(&entry)) {
+ DumpEntry(entry);
+ disk_cache::RankingsNode rankings;
+ if (dumper.LoadRankings(entry.rankings_node, &rankings))
+ DumpRankings(rankings);
+ }
+
+ printf("Done.\n");
+
+ return 0;
+}