• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
OpenServer(const base::string16 & pipe_number)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;
Message__anon9ad2a54c0111::Message66   Message() {
67     memset(this, 0, sizeof(*this));
68   }
operator =__anon9ad2a54c0111::Message69   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 
BaseSM(HANDLE channel)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 
~BaseSM()163 BaseSM::~BaseSM() {
164   if (entry_)
165     entry_->Close();
166 }
167 
SendMsg(const Message & msg)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 
ReceiveMsg()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 
ConnectChannel()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 
IsPending()210 bool BaseSM::IsPending() {
211   return pending_count_ != 0;
212 }
213 
214 // -----------------------------------------------------------------------
215 
216 class MasterSM : public BaseSM {
217  public:
MasterSM(const base::FilePath & path,HANDLE channel)218   MasterSM(const base::FilePath& path, HANDLE channel)
219       : BaseSM(channel),
220         path_(path) {
221   }
~MasterSM()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 
OnIOCompleted(base::MessageLoopForIO::IOContext * context,DWORD bytes_transfered,DWORD error)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 
DoInit()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 
SendGetPrevEntry()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 
DoGetEntry()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 
DoGetKey(int bytes_read)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 
DoCreateEntryComplete(int result)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 
DoGetUseTimes()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 
SendGetDataSize()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 
DoGetDataSize()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 
CloseEntry()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 
SendReadData()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 
DoReadData(int bytes_read)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 
DoReadDataComplete(int ret)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 
SendQuit()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 
DoEnd()545 void MasterSM::DoEnd() {
546   DEBUGMSG("Master DoEnd\n");
547   base::MessageLoop::current()->PostTask(FROM_HERE,
548                                          base::MessageLoop::QuitClosure());
549 }
550 
Fail()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 
SlaveSM(const base::FilePath & path,HANDLE channel)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 
~SlaveSM()612 SlaveSM::~SlaveSM() {
613   if (iterator_)
614     cache_->EndEnumeration(&iterator_);
615 }
616 
OnIOCompleted(base::MessageLoopForIO::IOContext * context,DWORD bytes_transfered,DWORD error)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 
DoInit()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 
DoGetNextEntry()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 
DoGetPrevEntry()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.
GetEntryFromList()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 
DoGetEntryComplete(int result)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 
DoCloseEntry()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 
DoGetKey()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 
DoGetUseTimes()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 
DoGetDataSize()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 
DoReadData()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 
DoReadDataComplete(int ret)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 
DoEnd()860 void SlaveSM::DoEnd() {
861   DEBUGMSG("\t\t\tSlave DoEnd\n");
862   base::MessageLoop::current()->PostTask(FROM_HERE,
863                                          base::MessageLoop::QuitClosure());
864 }
865 
Fail()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 
CreateServer(base::string16 * pipe_number)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.
UpgradeCache(const base::FilePath & output_path,HANDLE pipe)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.
RunSlave(const base::FilePath & input_path,const base::string16 & pipe_number)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