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/backend_impl.h" 21 #include "net/disk_cache/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::MessageLoop loop(base::MessageLoop::TYPE_IO); 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::MessageLoop loop(base::MessageLoop::TYPE_IO); 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 } 928