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