Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / net / tools / dump_cache / upgrade_win.cc
blobdfb9e5c32fc5651094e35aba56f07a7b77b06644
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.
5 #include "net/tools/dump_cache/upgrade_win.h"
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/blockfile/backend_impl.h"
21 #include "net/disk_cache/blockfile/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"
28 namespace {
30 const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\dump_cache_";
31 const int kChannelSize = 64 * 1024;
32 const int kNumStreams = 4;
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
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);
49 // This is the basic message to use between the two processes. It is intended
50 // to transmit a single action (like "get the key name for entry xx"), with up
51 // to 5 32-bit arguments and 4 64-bit arguments. After this structure, the rest
52 // of the message has |buffer_bytes| of length with the actual data.
53 struct Message {
54 int32 command;
55 int32 result;
56 int32 buffer_bytes;
57 int32 arg1;
58 int32 arg2;
59 int32 arg3;
60 int32 arg4;
61 int32 arg5;
62 int64 long_arg1;
63 int64 long_arg2;
64 int64 long_arg3;
65 int64 long_arg4;
66 Message() {
67 memset(this, 0, sizeof(*this));
69 Message& operator= (const Message& other) {
70 memcpy(this, &other, sizeof(*this));
71 return *this;
75 const int kBufferSize = kChannelSize - sizeof(Message);
76 struct IoBuffer {
77 Message msg;
78 char buffer[kBufferSize];
80 COMPILE_ASSERT(sizeof(IoBuffer) == kChannelSize, invalid_io_buffer);
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
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.
118 // -----------------------------------------------------------------------
120 class BaseSM : public base::MessageLoopForIO::IOHandler {
121 public:
122 explicit BaseSM(HANDLE channel);
123 virtual ~BaseSM();
125 protected:
126 bool SendMsg(const Message& msg);
127 bool ReceiveMsg();
128 bool ConnectChannel();
129 bool IsPending();
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_;
143 DISALLOW_COPY_AND_ASSIGN(BaseSM);
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());
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)));
163 BaseSM::~BaseSM() {
164 if (entry_)
165 entry_->Close();
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;
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;
181 pending_count_++;
182 return true;
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;
192 pending_count_++;
193 return true;
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;
206 pending_count_++;
207 return false;
210 bool BaseSM::IsPending() {
211 return pending_count_ != 0;
214 // -----------------------------------------------------------------------
216 class MasterSM : public BaseSM {
217 public:
218 MasterSM(const base::FilePath& path, HANDLE channel)
219 : BaseSM(channel),
220 path_(path) {
222 virtual ~MasterSM() {
223 delete writer_;
226 bool DoInit();
227 virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
228 DWORD bytes_transfered,
229 DWORD error);
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
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();
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_;
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();
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();
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;
318 bool MasterSM::DoInit() {
319 DEBUGMSG("Master DoInit\n");
320 DCHECK(state_ == MASTER_INITIAL);
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;
333 cache_ = cache.Pass();
334 writer_ = new CacheDumper(cache_.get());
336 copied_entries_ = 0;
337 remote_entry_ = 0;
339 if (ConnectChannel()) {
340 SendGetPrevEntry();
341 // If we don't have pending operations we couldn't connect.
342 return IsPending();
345 state_ = MASTER_CONNECT;
346 return true;
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);
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();
365 if (!input_->msg.long_arg1) {
366 printf("Done: %d entries copied over.\n", copied_entries_);
367 return SendQuit();
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);
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();
387 if (input_->msg.result != RESULT_OK)
388 return Fail();
390 std::string key(input_->buffer);
391 DCHECK(key.size() == static_cast<size_t>(input_->msg.buffer_bytes - 1));
393 int rv = writer_->CreateEntry(
394 key, reinterpret_cast<disk_cache::Entry**>(&entry_),
395 base::Bind(&MasterSM::DoCreateEntryComplete, base::Unretained(this)));
397 if (rv != net::ERR_IO_PENDING)
398 DoCreateEntryComplete(rv);
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();
408 if (key.size() >= 64) {
409 key[60] = '.';
410 key[61] = '.';
411 key[62] = '.';
412 key[63] = '\0';
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);
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();
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();
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);
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();
453 if (input_->msg.result != RESULT_OK)
454 return Fail();
456 bytes_remaining_ = input_->msg.arg2;
457 offset_ = 0;
458 SendReadData();
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();
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();
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);
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();
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();
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;
516 if (rv <= 0)
517 return Fail();
519 offset_ += read_size;
520 bytes_remaining_ -= read_size;
521 // Read some more.
522 SendReadData();
525 void MasterSM::DoReadDataComplete(int ret) {
526 if (ret != read_size_)
527 return Fail();
529 offset_ += ret;
530 bytes_remaining_ -= ret;
531 // Read some more.
532 SendReadData();
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();
545 void MasterSM::DoEnd() {
546 DEBUGMSG("Master DoEnd\n");
547 base::MessageLoop::current()->PostTask(FROM_HERE,
548 base::MessageLoop::QuitClosure());
551 void MasterSM::Fail() {
552 DEBUGMSG("Master Fail\n");
553 printf("Unexpected failure\n");
554 SendQuit();
557 // -----------------------------------------------------------------------
559 class SlaveSM : public BaseSM {
560 public:
561 SlaveSM(const base::FilePath& path, HANDLE channel);
562 virtual ~SlaveSM();
564 bool DoInit();
565 virtual void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
566 DWORD bytes_transfered,
567 DWORD error);
569 private:
570 enum {
571 SLAVE_INITIAL = 0,
572 SLAVE_WAITING,
573 SLAVE_END
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();
589 void* iterator_;
590 Message msg_; // Used for DoReadDataComplete and DoGetEntryComplete.
592 scoped_ptr<disk_cache::BackendImpl> cache_;
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;
608 cache_.reset(reinterpret_cast<disk_cache::BackendImpl*>(cache.release()));
609 cache_->SetUpgradeMode();
612 SlaveSM::~SlaveSM() {
613 if (iterator_)
614 cache_->EndEnumeration(&iterator_);
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();
627 if (context == &out_context_) {
628 if (!error)
629 return;
630 return Fail();
633 int bytes_read = static_cast<int>(bytes_transfered);
634 if (bytes_read < sizeof(Message)) {
635 printf("Communication breakdown\n");
636 return Fail();
638 DCHECK(state_ == SLAVE_WAITING);
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;
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;
678 return ReceiveMsg();
681 void SlaveSM::DoGetNextEntry() {
682 DEBUGMSG("\t\t\tSlave DoGetNextEntry\n");
683 Message msg;
684 msg.command = GET_NEXT_ENTRY;
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_);
693 SendMsg(msg);
696 void SlaveSM::DoGetPrevEntry() {
697 DEBUGMSG("\t\t\tSlave DoGetPrevEntry\n");
698 Message msg;
699 msg.command = GET_PREV_ENTRY;
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;
711 msg.long_arg1 = reinterpret_cast<int64>(entry_);
713 SendMsg(msg);
716 // Move to the next or previous entry on the list.
717 int32 SlaveSM::GetEntryFromList() {
718 DEBUGMSG("\t\t\tSlave GetEntryFromList\n");
719 if (input_->msg.long_arg1 != reinterpret_cast<int64>(entry_))
720 return RESULT_INVALID_PARAMETER;
722 // We know that the current iteration is valid.
723 if (entry_)
724 entry_->Close();
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)));
738 DCHECK_EQ(net::ERR_IO_PENDING, rv);
739 return RESULT_PENDING;
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");
749 msg_.result = RESULT_OK;
750 msg_.long_arg1 = reinterpret_cast<int64>(entry_);
751 SendMsg(msg_);
754 void SlaveSM::DoCloseEntry() {
755 DEBUGMSG("\t\t\tSlave DoCloseEntry\n");
756 Message msg;
757 msg.command = GET_KEY;
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;
767 SendMsg(msg);
770 void SlaveSM::DoGetKey() {
771 DEBUGMSG("\t\t\tSlave DoGetKey\n");
772 Message msg;
773 msg.command = GET_KEY;
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;
789 SendMsg(msg);
792 void SlaveSM::DoGetUseTimes() {
793 DEBUGMSG("\t\t\tSlave DoGetUseTimes\n");
794 Message msg;
795 msg.command = GET_USE_TIMES;
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;
804 SendMsg(msg);
807 void SlaveSM::DoGetDataSize() {
808 DEBUGMSG("\t\t\tSlave DoGetDataSize\n");
809 Message msg;
810 msg.command = GET_DATA_SIZE;
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;
821 SendMsg(msg);
824 void SlaveSM::DoReadData() {
825 DEBUGMSG("\t\t\tSlave DoReadData\n");
826 Message msg;
827 msg.command = READ_DATA;
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;
846 msg.buffer_bytes = (ret < 0) ? 0 : ret;
847 msg.result = RESULT_OK;
849 SendMsg(msg);
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_);
860 void SlaveSM::DoEnd() {
861 DEBUGMSG("\t\t\tSlave DoEnd\n");
862 base::MessageLoop::current()->PostTask(FROM_HERE,
863 base::MessageLoop::QuitClosure());
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();
877 } // namespace.
879 // -----------------------------------------------------------------------
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);
887 DWORD mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE |
888 FILE_FLAG_OVERLAPPED;
890 return CreateNamedPipe(pipe_name.c_str(), mode, 0, 1, kChannelSize,
891 kChannelSize, 0, NULL);
894 // This is the controller process for an upgrade operation.
895 int UpgradeCache(const base::FilePath& output_path, HANDLE pipe) {
896 base::MessageLoopForIO loop;
898 MasterSM master(output_path, pipe);
899 if (!master.DoInit()) {
900 printf("Unable to talk with the helper\n");
901 return -1;
904 loop.Run();
905 return 0;
908 // This process will only execute commands from the controller.
909 int RunSlave(const base::FilePath& input_path,
910 const base::string16& pipe_number) {
911 base::MessageLoopForIO loop;
913 base::win::ScopedHandle pipe(OpenServer(pipe_number));
914 if (!pipe.IsValid()) {
915 printf("Unable to open the server pipe\n");
916 return -1;
919 SlaveSM slave(input_path, pipe);
920 if (!slave.DoInit()) {
921 printf("Unable to talk with the main process\n");
922 return -1;
925 loop.Run();
926 return 0;