1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/tools/dump_cache/simple_cache_dumper.h" 6 7 #include "base/at_exit.h" 8 #include "base/command_line.h" 9 #include "base/logging.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/message_loop/message_loop.h" 12 #include "base/message_loop/message_loop_proxy.h" 13 #include "base/threading/thread.h" 14 #include "net/base/cache_type.h" 15 #include "net/base/io_buffer.h" 16 #include "net/base/net_errors.h" 17 #include "net/disk_cache/disk_cache.h" 18 #include "net/tools/dump_cache/cache_dumper.h" 19 20 namespace net { 21 22 SimpleCacheDumper::SimpleCacheDumper(base::FilePath input_path, 23 base::FilePath output_path) 24 : state_(STATE_NONE), 25 input_path_(input_path), 26 output_path_(output_path), 27 writer_(new DiskDumper(output_path)), 28 cache_thread_(new base::Thread("CacheThead")), 29 iter_(NULL), 30 src_entry_(NULL), 31 dst_entry_(NULL), 32 io_callback_(base::Bind(&SimpleCacheDumper::OnIOComplete, 33 base::Unretained(this))), 34 rv_(0) { 35 } 36 37 SimpleCacheDumper::~SimpleCacheDumper() { 38 } 39 40 int SimpleCacheDumper::Run() { 41 base::MessageLoopForIO main_message_loop; 42 43 LOG(INFO) << "Reading cache from: " << input_path_.value(); 44 LOG(INFO) << "Writing cache to: " << output_path_.value(); 45 46 if (!cache_thread_->StartWithOptions( 47 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))) { 48 LOG(ERROR) << "Unable to start thread"; 49 return ERR_UNEXPECTED; 50 } 51 state_ = STATE_CREATE_CACHE; 52 int rv = DoLoop(OK); 53 if (rv == ERR_IO_PENDING) { 54 main_message_loop.Run(); 55 return rv_; 56 } 57 return rv; 58 } 59 60 int SimpleCacheDumper::DoLoop(int rv) { 61 do { 62 State state = state_; 63 state_ = STATE_NONE; 64 switch (state) { 65 case STATE_CREATE_CACHE: 66 CHECK_EQ(OK, rv); 67 rv = DoCreateCache(); 68 break; 69 case STATE_CREATE_CACHE_COMPLETE: 70 rv = DoCreateCacheComplete(rv); 71 break; 72 case STATE_OPEN_ENTRY: 73 CHECK_EQ(OK, rv); 74 rv = DoOpenEntry(); 75 break; 76 case STATE_OPEN_ENTRY_COMPLETE: 77 rv = DoOpenEntryComplete(rv); 78 break; 79 case STATE_CREATE_ENTRY: 80 CHECK_EQ(OK, rv); 81 rv = DoCreateEntry(); 82 break; 83 case STATE_CREATE_ENTRY_COMPLETE: 84 rv = DoCreateEntryComplete(rv); 85 break; 86 case STATE_READ_HEADERS: 87 CHECK_EQ(OK, rv); 88 rv = DoReadHeaders(); 89 break; 90 case STATE_READ_HEADERS_COMPLETE: 91 rv = DoReadHeadersComplete(rv); 92 break; 93 case STATE_WRITE_HEADERS: 94 CHECK_EQ(OK, rv); 95 rv = DoWriteHeaders(); 96 break; 97 case STATE_WRITE_HEADERS_COMPLETE: 98 rv = DoWriteHeadersComplete(rv); 99 break; 100 case STATE_READ_BODY: 101 CHECK_EQ(OK, rv); 102 rv = DoReadBody(); 103 break; 104 case STATE_READ_BODY_COMPLETE: 105 rv = DoReadBodyComplete(rv); 106 break; 107 case STATE_WRITE_BODY: 108 CHECK_EQ(OK, rv); 109 rv = DoWriteBody(); 110 break; 111 case STATE_WRITE_BODY_COMPLETE: 112 rv = DoWriteBodyComplete(rv); 113 break; 114 default: 115 NOTREACHED() << "state_: " << state_; 116 break; 117 } 118 } while (state_ != STATE_NONE && rv != ERR_IO_PENDING); 119 return rv; 120 } 121 122 int SimpleCacheDumper::DoCreateCache() { 123 DCHECK(!cache_); 124 state_ = STATE_CREATE_CACHE_COMPLETE; 125 return disk_cache::CreateCacheBackend( 126 DISK_CACHE, 127 CACHE_BACKEND_DEFAULT, 128 input_path_, 129 0, 130 false, 131 cache_thread_->message_loop_proxy().get(), 132 NULL, 133 &cache_, 134 io_callback_); 135 } 136 137 int SimpleCacheDumper::DoCreateCacheComplete(int rv) { 138 if (rv < 0) 139 return rv; 140 141 reinterpret_cast<disk_cache::BackendImpl*>(cache_.get())->SetUpgradeMode(); 142 reinterpret_cast<disk_cache::BackendImpl*>(cache_.get())->SetFlags( 143 disk_cache::kNoRandom); 144 145 state_ = STATE_OPEN_ENTRY; 146 return OK; 147 } 148 149 int SimpleCacheDumper::DoOpenEntry() { 150 DCHECK(!dst_entry_); 151 DCHECK(!src_entry_); 152 state_ = STATE_OPEN_ENTRY_COMPLETE; 153 return cache_->OpenNextEntry(&iter_, &src_entry_, io_callback_); 154 } 155 156 int SimpleCacheDumper::DoOpenEntryComplete(int rv) { 157 // ERR_FAILED indicates iteration finished. 158 if (rv == ERR_FAILED) { 159 cache_->EndEnumeration(&iter_); 160 return OK; 161 } 162 163 if (rv < 0) 164 return rv; 165 166 state_ = STATE_CREATE_ENTRY; 167 return OK; 168 } 169 170 int SimpleCacheDumper::DoCreateEntry() { 171 DCHECK(!dst_entry_); 172 state_ = STATE_CREATE_ENTRY_COMPLETE; 173 174 return writer_->CreateEntry(src_entry_->GetKey(), &dst_entry_, 175 io_callback_); 176 } 177 178 int SimpleCacheDumper::DoCreateEntryComplete(int rv) { 179 if (rv < 0) 180 return rv; 181 182 state_ = STATE_READ_HEADERS; 183 return OK; 184 } 185 186 int SimpleCacheDumper::DoReadHeaders() { 187 state_ = STATE_READ_HEADERS_COMPLETE; 188 int32 size = src_entry_->GetDataSize(0); 189 buf_ = new IOBufferWithSize(size); 190 return src_entry_->ReadData(0, 0, buf_.get(), size, io_callback_); 191 } 192 193 int SimpleCacheDumper::DoReadHeadersComplete(int rv) { 194 if (rv < 0) 195 return rv; 196 197 state_ = STATE_WRITE_HEADERS; 198 return OK; 199 } 200 201 int SimpleCacheDumper::DoWriteHeaders() { 202 int rv = writer_->WriteEntry( 203 dst_entry_, 0, 0, buf_.get(), buf_->size(), io_callback_); 204 if (rv == 0) 205 return ERR_FAILED; 206 207 state_ = STATE_WRITE_HEADERS_COMPLETE; 208 return OK; 209 } 210 211 int SimpleCacheDumper::DoWriteHeadersComplete(int rv) { 212 if (rv < 0) 213 return rv; 214 215 state_ = STATE_READ_BODY; 216 return OK; 217 } 218 219 int SimpleCacheDumper::DoReadBody() { 220 state_ = STATE_READ_BODY_COMPLETE; 221 int32 size = src_entry_->GetDataSize(1); 222 // If the body is empty, we can neither read nor write it, so 223 // just move to the next. 224 if (size <= 0) { 225 state_ = STATE_WRITE_BODY_COMPLETE; 226 return OK; 227 } 228 buf_ = new IOBufferWithSize(size); 229 return src_entry_->ReadData(1, 0, buf_.get(), size, io_callback_); 230 } 231 232 int SimpleCacheDumper::DoReadBodyComplete(int rv) { 233 if (rv < 0) 234 return rv; 235 236 state_ = STATE_WRITE_BODY; 237 return OK; 238 } 239 240 int SimpleCacheDumper::DoWriteBody() { 241 int rv = writer_->WriteEntry( 242 dst_entry_, 1, 0, buf_.get(), buf_->size(), io_callback_); 243 if (rv == 0) 244 return ERR_FAILED; 245 246 state_ = STATE_WRITE_BODY_COMPLETE; 247 return OK; 248 } 249 250 int SimpleCacheDumper::DoWriteBodyComplete(int rv) { 251 if (rv < 0) 252 return rv; 253 254 src_entry_->Close(); 255 writer_->CloseEntry(dst_entry_, base::Time::Now(), base::Time::Now()); 256 src_entry_ = NULL; 257 dst_entry_ = NULL; 258 259 state_ = STATE_OPEN_ENTRY; 260 return OK; 261 } 262 263 void SimpleCacheDumper::OnIOComplete(int rv) { 264 rv = DoLoop(rv); 265 266 if (rv != ERR_IO_PENDING) { 267 rv_ = rv; 268 cache_.reset(); 269 base::MessageLoop::current()->Quit(); 270 } 271 } 272 273 } // namespace net 274