Home | History | Annotate | Download | only in dump_cache
      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