| Index: net/tools/dump_cache/dump_files.cc
|
| ===================================================================
|
| --- net/tools/dump_cache/dump_files.cc (revision 0)
|
| +++ net/tools/dump_cache/dump_files.cc (revision 0)
|
| @@ -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;
|
| +}
|
|
|
| Property changes on: net\tools\dump_cache\dump_files.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|