• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
OpenServer(const std::wstring & pipe_number)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;
Message__anonc1dd2ab80111::Message57   Message() {
58     memset(this, 0, sizeof(*this));
59   }
operator =__anonc1dd2ab80111::Message60   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 
BaseSM(HANDLE channel)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 
~BaseSM()148 BaseSM::~BaseSM() {
149   if (entry_)
150     entry_->Close();
151 }
152 
SendMsg(const Message & msg)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 
ReceiveMsg()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 
ConnectChannel()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 
IsPending()195 bool BaseSM::IsPending() {
196   return pending_count_ != 0;
197 }
198 
199 // -----------------------------------------------------------------------
200 
201 class MasterSM : public BaseSM {
202  public:
MasterSM(const std::wstring & path,HANDLE channel,bool dump_to_disk)203    MasterSM(const std::wstring& path, HANDLE channel, bool dump_to_disk)
204       : BaseSM(channel), path_(path), dump_to_disk_(dump_to_disk) {
205   }
~MasterSM()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 
OnIOCompleted(MessageLoopForIO::IOContext * context,DWORD bytes_transfered,DWORD error)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 
DoInit()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 
SendGetPrevEntry()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 
DoGetEntry()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 
DoGetKey(int bytes_read)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 
DoGetUseTimes()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 
SendGetDataSize()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 
DoGetDataSize()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 
CloseEntry()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 
SendReadData()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 
DoReadData(int bytes_read)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 
SendQuit()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 
DoEnd()496 void MasterSM::DoEnd() {
497   DEBUGMSG("Master DoEnd\n");
498   MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
499 }
500 
Fail()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:
SlaveSM(const std::wstring & path,HANDLE channel)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 
~SlaveSM()549 SlaveSM::~SlaveSM() {
550   if (iterator_)
551     cache_->EndEnumeration(&iterator_);
552 }
553 
OnIOCompleted(MessageLoopForIO::IOContext * context,DWORD bytes_transfered,DWORD error)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 
DoInit()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 
DoGetNextEntry()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 
DoGetPrevEntry()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.
GetEntryFromList()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 
DoCloseEntry()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 
DoGetKey()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 
DoGetUseTimes()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 
DoGetDataSize()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 
DoReadData()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 
DoEnd()764 void SlaveSM::DoEnd() {
765   DEBUGMSG("\t\t\tSlave DoEnd\n");
766   MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
767 }
768 
Fail()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 
CreateServer(std::wstring * pipe_number)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.
CopyCache(const std::wstring & output_path,HANDLE pipe,bool copy_to_text)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.
RunSlave(const std::wstring & input_path,const std::wstring & pipe_number)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