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