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