| OLD | NEW |
| (Empty) |
| 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/upgrade_win.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/bind_helpers.h" | |
| 9 #include "base/logging.h" | |
| 10 #include "base/memory/scoped_ptr.h" | |
| 11 #include "base/message_loop/message_loop.h" | |
| 12 #include "base/strings/string_number_conversions.h" | |
| 13 #include "base/strings/string_util.h" | |
| 14 #include "base/threading/thread.h" | |
| 15 #include "base/win/scoped_handle.h" | |
| 16 #include "net/base/cache_type.h" | |
| 17 #include "net/base/io_buffer.h" | |
| 18 #include "net/base/net_errors.h" | |
| 19 #include "net/base/test_completion_callback.h" | |
| 20 #include "net/disk_cache/blockfile/backend_impl.h" | |
| 21 #include "net/disk_cache/blockfile/entry_impl.h" | |
| 22 #include "net/http/http_cache.h" | |
| 23 #include "net/http/http_response_headers.h" | |
| 24 #include "net/http/http_response_info.h" | |
| 25 #include "net/tools/dump_cache/cache_dumper.h" | |
| 26 #include "url/gurl.h" | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\dump_cache_"; | |
| 31 const int kChannelSize = 64 * 1024; | |
| 32 const int kNumStreams = 4; | |
| 33 | |
| 34 // Simple macro to print out formatted debug messages. It is similar to a DLOG | |
| 35 // except that it doesn't include a header. | |
| 36 #ifdef NDEBUG | |
| 37 #define DEBUGMSG(...) {} | |
| 38 #else | |
| 39 #define DEBUGMSG(...) { printf(__VA_ARGS__); } | |
| 40 #endif | |
| 41 | |
| 42 HANDLE OpenServer(const base::string16& pipe_number) { | |
| 43 base::string16 pipe_name(kPipePrefix); | |
| 44 pipe_name.append(pipe_number); | |
| 45 return CreateFile(pipe_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, | |
| 46 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); | |
| 47 } | |
| 48 | |
| 49 // This is the basic message to use between the two processes. It is intended | |
| 50 // to transmit a single action (like "get the key name for entry xx"), with up | |
| 51 // to 5 32-bit arguments and 4 64-bit arguments. After this structure, the rest | |
| 52 // of the message has |buffer_bytes| of length with the actual data. | |
| 53 struct Message { | |
| 54 int32 command; | |
| 55 int32 result; | |
| 56 int32 buffer_bytes; | |
| 57 int32 arg1; | |
| 58 int32 arg2; | |
| 59 int32 arg3; | |
| 60 int32 arg4; | |
| 61 int32 arg5; | |
| 62 int64 long_arg1; | |
| 63 int64 long_arg2; | |
| 64 int64 long_arg3; | |
| 65 int64 long_arg4; | |
| 66 Message() { | |
| 67 memset(this, 0, sizeof(*this)); | |
| 68 } | |
| 69 Message& operator= (const Message& other) { | |
| 70 memcpy(this, &other, sizeof(*this)); | |
| 71 return *this; | |
| 72 } | |
| 73 }; | |
| 74 | |
| 75 const int kBufferSize = kChannelSize - sizeof(Message); | |
| 76 struct IoBuffer { | |
| 77 Message msg; | |
| 78 char buffer[kBufferSize]; | |
| 79 }; | |
| 80 COMPILE_ASSERT(sizeof(IoBuffer) == kChannelSize, invalid_io_buffer); | |
| 81 | |
| 82 | |
| 83 // The list of commands. | |
| 84 // Currently, there is support for working ONLY with one entry at a time. | |
| 85 enum { | |
| 86 // Get the entry from list |arg1| that follows |long_arg1|. | |
| 87 // The result is placed on |long_arg1| (closes the previous one). | |
| 88 GET_NEXT_ENTRY = 1, | |
| 89 // Get the entry from list |arg1| that precedes |long_arg1|. | |
| 90 // The result is placed on |long_arg1| (closes the previous one). | |
| 91 GET_PREV_ENTRY, | |
| 92 // Closes the entry |long_arg1|. | |
| 93 CLOSE_ENTRY, | |
| 94 // Get the key of the entry |long_arg1|. | |
| 95 GET_KEY, | |
| 96 // Get last used (long_arg2) and last modified (long_arg3) times for the | |
| 97 // entry at |long_arg1|. | |
| 98 GET_USE_TIMES, | |
| 99 // Returns on |arg2| the data size in bytes if the stream |arg1| of entry at | |
| 100 // |long_arg1|. | |
| 101 GET_DATA_SIZE, | |
| 102 // Returns |arg2| bytes of the stream |arg1| for the entry at |long_arg1|, | |
| 103 // starting at offset |arg3|. | |
| 104 READ_DATA, | |
| 105 // End processing requests. | |
| 106 QUIT | |
| 107 }; | |
| 108 | |
| 109 // The list of return codes. | |
| 110 enum { | |
| 111 RESULT_OK = 0, | |
| 112 RESULT_UNKNOWN_COMMAND, | |
| 113 RESULT_INVALID_PARAMETER, | |
| 114 RESULT_NAME_OVERFLOW, | |
| 115 RESULT_PENDING // This error code is NOT expected by the master process. | |
| 116 }; | |
| 117 | |
| 118 // ----------------------------------------------------------------------- | |
| 119 | |
| 120 class BaseSM : public base::MessageLoopForIO::IOHandler { | |
| 121 public: | |
| 122 explicit BaseSM(HANDLE channel); | |
| 123 virtual ~BaseSM(); | |
| 124 | |
| 125 protected: | |
| 126 bool SendMsg(const Message& msg); | |
| 127 bool ReceiveMsg(); | |
| 128 bool ConnectChannel(); | |
| 129 bool IsPending(); | |
| 130 | |
| 131 base::MessageLoopForIO::IOContext in_context_; | |
| 132 base::MessageLoopForIO::IOContext out_context_; | |
| 133 disk_cache::EntryImpl* entry_; | |
| 134 HANDLE channel_; | |
| 135 int state_; | |
| 136 int pending_count_; | |
| 137 scoped_ptr<char[]> in_buffer_; | |
| 138 scoped_ptr<char[]> out_buffer_; | |
| 139 IoBuffer* input_; | |
| 140 IoBuffer* output_; | |
| 141 base::Thread cache_thread_; | |
| 142 | |
| 143 DISALLOW_COPY_AND_ASSIGN(BaseSM); | |
| 144 }; | |
| 145 | |
| 146 BaseSM::BaseSM(HANDLE channel) | |
| 147 : entry_(NULL), channel_(channel), state_(0), pending_count_(0), | |
| 148 cache_thread_("cache") { | |
| 149 in_buffer_.reset(new char[kChannelSize]); | |
| 150 out_buffer_.reset(new char[kChannelSize]); | |
| 151 input_ = reinterpret_cast<IoBuffer*>(in_buffer_.get()); | |
| 152 output_ = reinterpret_cast<IoBuffer*>(out_buffer_.get()); | |
| 153 | |
| 154 memset(&in_context_, 0, sizeof(in_context_)); | |
| 155 memset(&out_context_, 0, sizeof(out_context_)); | |
| 156 in_context_.handler = this; | |
| 157 out_context_.handler = this; | |
| 158 base::MessageLoopForIO::current()->RegisterIOHandler(channel_, this); | |
| 159 CHECK(cache_thread_.StartWithOptions( | |
| 160 base::Thread::Options(base::MessageLoop::TYPE_IO, 0))); | |
| 161 } | |
| 162 | |
| 163 BaseSM::~BaseSM() { | |
| 164 if (entry_) | |
| 165 entry_->Close(); | |
| 166 } | |
| 167 | |
| 168 bool BaseSM::SendMsg(const Message& msg) { | |
| 169 // Only one command will be in-flight at a time. Let's start the Read IO here | |
| 170 // when we know that it will be pending. | |
| 171 if (!ReceiveMsg()) | |
| 172 return false; | |
| 173 | |
| 174 output_->msg = msg; | |
| 175 DWORD written; | |
| 176 if (!WriteFile(channel_, output_, sizeof(msg) + msg.buffer_bytes, &written, | |
| 177 &out_context_.overlapped)) { | |
| 178 if (ERROR_IO_PENDING != GetLastError()) | |
| 179 return false; | |
| 180 } | |
| 181 pending_count_++; | |
| 182 return true; | |
| 183 } | |
| 184 | |
| 185 bool BaseSM::ReceiveMsg() { | |
| 186 DWORD read; | |
| 187 if (!ReadFile(channel_, input_, kChannelSize, &read, | |
| 188 &in_context_.overlapped)) { | |
| 189 if (ERROR_IO_PENDING != GetLastError()) | |
| 190 return false; | |
| 191 } | |
| 192 pending_count_++; | |
| 193 return true; | |
| 194 } | |
| 195 | |
| 196 bool BaseSM::ConnectChannel() { | |
| 197 if (!ConnectNamedPipe(channel_, &in_context_.overlapped)) { | |
| 198 DWORD error = GetLastError(); | |
| 199 if (ERROR_PIPE_CONNECTED == error) | |
| 200 return true; | |
| 201 // By returning true in case of a generic error, we allow the operation to | |
| 202 // fail while sending the first message. | |
| 203 if (ERROR_IO_PENDING != error) | |
| 204 return true; | |
| 205 } | |
| 206 pending_count_++; | |
| 207 return false; | |
| 208 } | |
| 209 | |
| 210 bool BaseSM::IsPending() { | |
| 211 return pending_count_ != 0; | |
| 212 } | |
| 213 | |
| 214 // ----------------------------------------------------------------------- | |
| 215 | |
| 216 class MasterSM : public BaseSM { | |
| 217 public: | |
| 218 MasterSM(const base::FilePath& path, HANDLE channel) | |
| 219 : BaseSM(channel), | |
| 220 path_(path) { | |
| 221 } | |
| 222 virtual ~MasterSM() { | |
| 223 delete writer_; | |
| 224 } | |
| 225 | |
| 226 bool DoInit(); | |
| 227 virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context, | |
| 228 DWORD bytes_transfered, | |
| 229 DWORD error); | |
| 230 | |
| 231 private: | |
| 232 enum { | |
| 233 MASTER_INITIAL = 0, | |
| 234 MASTER_CONNECT, | |
| 235 MASTER_GET_ENTRY, | |
| 236 MASTER_GET_NEXT_ENTRY, | |
| 237 MASTER_GET_KEY, | |
| 238 MASTER_GET_USE_TIMES, | |
| 239 MASTER_GET_DATA_SIZE, | |
| 240 MASTER_READ_DATA, | |
| 241 MASTER_END | |
| 242 }; | |
| 243 | |
| 244 void SendGetPrevEntry(); | |
| 245 void DoGetEntry(); | |
| 246 void DoGetKey(int bytes_read); | |
| 247 void DoCreateEntryComplete(int result); | |
| 248 void DoGetUseTimes(); | |
| 249 void SendGetDataSize(); | |
| 250 void DoGetDataSize(); | |
| 251 void CloseEntry(); | |
| 252 void SendReadData(); | |
| 253 void DoReadData(int bytes_read); | |
| 254 void DoReadDataComplete(int ret); | |
| 255 void SendQuit(); | |
| 256 void DoEnd(); | |
| 257 void Fail(); | |
| 258 | |
| 259 base::Time last_used_; | |
| 260 base::Time last_modified_; | |
| 261 int64 remote_entry_; | |
| 262 int stream_; | |
| 263 int bytes_remaining_; | |
| 264 int offset_; | |
| 265 int copied_entries_; | |
| 266 int read_size_; | |
| 267 scoped_ptr<disk_cache::Backend> cache_; | |
| 268 CacheDumpWriter* writer_; | |
| 269 const base::FilePath path_; | |
| 270 }; | |
| 271 | |
| 272 void MasterSM::OnIOCompleted(base::MessageLoopForIO::IOContext* context, | |
| 273 DWORD bytes_transfered, | |
| 274 DWORD error) { | |
| 275 pending_count_--; | |
| 276 if (context == &out_context_) { | |
| 277 if (!error) | |
| 278 return; | |
| 279 return Fail(); | |
| 280 } | |
| 281 | |
| 282 int bytes_read = static_cast<int>(bytes_transfered); | |
| 283 if (bytes_read < sizeof(Message) && state_ != MASTER_END && | |
| 284 state_ != MASTER_CONNECT) { | |
| 285 printf("Communication breakdown\n"); | |
| 286 return Fail(); | |
| 287 } | |
| 288 | |
| 289 switch (state_) { | |
| 290 case MASTER_CONNECT: | |
| 291 SendGetPrevEntry(); | |
| 292 break; | |
| 293 case MASTER_GET_ENTRY: | |
| 294 DoGetEntry(); | |
| 295 break; | |
| 296 case MASTER_GET_KEY: | |
| 297 DoGetKey(bytes_read); | |
| 298 break; | |
| 299 case MASTER_GET_USE_TIMES: | |
| 300 DoGetUseTimes(); | |
| 301 break; | |
| 302 case MASTER_GET_DATA_SIZE: | |
| 303 DoGetDataSize(); | |
| 304 break; | |
| 305 case MASTER_READ_DATA: | |
| 306 DoReadData(bytes_read); | |
| 307 break; | |
| 308 case MASTER_END: | |
| 309 if (!IsPending()) | |
| 310 DoEnd(); | |
| 311 break; | |
| 312 default: | |
| 313 NOTREACHED(); | |
| 314 break; | |
| 315 } | |
| 316 } | |
| 317 | |
| 318 bool MasterSM::DoInit() { | |
| 319 DEBUGMSG("Master DoInit\n"); | |
| 320 DCHECK(state_ == MASTER_INITIAL); | |
| 321 | |
| 322 scoped_ptr<disk_cache::Backend> cache; | |
| 323 net::TestCompletionCallback cb; | |
| 324 int rv = disk_cache::CreateCacheBackend(net::DISK_CACHE, | |
| 325 net::CACHE_BACKEND_DEFAULT, path_, 0, | |
| 326 false, | |
| 327 cache_thread_.message_loop_proxy(), | |
| 328 NULL, &cache, cb.callback()); | |
| 329 if (cb.GetResult(rv) != net::OK) { | |
| 330 printf("Unable to initialize new files\n"); | |
| 331 return false; | |
| 332 } | |
| 333 cache_ = cache.Pass(); | |
| 334 writer_ = new CacheDumper(cache_.get()); | |
| 335 | |
| 336 copied_entries_ = 0; | |
| 337 remote_entry_ = 0; | |
| 338 | |
| 339 if (ConnectChannel()) { | |
| 340 SendGetPrevEntry(); | |
| 341 // If we don't have pending operations we couldn't connect. | |
| 342 return IsPending(); | |
| 343 } | |
| 344 | |
| 345 state_ = MASTER_CONNECT; | |
| 346 return true; | |
| 347 } | |
| 348 | |
| 349 void MasterSM::SendGetPrevEntry() { | |
| 350 DEBUGMSG("Master SendGetPrevEntry\n"); | |
| 351 state_ = MASTER_GET_ENTRY; | |
| 352 Message msg; | |
| 353 msg.command = GET_PREV_ENTRY; | |
| 354 msg.long_arg1 = remote_entry_; | |
| 355 SendMsg(msg); | |
| 356 } | |
| 357 | |
| 358 void MasterSM::DoGetEntry() { | |
| 359 DEBUGMSG("Master DoGetEntry\n"); | |
| 360 DCHECK(state_ == MASTER_GET_ENTRY); | |
| 361 DCHECK(input_->msg.command == GET_PREV_ENTRY); | |
| 362 if (input_->msg.result != RESULT_OK) | |
| 363 return Fail(); | |
| 364 | |
| 365 if (!input_->msg.long_arg1) { | |
| 366 printf("Done: %d entries copied over.\n", copied_entries_); | |
| 367 return SendQuit(); | |
| 368 } | |
| 369 remote_entry_ = input_->msg.long_arg1; | |
| 370 state_ = MASTER_GET_KEY; | |
| 371 Message msg; | |
| 372 msg.command = GET_KEY; | |
| 373 msg.long_arg1 = remote_entry_; | |
| 374 SendMsg(msg); | |
| 375 } | |
| 376 | |
| 377 void MasterSM::DoGetKey(int bytes_read) { | |
| 378 DEBUGMSG("Master DoGetKey\n"); | |
| 379 DCHECK(state_ == MASTER_GET_KEY); | |
| 380 DCHECK(input_->msg.command == GET_KEY); | |
| 381 if (input_->msg.result == RESULT_NAME_OVERFLOW) { | |
| 382 // The key is too long. Just move on. | |
| 383 printf("Skipping entry (name too long)\n"); | |
| 384 return SendGetPrevEntry(); | |
| 385 } | |
| 386 | |
| 387 if (input_->msg.result != RESULT_OK) | |
| 388 return Fail(); | |
| 389 | |
| 390 std::string key(input_->buffer); | |
| 391 DCHECK(key.size() == static_cast<size_t>(input_->msg.buffer_bytes - 1)); | |
| 392 | |
| 393 int rv = writer_->CreateEntry( | |
| 394 key, reinterpret_cast<disk_cache::Entry**>(&entry_), | |
| 395 base::Bind(&MasterSM::DoCreateEntryComplete, base::Unretained(this))); | |
| 396 | |
| 397 if (rv != net::ERR_IO_PENDING) | |
| 398 DoCreateEntryComplete(rv); | |
| 399 } | |
| 400 | |
| 401 void MasterSM::DoCreateEntryComplete(int result) { | |
| 402 std::string key(input_->buffer); | |
| 403 if (result != net::OK) { | |
| 404 printf("Skipping entry \"%s\": %d\n", key.c_str(), GetLastError()); | |
| 405 return SendGetPrevEntry(); | |
| 406 } | |
| 407 | |
| 408 if (key.size() >= 64) { | |
| 409 key[60] = '.'; | |
| 410 key[61] = '.'; | |
| 411 key[62] = '.'; | |
| 412 key[63] = '\0'; | |
| 413 } | |
| 414 DEBUGMSG("Entry \"%s\" created\n", key.c_str()); | |
| 415 state_ = MASTER_GET_USE_TIMES; | |
| 416 Message msg; | |
| 417 msg.command = GET_USE_TIMES; | |
| 418 msg.long_arg1 = remote_entry_; | |
| 419 SendMsg(msg); | |
| 420 } | |
| 421 | |
| 422 void MasterSM::DoGetUseTimes() { | |
| 423 DEBUGMSG("Master DoGetUseTimes\n"); | |
| 424 DCHECK(state_ == MASTER_GET_USE_TIMES); | |
| 425 DCHECK(input_->msg.command == GET_USE_TIMES); | |
| 426 if (input_->msg.result != RESULT_OK) | |
| 427 return Fail(); | |
| 428 | |
| 429 last_used_ = base::Time::FromInternalValue(input_->msg.long_arg2); | |
| 430 last_modified_ = base::Time::FromInternalValue(input_->msg.long_arg3); | |
| 431 stream_ = 0; | |
| 432 SendGetDataSize(); | |
| 433 } | |
| 434 | |
| 435 void MasterSM::SendGetDataSize() { | |
| 436 DEBUGMSG("Master SendGetDataSize (%d)\n", stream_); | |
| 437 state_ = MASTER_GET_DATA_SIZE; | |
| 438 Message msg; | |
| 439 msg.command = GET_DATA_SIZE; | |
| 440 msg.arg1 = stream_; | |
| 441 msg.long_arg1 = remote_entry_; | |
| 442 SendMsg(msg); | |
| 443 } | |
| 444 | |
| 445 void MasterSM::DoGetDataSize() { | |
| 446 DEBUGMSG("Master DoGetDataSize: %d\n", input_->msg.arg2); | |
| 447 DCHECK(state_ == MASTER_GET_DATA_SIZE); | |
| 448 DCHECK(input_->msg.command == GET_DATA_SIZE); | |
| 449 if (input_->msg.result == RESULT_INVALID_PARAMETER) | |
| 450 // No more streams, move to the next entry. | |
| 451 return CloseEntry(); | |
| 452 | |
| 453 if (input_->msg.result != RESULT_OK) | |
| 454 return Fail(); | |
| 455 | |
| 456 bytes_remaining_ = input_->msg.arg2; | |
| 457 offset_ = 0; | |
| 458 SendReadData(); | |
| 459 } | |
| 460 | |
| 461 void MasterSM::CloseEntry() { | |
| 462 DEBUGMSG("Master CloseEntry\n"); | |
| 463 printf("%c\r", copied_entries_ % 2 ? 'x' : '+'); | |
| 464 writer_->CloseEntry(entry_, last_used_, last_modified_); | |
| 465 entry_ = NULL; | |
| 466 copied_entries_++; | |
| 467 SendGetPrevEntry(); | |
| 468 } | |
| 469 | |
| 470 void MasterSM::SendReadData() { | |
| 471 int read_size = std::min(bytes_remaining_, kBufferSize); | |
| 472 DEBUGMSG("Master SendReadData (%d): %d bytes at %d\n", stream_, read_size, | |
| 473 offset_); | |
| 474 if (bytes_remaining_ <= 0) { | |
| 475 stream_++; | |
| 476 if (stream_ >= kNumStreams) | |
| 477 return CloseEntry(); | |
| 478 return SendGetDataSize(); | |
| 479 } | |
| 480 | |
| 481 state_ = MASTER_READ_DATA; | |
| 482 Message msg; | |
| 483 msg.command = READ_DATA; | |
| 484 msg.arg1 = stream_; | |
| 485 msg.arg2 = read_size; | |
| 486 msg.arg3 = offset_; | |
| 487 msg.long_arg1 = remote_entry_; | |
| 488 SendMsg(msg); | |
| 489 } | |
| 490 | |
| 491 void MasterSM::DoReadData(int bytes_read) { | |
| 492 DEBUGMSG("Master DoReadData: %d bytes\n", input_->msg.buffer_bytes); | |
| 493 DCHECK(state_ == MASTER_READ_DATA); | |
| 494 DCHECK(input_->msg.command == READ_DATA); | |
| 495 if (input_->msg.result != RESULT_OK) | |
| 496 return Fail(); | |
| 497 | |
| 498 int read_size = input_->msg.buffer_bytes; | |
| 499 if (!read_size) { | |
| 500 printf("Read failed, entry \"%s\" truncated!\n", entry_->GetKey().c_str()); | |
| 501 bytes_remaining_ = 0; | |
| 502 return SendReadData(); | |
| 503 } | |
| 504 | |
| 505 scoped_refptr<net::WrappedIOBuffer> buf = | |
| 506 new net::WrappedIOBuffer(input_->buffer); | |
| 507 int rv = writer_->WriteEntry( | |
| 508 entry_, stream_, offset_, buf, read_size, | |
| 509 base::Bind(&MasterSM::DoReadDataComplete, base::Unretained(this))); | |
| 510 if (rv == net::ERR_IO_PENDING) { | |
| 511 // We'll continue in DoReadDataComplete. | |
| 512 read_size_ = read_size; | |
| 513 return; | |
| 514 } | |
| 515 | |
| 516 if (rv <= 0) | |
| 517 return Fail(); | |
| 518 | |
| 519 offset_ += read_size; | |
| 520 bytes_remaining_ -= read_size; | |
| 521 // Read some more. | |
| 522 SendReadData(); | |
| 523 } | |
| 524 | |
| 525 void MasterSM::DoReadDataComplete(int ret) { | |
| 526 if (ret != read_size_) | |
| 527 return Fail(); | |
| 528 | |
| 529 offset_ += ret; | |
| 530 bytes_remaining_ -= ret; | |
| 531 // Read some more. | |
| 532 SendReadData(); | |
| 533 } | |
| 534 | |
| 535 void MasterSM::SendQuit() { | |
| 536 DEBUGMSG("Master SendQuit\n"); | |
| 537 state_ = MASTER_END; | |
| 538 Message msg; | |
| 539 msg.command = QUIT; | |
| 540 SendMsg(msg); | |
| 541 if (!IsPending()) | |
| 542 DoEnd(); | |
| 543 } | |
| 544 | |
| 545 void MasterSM::DoEnd() { | |
| 546 DEBUGMSG("Master DoEnd\n"); | |
| 547 base::MessageLoop::current()->PostTask(FROM_HERE, | |
| 548 base::MessageLoop::QuitClosure()); | |
| 549 } | |
| 550 | |
| 551 void MasterSM::Fail() { | |
| 552 DEBUGMSG("Master Fail\n"); | |
| 553 printf("Unexpected failure\n"); | |
| 554 SendQuit(); | |
| 555 } | |
| 556 | |
| 557 // ----------------------------------------------------------------------- | |
| 558 | |
| 559 class SlaveSM : public BaseSM { | |
| 560 public: | |
| 561 SlaveSM(const base::FilePath& path, HANDLE channel); | |
| 562 virtual ~SlaveSM(); | |
| 563 | |
| 564 bool DoInit(); | |
| 565 virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context, | |
| 566 DWORD bytes_transfered, | |
| 567 DWORD error); | |
| 568 | |
| 569 private: | |
| 570 enum { | |
| 571 SLAVE_INITIAL = 0, | |
| 572 SLAVE_WAITING, | |
| 573 SLAVE_END | |
| 574 }; | |
| 575 | |
| 576 void DoGetNextEntry(); | |
| 577 void DoGetPrevEntry(); | |
| 578 int32 GetEntryFromList(); | |
| 579 void DoGetEntryComplete(int result); | |
| 580 void DoCloseEntry(); | |
| 581 void DoGetKey(); | |
| 582 void DoGetUseTimes(); | |
| 583 void DoGetDataSize(); | |
| 584 void DoReadData(); | |
| 585 void DoReadDataComplete(int ret); | |
| 586 void DoEnd(); | |
| 587 void Fail(); | |
| 588 | |
| 589 void* iterator_; | |
| 590 Message msg_; // Used for DoReadDataComplete and DoGetEntryComplete. | |
| 591 | |
| 592 scoped_ptr<disk_cache::BackendImpl> cache_; | |
| 593 }; | |
| 594 | |
| 595 SlaveSM::SlaveSM(const base::FilePath& path, HANDLE channel) | |
| 596 : BaseSM(channel), iterator_(NULL) { | |
| 597 scoped_ptr<disk_cache::Backend> cache; | |
| 598 net::TestCompletionCallback cb; | |
| 599 int rv = disk_cache::CreateCacheBackend(net::DISK_CACHE, | |
| 600 net::CACHE_BACKEND_BLOCKFILE, path, 0, | |
| 601 false, | |
| 602 cache_thread_.message_loop_proxy(), | |
| 603 NULL, &cache, cb.callback()); | |
| 604 if (cb.GetResult(rv) != net::OK) { | |
| 605 printf("Unable to open cache files\n"); | |
| 606 return; | |
| 607 } | |
| 608 cache_.reset(reinterpret_cast<disk_cache::BackendImpl*>(cache.release())); | |
| 609 cache_->SetUpgradeMode(); | |
| 610 } | |
| 611 | |
| 612 SlaveSM::~SlaveSM() { | |
| 613 if (iterator_) | |
| 614 cache_->EndEnumeration(&iterator_); | |
| 615 } | |
| 616 | |
| 617 void SlaveSM::OnIOCompleted(base::MessageLoopForIO::IOContext* context, | |
| 618 DWORD bytes_transfered, | |
| 619 DWORD error) { | |
| 620 pending_count_--; | |
| 621 if (state_ == SLAVE_END) { | |
| 622 if (IsPending()) | |
| 623 return; | |
| 624 return DoEnd(); | |
| 625 } | |
| 626 | |
| 627 if (context == &out_context_) { | |
| 628 if (!error) | |
| 629 return; | |
| 630 return Fail(); | |
| 631 } | |
| 632 | |
| 633 int bytes_read = static_cast<int>(bytes_transfered); | |
| 634 if (bytes_read < sizeof(Message)) { | |
| 635 printf("Communication breakdown\n"); | |
| 636 return Fail(); | |
| 637 } | |
| 638 DCHECK(state_ == SLAVE_WAITING); | |
| 639 | |
| 640 switch (input_->msg.command) { | |
| 641 case GET_NEXT_ENTRY: | |
| 642 DoGetNextEntry(); | |
| 643 break; | |
| 644 case GET_PREV_ENTRY: | |
| 645 DoGetPrevEntry(); | |
| 646 break; | |
| 647 case CLOSE_ENTRY: | |
| 648 DoCloseEntry(); | |
| 649 break; | |
| 650 case GET_KEY: | |
| 651 DoGetKey(); | |
| 652 break; | |
| 653 case GET_USE_TIMES: | |
| 654 DoGetUseTimes(); | |
| 655 break; | |
| 656 case GET_DATA_SIZE: | |
| 657 DoGetDataSize(); | |
| 658 break; | |
| 659 case READ_DATA: | |
| 660 DoReadData(); | |
| 661 break; | |
| 662 case QUIT: | |
| 663 DoEnd(); | |
| 664 break; | |
| 665 default: | |
| 666 NOTREACHED(); | |
| 667 break; | |
| 668 } | |
| 669 } | |
| 670 | |
| 671 bool SlaveSM::DoInit() { | |
| 672 DEBUGMSG("\t\t\tSlave DoInit\n"); | |
| 673 DCHECK(state_ == SLAVE_INITIAL); | |
| 674 state_ = SLAVE_WAITING; | |
| 675 if (!cache_.get()) | |
| 676 return false; | |
| 677 | |
| 678 return ReceiveMsg(); | |
| 679 } | |
| 680 | |
| 681 void SlaveSM::DoGetNextEntry() { | |
| 682 DEBUGMSG("\t\t\tSlave DoGetNextEntry\n"); | |
| 683 Message msg; | |
| 684 msg.command = GET_NEXT_ENTRY; | |
| 685 | |
| 686 if (input_->msg.arg1) { | |
| 687 // We only support one list. | |
| 688 msg.result = RESULT_UNKNOWN_COMMAND; | |
| 689 } else { | |
| 690 msg.result = GetEntryFromList(); | |
| 691 msg.long_arg1 = reinterpret_cast<int64>(entry_); | |
| 692 } | |
| 693 SendMsg(msg); | |
| 694 } | |
| 695 | |
| 696 void SlaveSM::DoGetPrevEntry() { | |
| 697 DEBUGMSG("\t\t\tSlave DoGetPrevEntry\n"); | |
| 698 Message msg; | |
| 699 msg.command = GET_PREV_ENTRY; | |
| 700 | |
| 701 if (input_->msg.arg1) { | |
| 702 // We only support one list. | |
| 703 msg.result = RESULT_UNKNOWN_COMMAND; | |
| 704 } else { | |
| 705 msg.result = GetEntryFromList(); | |
| 706 if (msg.result == RESULT_PENDING) { | |
| 707 // We are not done yet. | |
| 708 msg_ = msg; | |
| 709 return; | |
| 710 } | |
| 711 msg.long_arg1 = reinterpret_cast<int64>(entry_); | |
| 712 } | |
| 713 SendMsg(msg); | |
| 714 } | |
| 715 | |
| 716 // Move to the next or previous entry on the list. | |
| 717 int32 SlaveSM::GetEntryFromList() { | |
| 718 DEBUGMSG("\t\t\tSlave GetEntryFromList\n"); | |
| 719 if (input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) | |
| 720 return RESULT_INVALID_PARAMETER; | |
| 721 | |
| 722 // We know that the current iteration is valid. | |
| 723 if (entry_) | |
| 724 entry_->Close(); | |
| 725 | |
| 726 int rv; | |
| 727 if (input_->msg.command == GET_NEXT_ENTRY) { | |
| 728 rv = cache_->OpenNextEntry( | |
| 729 &iterator_, reinterpret_cast<disk_cache::Entry**>(&entry_), | |
| 730 base::Bind(&SlaveSM::DoGetEntryComplete, base::Unretained(this))); | |
| 731 } else { | |
| 732 DCHECK(input_->msg.command == GET_PREV_ENTRY); | |
| 733 rv = cache_->OpenPrevEntry(&iterator_, | |
| 734 reinterpret_cast<disk_cache::Entry**>(&entry_), | |
| 735 base::Bind(&SlaveSM::DoGetEntryComplete, | |
| 736 base::Unretained(this))); | |
| 737 } | |
| 738 DCHECK_EQ(net::ERR_IO_PENDING, rv); | |
| 739 return RESULT_PENDING; | |
| 740 } | |
| 741 | |
| 742 void SlaveSM::DoGetEntryComplete(int result) { | |
| 743 DEBUGMSG("\t\t\tSlave DoGetEntryComplete\n"); | |
| 744 if (result != net::OK) { | |
| 745 entry_ = NULL; | |
| 746 DEBUGMSG("\t\t\tSlave end of list\n"); | |
| 747 } | |
| 748 | |
| 749 msg_.result = RESULT_OK; | |
| 750 msg_.long_arg1 = reinterpret_cast<int64>(entry_); | |
| 751 SendMsg(msg_); | |
| 752 } | |
| 753 | |
| 754 void SlaveSM::DoCloseEntry() { | |
| 755 DEBUGMSG("\t\t\tSlave DoCloseEntry\n"); | |
| 756 Message msg; | |
| 757 msg.command = GET_KEY; | |
| 758 | |
| 759 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) { | |
| 760 msg.result = RESULT_INVALID_PARAMETER; | |
| 761 } else { | |
| 762 entry_->Close(); | |
| 763 entry_ = NULL; | |
| 764 cache_->EndEnumeration(&iterator_); | |
| 765 msg.result = RESULT_OK; | |
| 766 } | |
| 767 SendMsg(msg); | |
| 768 } | |
| 769 | |
| 770 void SlaveSM::DoGetKey() { | |
| 771 DEBUGMSG("\t\t\tSlave DoGetKey\n"); | |
| 772 Message msg; | |
| 773 msg.command = GET_KEY; | |
| 774 | |
| 775 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) { | |
| 776 msg.result = RESULT_INVALID_PARAMETER; | |
| 777 } else { | |
| 778 std::string key = entry_->GetKey(); | |
| 779 msg.buffer_bytes = std::min(key.size() + 1, | |
| 780 static_cast<size_t>(kBufferSize)); | |
| 781 memcpy(output_->buffer, key.c_str(), msg.buffer_bytes); | |
| 782 if (msg.buffer_bytes != static_cast<int32>(key.size() + 1)) { | |
| 783 // We don't support moving this entry. Just tell the master. | |
| 784 msg.result = RESULT_NAME_OVERFLOW; | |
| 785 } else { | |
| 786 msg.result = RESULT_OK; | |
| 787 } | |
| 788 } | |
| 789 SendMsg(msg); | |
| 790 } | |
| 791 | |
| 792 void SlaveSM::DoGetUseTimes() { | |
| 793 DEBUGMSG("\t\t\tSlave DoGetUseTimes\n"); | |
| 794 Message msg; | |
| 795 msg.command = GET_USE_TIMES; | |
| 796 | |
| 797 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) { | |
| 798 msg.result = RESULT_INVALID_PARAMETER; | |
| 799 } else { | |
| 800 msg.long_arg2 = entry_->GetLastUsed().ToInternalValue(); | |
| 801 msg.long_arg3 = entry_->GetLastModified().ToInternalValue(); | |
| 802 msg.result = RESULT_OK; | |
| 803 } | |
| 804 SendMsg(msg); | |
| 805 } | |
| 806 | |
| 807 void SlaveSM::DoGetDataSize() { | |
| 808 DEBUGMSG("\t\t\tSlave DoGetDataSize\n"); | |
| 809 Message msg; | |
| 810 msg.command = GET_DATA_SIZE; | |
| 811 | |
| 812 int stream = input_->msg.arg1; | |
| 813 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) || | |
| 814 stream < 0 || stream >= kNumStreams) { | |
| 815 msg.result = RESULT_INVALID_PARAMETER; | |
| 816 } else { | |
| 817 msg.arg1 = stream; | |
| 818 msg.arg2 = entry_->GetDataSize(stream); | |
| 819 msg.result = RESULT_OK; | |
| 820 } | |
| 821 SendMsg(msg); | |
| 822 } | |
| 823 | |
| 824 void SlaveSM::DoReadData() { | |
| 825 DEBUGMSG("\t\t\tSlave DoReadData\n"); | |
| 826 Message msg; | |
| 827 msg.command = READ_DATA; | |
| 828 | |
| 829 int stream = input_->msg.arg1; | |
| 830 int size = input_->msg.arg2; | |
| 831 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) || | |
| 832 stream < 0 || stream > 1 || size > kBufferSize) { | |
| 833 msg.result = RESULT_INVALID_PARAMETER; | |
| 834 } else { | |
| 835 scoped_refptr<net::WrappedIOBuffer> buf = | |
| 836 new net::WrappedIOBuffer(output_->buffer); | |
| 837 int ret = entry_->ReadData(stream, input_->msg.arg3, buf, size, | |
| 838 base::Bind(&SlaveSM::DoReadDataComplete, | |
| 839 base::Unretained(this))); | |
| 840 if (ret == net::ERR_IO_PENDING) { | |
| 841 // Save the message so we can continue were we left. | |
| 842 msg_ = msg; | |
| 843 return; | |
| 844 } | |
| 845 | |
| 846 msg.buffer_bytes = (ret < 0) ? 0 : ret; | |
| 847 msg.result = RESULT_OK; | |
| 848 } | |
| 849 SendMsg(msg); | |
| 850 } | |
| 851 | |
| 852 void SlaveSM::DoReadDataComplete(int ret) { | |
| 853 DEBUGMSG("\t\t\tSlave DoReadDataComplete\n"); | |
| 854 DCHECK_EQ(READ_DATA, msg_.command); | |
| 855 msg_.buffer_bytes = (ret < 0) ? 0 : ret; | |
| 856 msg_.result = RESULT_OK; | |
| 857 SendMsg(msg_); | |
| 858 } | |
| 859 | |
| 860 void SlaveSM::DoEnd() { | |
| 861 DEBUGMSG("\t\t\tSlave DoEnd\n"); | |
| 862 base::MessageLoop::current()->PostTask(FROM_HERE, | |
| 863 base::MessageLoop::QuitClosure()); | |
| 864 } | |
| 865 | |
| 866 void SlaveSM::Fail() { | |
| 867 DEBUGMSG("\t\t\tSlave Fail\n"); | |
| 868 printf("Unexpected failure\n"); | |
| 869 state_ = SLAVE_END; | |
| 870 if (IsPending()) { | |
| 871 CancelIo(channel_); | |
| 872 } else { | |
| 873 DoEnd(); | |
| 874 } | |
| 875 } | |
| 876 | |
| 877 } // namespace. | |
| 878 | |
| 879 // ----------------------------------------------------------------------- | |
| 880 | |
| 881 HANDLE CreateServer(base::string16* pipe_number) { | |
| 882 base::string16 pipe_name(kPipePrefix); | |
| 883 srand(static_cast<int>(base::Time::Now().ToInternalValue())); | |
| 884 *pipe_number = base::IntToString16(rand()); | |
| 885 pipe_name.append(*pipe_number); | |
| 886 | |
| 887 DWORD mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | | |
| 888 FILE_FLAG_OVERLAPPED; | |
| 889 | |
| 890 return CreateNamedPipe(pipe_name.c_str(), mode, 0, 1, kChannelSize, | |
| 891 kChannelSize, 0, NULL); | |
| 892 } | |
| 893 | |
| 894 // This is the controller process for an upgrade operation. | |
| 895 int UpgradeCache(const base::FilePath& output_path, HANDLE pipe) { | |
| 896 base::MessageLoopForIO loop; | |
| 897 | |
| 898 MasterSM master(output_path, pipe); | |
| 899 if (!master.DoInit()) { | |
| 900 printf("Unable to talk with the helper\n"); | |
| 901 return -1; | |
| 902 } | |
| 903 | |
| 904 loop.Run(); | |
| 905 return 0; | |
| 906 } | |
| 907 | |
| 908 // This process will only execute commands from the controller. | |
| 909 int RunSlave(const base::FilePath& input_path, | |
| 910 const base::string16& pipe_number) { | |
| 911 base::MessageLoopForIO loop; | |
| 912 | |
| 913 base::win::ScopedHandle pipe(OpenServer(pipe_number)); | |
| 914 if (!pipe.IsValid()) { | |
| 915 printf("Unable to open the server pipe\n"); | |
| 916 return -1; | |
| 917 } | |
| 918 | |
| 919 SlaveSM slave(input_path, pipe); | |
| 920 if (!slave.DoInit()) { | |
| 921 printf("Unable to talk with the main process\n"); | |
| 922 return -1; | |
| 923 } | |
| 924 | |
| 925 loop.Run(); | |
| 926 return 0; | |
| 927 } | |
| OLD | NEW |