• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
OpenServer(const std::wstring & pipe_number)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;
Message__anona64442140111::Message62   Message() {
63     memset(this, 0, sizeof(*this));
64   }
operator =__anona64442140111::Message65   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 
BaseSM(HANDLE channel)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 
~BaseSM()159 BaseSM::~BaseSM() {
160   if (entry_)
161     entry_->Close();
162 }
163 
SendMsg(const Message & msg)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 
ReceiveMsg()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 
ConnectChannel()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 
IsPending()206 bool BaseSM::IsPending() {
207   return pending_count_ != 0;
208 }
209 
210 // -----------------------------------------------------------------------
211 
212 class MasterSM : public BaseSM {
213  public:
MasterSM(const std::wstring & path,HANDLE channel,bool dump_to_disk)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   }
~MasterSM()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 
OnIOCompleted(MessageLoopForIO::IOContext * context,DWORD bytes_transfered,DWORD error)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 
DoInit()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 
SendGetPrevEntry()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 
DoGetEntry()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 
DoGetKey(int bytes_read)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 
DoCreateEntryComplete(int result)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 
DoGetUseTimes()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 
SendGetDataSize()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 
DoGetDataSize()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 
CloseEntry()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 
SendReadData()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 
DoReadData(int bytes_read)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 
DoReadDataComplete(int ret)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 
SendQuit()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 
DoEnd()550 void MasterSM::DoEnd() {
551   DEBUGMSG("Master DoEnd\n");
552   MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
553 }
554 
Fail()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 
SlaveSM(const std::wstring & path,HANDLE channel)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 
~SlaveSM()621 SlaveSM::~SlaveSM() {
622   if (iterator_)
623     cache_->EndEnumeration(&iterator_);
624 }
625 
OnIOCompleted(MessageLoopForIO::IOContext * context,DWORD bytes_transfered,DWORD error)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 
DoInit()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 
DoGetNextEntry()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 
DoGetPrevEntry()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.
GetEntryFromList()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 
DoGetEntryComplete(int result)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 
DoCloseEntry()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 
DoGetKey()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 
DoGetUseTimes()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 
DoGetDataSize()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 
DoReadData()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 
DoReadDataComplete(int ret)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 
DoEnd()866 void SlaveSM::DoEnd() {
867   DEBUGMSG("\t\t\tSlave DoEnd\n");
868   MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
869 }
870 
Fail()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 
CreateServer(std::wstring * pipe_number)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.
CopyCache(const std::wstring & output_path,HANDLE pipe,bool copy_to_text)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.
RunSlave(const std::wstring & input_path,const std::wstring & pipe_number)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