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