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