1 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/file_path.h"
6 #include "base/logging.h"
7 #include "base/message_loop.h"
8 #include "base/scoped_ptr.h"
9 #include "base/string_util.h"
10 #include "googleurl/src/gurl.h"
11 #include "net/base/io_buffer.h"
12 #include "net/disk_cache/backend_impl.h"
13 #include "net/disk_cache/entry_impl.h"
14 #include "net/http/http_cache.h"
15 #include "net/http/http_response_headers.h"
16 #include "net/http/http_response_info.h"
17 #include "net/tools/dump_cache/cache_dumper.h"
18
19 namespace {
20
21 const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\dump_cache_";
22 const int kChannelSize = 64 * 1024;
23 const int kNumStreams = 4;
24
25 // Simple macro to print out formatted debug messages. It is similar to a DLOG
26 // except that it doesn't include a header.
27 #ifdef NDEBUG
28 #define DEBUGMSG(...) {}
29 #else
30 #define DEBUGMSG(...) { printf(__VA_ARGS__); }
31 #endif
32
OpenServer(const std::wstring & pipe_number)33 HANDLE OpenServer(const std::wstring& pipe_number) {
34 std::wstring pipe_name(kPipePrefix);
35 pipe_name.append(pipe_number);
36 return CreateFile(pipe_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
37 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
38 }
39
40 // This is the basic message to use between the two processes. It is intended
41 // to transmit a single action (like "get the key name for entry xx"), with up
42 // to 5 32-bit arguments and 4 64-bit arguments. After this structure, the rest
43 // of the message has |buffer_bytes| of length with the actual data.
44 struct Message {
45 int32 command;
46 int32 result;
47 int32 buffer_bytes;
48 int32 arg1;
49 int32 arg2;
50 int32 arg3;
51 int32 arg4;
52 int32 arg5;
53 int64 long_arg1;
54 int64 long_arg2;
55 int64 long_arg3;
56 int64 long_arg4;
Message__anonc1dd2ab80111::Message57 Message() {
58 memset(this, 0, sizeof(*this));
59 }
operator =__anonc1dd2ab80111::Message60 Message& operator= (const Message& other) {
61 memcpy(this, &other, sizeof(*this));
62 return *this;
63 }
64 };
65
66 const int kBufferSize = kChannelSize - sizeof(Message);
67 struct IoBuffer {
68 Message msg;
69 char buffer[kBufferSize];
70 };
71 COMPILE_ASSERT(sizeof(IoBuffer) == kChannelSize, invalid_io_buffer);
72
73
74 // The list of commands.
75 // Currently, there is support for working ONLY with one entry at a time.
76 enum {
77 // Get the entry from list |arg1| that follows |long_arg1|.
78 // The result is placed on |long_arg1| (closes the previous one).
79 GET_NEXT_ENTRY = 1,
80 // Get the entry from list |arg1| that precedes |long_arg1|.
81 // The result is placed on |long_arg1| (closes the previous one).
82 GET_PREV_ENTRY,
83 // Closes the entry |long_arg1|.
84 CLOSE_ENTRY,
85 // Get the key of the entry |long_arg1|.
86 GET_KEY,
87 // Get last used (long_arg2) and last modified (long_arg3) times for the
88 // entry at |long_arg1|.
89 GET_USE_TIMES,
90 // Returns on |arg2| the data size in bytes if the stream |arg1| of entry at
91 // |long_arg1|.
92 GET_DATA_SIZE,
93 // Returns |arg2| bytes of the stream |arg1| for the entry at |long_arg1|,
94 // starting at offset |arg3|.
95 READ_DATA,
96 // End processing requests.
97 QUIT
98 };
99
100 // The list of return codes.
101 enum {
102 RESULT_OK = 0,
103 RESULT_UNKNOWN_COMMAND,
104 RESULT_INVALID_PARAMETER,
105 RESULT_NAME_OVERFLOW
106 };
107
108 // -----------------------------------------------------------------------
109
110 class BaseSM : public MessageLoopForIO::IOHandler {
111 public:
112 BaseSM(HANDLE channel);
113 virtual ~BaseSM();
114
115 protected:
116 bool SendMsg(const Message& msg);
117 bool ReceiveMsg();
118 bool ConnectChannel();
119 bool IsPending();
120
121 MessageLoopForIO::IOContext in_context_;
122 MessageLoopForIO::IOContext out_context_;
123 disk_cache::EntryImpl* entry_;
124 HANDLE channel_;
125 int state_;
126 int pending_count_;
127 scoped_array<char> in_buffer_;
128 scoped_array<char> out_buffer_;
129 IoBuffer* input_;
130 IoBuffer* output_;
131 DISALLOW_COPY_AND_ASSIGN(BaseSM);
132 };
133
BaseSM(HANDLE channel)134 BaseSM::BaseSM(HANDLE channel)
135 : entry_(NULL), channel_(channel), state_(0), pending_count_(0) {
136 in_buffer_.reset(new char[kChannelSize]);
137 out_buffer_.reset(new char[kChannelSize]);
138 input_ = reinterpret_cast<IoBuffer*>(in_buffer_.get());
139 output_ = reinterpret_cast<IoBuffer*>(out_buffer_.get());
140
141 memset(&in_context_, 0, sizeof(in_context_));
142 memset(&out_context_, 0, sizeof(out_context_));
143 in_context_.handler = this;
144 out_context_.handler = this;
145 MessageLoopForIO::current()->RegisterIOHandler(channel_, this);
146 }
147
~BaseSM()148 BaseSM::~BaseSM() {
149 if (entry_)
150 entry_->Close();
151 }
152
SendMsg(const Message & msg)153 bool BaseSM::SendMsg(const Message& msg) {
154 // Only one command will be in-flight at a time. Let's start the Read IO here
155 // when we know that it will be pending.
156 if (!ReceiveMsg())
157 return false;
158
159 output_->msg = msg;
160 DWORD written;
161 if (!WriteFile(channel_, output_, sizeof(msg) + msg.buffer_bytes, &written,
162 &out_context_.overlapped)) {
163 if (ERROR_IO_PENDING != GetLastError())
164 return false;
165 }
166 pending_count_++;
167 return true;
168 }
169
ReceiveMsg()170 bool BaseSM::ReceiveMsg() {
171 DWORD read;
172 if (!ReadFile(channel_, input_, kChannelSize, &read,
173 &in_context_.overlapped)) {
174 if (ERROR_IO_PENDING != GetLastError())
175 return false;
176 }
177 pending_count_++;
178 return true;
179 }
180
ConnectChannel()181 bool BaseSM::ConnectChannel() {
182 if (!ConnectNamedPipe(channel_, &in_context_.overlapped)) {
183 DWORD error = GetLastError();
184 if (ERROR_PIPE_CONNECTED == error)
185 return true;
186 // By returning true in case of a generic error, we allow the operation to
187 // fail while sending the first message.
188 if (ERROR_IO_PENDING != error)
189 return true;
190 }
191 pending_count_++;
192 return false;
193 }
194
IsPending()195 bool BaseSM::IsPending() {
196 return pending_count_ != 0;
197 }
198
199 // -----------------------------------------------------------------------
200
201 class MasterSM : public BaseSM {
202 public:
MasterSM(const std::wstring & path,HANDLE channel,bool dump_to_disk)203 MasterSM(const std::wstring& path, HANDLE channel, bool dump_to_disk)
204 : BaseSM(channel), path_(path), dump_to_disk_(dump_to_disk) {
205 }
~MasterSM()206 virtual ~MasterSM() {
207 delete writer_;
208 }
209
210 bool DoInit();
211 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
212 DWORD bytes_transfered, DWORD error);
213
214 private:
215 enum {
216 MASTER_INITIAL = 0,
217 MASTER_CONNECT,
218 MASTER_GET_ENTRY,
219 MASTER_GET_NEXT_ENTRY,
220 MASTER_GET_KEY,
221 MASTER_GET_USE_TIMES,
222 MASTER_GET_DATA_SIZE,
223 MASTER_READ_DATA,
224 MASTER_END
225 };
226
227 void SendGetPrevEntry();
228 void DoGetEntry();
229 void DoGetKey(int bytes_read);
230 void DoGetUseTimes();
231 void SendGetDataSize();
232 void DoGetDataSize();
233 void CloseEntry();
234 void SendReadData();
235 void DoReadData(int bytes_read);
236 void SendQuit();
237 void DoEnd();
238 void Fail();
239
240 base::Time last_used_;
241 base::Time last_modified_;
242 int64 remote_entry_;
243 int stream_;
244 int bytes_remaining_;
245 int offset_;
246 int copied_entries_;
247 scoped_ptr<disk_cache::BackendImpl> cache_;
248 CacheDumpWriter* writer_;
249 const std::wstring& path_;
250 bool dump_to_disk_;
251 };
252
OnIOCompleted(MessageLoopForIO::IOContext * context,DWORD bytes_transfered,DWORD error)253 void MasterSM::OnIOCompleted(MessageLoopForIO::IOContext* context,
254 DWORD bytes_transfered, DWORD error) {
255 pending_count_--;
256 if (context == &out_context_) {
257 if (!error)
258 return;
259 return Fail();
260 }
261
262 int bytes_read = static_cast<int>(bytes_transfered);
263 if (bytes_read < sizeof(Message) && state_ != MASTER_END &&
264 state_ != MASTER_CONNECT) {
265 printf("Communication breakdown\n");
266 return Fail();
267 }
268
269 switch (state_) {
270 case MASTER_CONNECT:
271 SendGetPrevEntry();
272 break;
273 case MASTER_GET_ENTRY:
274 DoGetEntry();
275 break;
276 case MASTER_GET_KEY:
277 DoGetKey(bytes_read);
278 break;
279 case MASTER_GET_USE_TIMES:
280 DoGetUseTimes();
281 break;
282 case MASTER_GET_DATA_SIZE:
283 DoGetDataSize();
284 break;
285 case MASTER_READ_DATA:
286 DoReadData(bytes_read);
287 break;
288 case MASTER_END:
289 if (!IsPending())
290 DoEnd();
291 break;
292 default:
293 NOTREACHED();
294 break;
295 }
296 }
297
DoInit()298 bool MasterSM::DoInit() {
299 DEBUGMSG("Master DoInit\n");
300 DCHECK(state_ == MASTER_INITIAL);
301
302 if (dump_to_disk_) {
303 writer_ = new DiskDumper(path_);
304 } else {
305 cache_.reset(new disk_cache::BackendImpl(FilePath::FromWStringHack(path_)));
306 if (!cache_->Init()) {
307 printf("Unable to initialize new files\n");
308 return false;
309 }
310 writer_ = new CacheDumper(cache_.get());
311 }
312 if (!writer_)
313 return false;
314
315 copied_entries_ = 0;
316 remote_entry_ = 0;
317
318 if (ConnectChannel()) {
319 SendGetPrevEntry();
320 // If we don't have pending operations we couldn't connect.
321 return IsPending();
322 }
323
324 state_ = MASTER_CONNECT;
325 return true;
326 }
327
SendGetPrevEntry()328 void MasterSM::SendGetPrevEntry() {
329 DEBUGMSG("Master SendGetPrevEntry\n");
330 state_ = MASTER_GET_ENTRY;
331 Message msg;
332 msg.command = GET_PREV_ENTRY;
333 msg.long_arg1 = remote_entry_;
334 SendMsg(msg);
335 }
336
DoGetEntry()337 void MasterSM::DoGetEntry() {
338 DEBUGMSG("Master DoGetEntry\n");
339 DCHECK(state_ == MASTER_GET_ENTRY);
340 DCHECK(input_->msg.command == GET_PREV_ENTRY);
341 if (input_->msg.result != RESULT_OK)
342 return Fail();
343
344 if (!input_->msg.long_arg1) {
345 printf("Done: %d entries copied over.\n", copied_entries_);
346 return SendQuit();
347 }
348 remote_entry_ = input_->msg.long_arg1;
349 state_ = MASTER_GET_KEY;
350 Message msg;
351 msg.command = GET_KEY;
352 msg.long_arg1 = remote_entry_;
353 SendMsg(msg);
354 }
355
DoGetKey(int bytes_read)356 void MasterSM::DoGetKey(int bytes_read) {
357 DEBUGMSG("Master DoGetKey\n");
358 DCHECK(state_ == MASTER_GET_KEY);
359 DCHECK(input_->msg.command == GET_KEY);
360 if (input_->msg.result == RESULT_NAME_OVERFLOW) {
361 // The key is too long. Just move on.
362 printf("Skipping entry (name too long)\n");
363 return SendGetPrevEntry();
364 }
365
366 if (input_->msg.result != RESULT_OK)
367 return Fail();
368
369 std::string key(input_->buffer);
370 DCHECK(key.size() == input_->msg.buffer_bytes - 1);
371
372 if (!writer_->CreateEntry(key,
373 reinterpret_cast<disk_cache::Entry**>(&entry_))) {
374 printf("Skipping entry \"%s\" (name conflict!)\n", key.c_str());
375 return SendGetPrevEntry();
376 }
377
378 if (key.size() >= 64) {
379 key[60] = '.';
380 key[61] = '.';
381 key[62] = '.';
382 key[63] = '\0';
383 }
384 DEBUGMSG("Entry \"%s\" created\n", key.c_str());
385 state_ = MASTER_GET_USE_TIMES;
386 Message msg;
387 msg.command = GET_USE_TIMES;
388 msg.long_arg1 = remote_entry_;
389 SendMsg(msg);
390 }
391
DoGetUseTimes()392 void MasterSM::DoGetUseTimes() {
393 DEBUGMSG("Master DoGetUseTimes\n");
394 DCHECK(state_ == MASTER_GET_USE_TIMES);
395 DCHECK(input_->msg.command == GET_USE_TIMES);
396 if (input_->msg.result != RESULT_OK)
397 return Fail();
398
399 last_used_ = base::Time::FromInternalValue(input_->msg.long_arg2);
400 last_modified_ = base::Time::FromInternalValue(input_->msg.long_arg3);
401 stream_ = 0;
402 SendGetDataSize();
403 }
404
SendGetDataSize()405 void MasterSM::SendGetDataSize() {
406 DEBUGMSG("Master SendGetDataSize (%d)\n", stream_);
407 state_ = MASTER_GET_DATA_SIZE;
408 Message msg;
409 msg.command = GET_DATA_SIZE;
410 msg.arg1 = stream_;
411 msg.long_arg1 = remote_entry_;
412 SendMsg(msg);
413 }
414
DoGetDataSize()415 void MasterSM::DoGetDataSize() {
416 DEBUGMSG("Master DoGetDataSize: %d\n", input_->msg.arg2);
417 DCHECK(state_ == MASTER_GET_DATA_SIZE);
418 DCHECK(input_->msg.command == GET_DATA_SIZE);
419 if (input_->msg.result == RESULT_INVALID_PARAMETER)
420 // No more streams, move to the next entry.
421 return CloseEntry();
422
423 if (input_->msg.result != RESULT_OK)
424 return Fail();
425
426 bytes_remaining_ = input_->msg.arg2;
427 offset_ = 0;
428 SendReadData();
429 }
430
CloseEntry()431 void MasterSM::CloseEntry() {
432 DEBUGMSG("Master CloseEntry\n");
433 printf("%c\r", copied_entries_ % 2 ? 'x' : '+');
434 writer_->CloseEntry(entry_, last_used_, last_modified_);
435 entry_ = NULL;
436 copied_entries_++;
437 SendGetPrevEntry();
438 }
439
SendReadData()440 void MasterSM::SendReadData() {
441 int read_size = std::min(bytes_remaining_, kBufferSize);
442 DEBUGMSG("Master SendReadData (%d): %d bytes at %d\n", stream_, read_size,
443 offset_);
444 if (bytes_remaining_ <= 0) {
445 stream_++;
446 if (stream_ >= kNumStreams)
447 return CloseEntry();
448 return SendGetDataSize();
449 }
450
451 state_ = MASTER_READ_DATA;
452 Message msg;
453 msg.command = READ_DATA;
454 msg.arg1 = stream_;
455 msg.arg2 = read_size;
456 msg.arg3 = offset_;
457 msg.long_arg1 = remote_entry_;
458 SendMsg(msg);
459 }
460
DoReadData(int bytes_read)461 void MasterSM::DoReadData(int bytes_read) {
462 DEBUGMSG("Master DoReadData: %d bytes\n", input_->msg.buffer_bytes);
463 DCHECK(state_ == MASTER_READ_DATA);
464 DCHECK(input_->msg.command == READ_DATA);
465 if (input_->msg.result != RESULT_OK)
466 return Fail();
467
468 int read_size = input_->msg.buffer_bytes;
469 if (!read_size) {
470 printf("Read failed, entry \"%s\" truncated!\n", entry_->GetKey().c_str());
471 bytes_remaining_ = 0;
472 return SendReadData();
473 }
474
475 scoped_refptr<net::WrappedIOBuffer> buf =
476 new net::WrappedIOBuffer(input_->buffer);
477 if (!writer_->WriteEntry(entry_, stream_, offset_, buf, read_size))
478 return Fail();
479
480 offset_ += read_size;
481 bytes_remaining_ -= read_size;
482 // Read some more.
483 SendReadData();
484 }
485
SendQuit()486 void MasterSM::SendQuit() {
487 DEBUGMSG("Master SendQuit\n");
488 state_ = MASTER_END;
489 Message msg;
490 msg.command = QUIT;
491 SendMsg(msg);
492 if (!IsPending())
493 DoEnd();
494 }
495
DoEnd()496 void MasterSM::DoEnd() {
497 DEBUGMSG("Master DoEnd\n");
498 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
499 }
500
Fail()501 void MasterSM::Fail() {
502 DEBUGMSG("Master Fail\n");
503 printf("Unexpected failure\n");
504 SendQuit();
505 }
506
507 // -----------------------------------------------------------------------
508
509 class SlaveSM : public BaseSM {
510 public:
SlaveSM(const std::wstring & path,HANDLE channel)511 SlaveSM(const std::wstring& path, HANDLE channel)
512 : BaseSM(channel), iterator_(NULL) {
513 cache_.reset(new disk_cache::BackendImpl(FilePath::FromWStringHack(path)));
514 if (!cache_->Init()) {
515 printf("Unable to open cache files\n");
516 return;
517 }
518 cache_->SetUpgradeMode();
519 }
520 virtual ~SlaveSM();
521
522 bool DoInit();
523 virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
524 DWORD bytes_transfered, DWORD error);
525
526 private:
527 enum {
528 SLAVE_INITIAL = 0,
529 SLAVE_WAITING,
530 SLAVE_END
531 };
532
533 void DoGetNextEntry();
534 void DoGetPrevEntry();
535 int32 GetEntryFromList();
536 void DoCloseEntry();
537 void DoGetKey();
538 void DoGetUseTimes();
539 void DoGetDataSize();
540 void DoReadData();
541 void DoEnd();
542 void Fail();
543
544 void* iterator_;
545
546 scoped_ptr<disk_cache::BackendImpl> cache_;
547 };
548
~SlaveSM()549 SlaveSM::~SlaveSM() {
550 if (iterator_)
551 cache_->EndEnumeration(&iterator_);
552 }
553
OnIOCompleted(MessageLoopForIO::IOContext * context,DWORD bytes_transfered,DWORD error)554 void SlaveSM::OnIOCompleted(MessageLoopForIO::IOContext* context,
555 DWORD bytes_transfered, DWORD error) {
556 pending_count_--;
557 if (state_ == SLAVE_END) {
558 if (IsPending())
559 return;
560 return DoEnd();
561 }
562
563 if (context == &out_context_) {
564 if (!error)
565 return;
566 return Fail();
567 }
568
569 int bytes_read = static_cast<int>(bytes_transfered);
570 if (bytes_read < sizeof(Message)) {
571 printf("Communication breakdown\n");
572 return Fail();
573 }
574 DCHECK(state_ == SLAVE_WAITING);
575
576 switch (input_->msg.command) {
577 case GET_NEXT_ENTRY:
578 DoGetNextEntry();
579 break;
580 case GET_PREV_ENTRY:
581 DoGetPrevEntry();
582 break;
583 case CLOSE_ENTRY:
584 DoCloseEntry();
585 break;
586 case GET_KEY:
587 DoGetKey();
588 break;
589 case GET_USE_TIMES:
590 DoGetUseTimes();
591 break;
592 case GET_DATA_SIZE:
593 DoGetDataSize();
594 break;
595 case READ_DATA:
596 DoReadData();
597 break;
598 case QUIT:
599 DoEnd();
600 break;
601 default:
602 NOTREACHED();
603 break;
604 }
605 }
606
DoInit()607 bool SlaveSM::DoInit() {
608 DEBUGMSG("\t\t\tSlave DoInit\n");
609 DCHECK(state_ == SLAVE_INITIAL);
610 state_ = SLAVE_WAITING;
611 return ReceiveMsg();
612 }
613
DoGetNextEntry()614 void SlaveSM::DoGetNextEntry() {
615 DEBUGMSG("\t\t\tSlave DoGetNextEntry\n");
616 Message msg;
617 msg.command = GET_NEXT_ENTRY;
618
619 if (input_->msg.arg1) {
620 // We only support one list.
621 msg.result = RESULT_UNKNOWN_COMMAND;
622 } else {
623 msg.result = GetEntryFromList();
624 msg.long_arg1 = reinterpret_cast<int64>(entry_);
625 }
626 SendMsg(msg);
627 }
628
DoGetPrevEntry()629 void SlaveSM::DoGetPrevEntry() {
630 DEBUGMSG("\t\t\tSlave DoGetPrevEntry\n");
631 Message msg;
632 msg.command = GET_PREV_ENTRY;
633
634 if (input_->msg.arg1) {
635 // We only support one list.
636 msg.result = RESULT_UNKNOWN_COMMAND;
637 } else {
638 msg.result = GetEntryFromList();
639 msg.long_arg1 = reinterpret_cast<int64>(entry_);
640 }
641 SendMsg(msg);
642 }
643
644 // Move to the next or previous entry on the list.
GetEntryFromList()645 int32 SlaveSM::GetEntryFromList() {
646 DEBUGMSG("\t\t\tSlave GetEntryFromList\n");
647 if (input_->msg.long_arg1 != reinterpret_cast<int64>(entry_))
648 return RESULT_INVALID_PARAMETER;
649
650 // We know that the current iteration is valid.
651 if (entry_)
652 entry_->Close();
653
654 bool ret;
655 if (input_->msg.command == GET_NEXT_ENTRY) {
656 ret = cache_->OpenNextEntry(&iterator_,
657 reinterpret_cast<disk_cache::Entry**>(&entry_));
658 } else {
659 DCHECK(input_->msg.command == GET_PREV_ENTRY);
660 ret = cache_->OpenPrevEntry(&iterator_,
661 reinterpret_cast<disk_cache::Entry**>(&entry_));
662 }
663
664 if (!ret)
665 entry_ = NULL;
666
667 if (!entry_)
668 DEBUGMSG("\t\t\tSlave end of list\n");
669
670 return RESULT_OK;
671 }
672
DoCloseEntry()673 void SlaveSM::DoCloseEntry() {
674 DEBUGMSG("\t\t\tSlave DoCloseEntry\n");
675 Message msg;
676 msg.command = GET_KEY;
677
678 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) {
679 msg.result = RESULT_INVALID_PARAMETER;
680 } else {
681 entry_->Close();
682 entry_ = NULL;
683 cache_->EndEnumeration(&iterator_);
684 msg.result = RESULT_OK;
685 }
686 SendMsg(msg);
687 }
688
DoGetKey()689 void SlaveSM::DoGetKey() {
690 DEBUGMSG("\t\t\tSlave DoGetKey\n");
691 Message msg;
692 msg.command = GET_KEY;
693
694 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) {
695 msg.result = RESULT_INVALID_PARAMETER;
696 } else {
697 std::string key = entry_->GetKey();
698 msg.buffer_bytes = std::min(key.size() + 1,
699 static_cast<size_t>(kBufferSize));
700 memcpy(output_->buffer, key.c_str(), msg.buffer_bytes);
701 if (msg.buffer_bytes != key.size() + 1) {
702 // We don't support moving this entry. Just tell the master.
703 msg.result = RESULT_NAME_OVERFLOW;
704 } else {
705 msg.result = RESULT_OK;
706 }
707 }
708 SendMsg(msg);
709 }
710
DoGetUseTimes()711 void SlaveSM::DoGetUseTimes() {
712 DEBUGMSG("\t\t\tSlave DoGetUseTimes\n");
713 Message msg;
714 msg.command = GET_USE_TIMES;
715
716 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) {
717 msg.result = RESULT_INVALID_PARAMETER;
718 } else {
719 msg.long_arg2 = entry_->GetLastUsed().ToInternalValue();
720 msg.long_arg3 = entry_->GetLastModified().ToInternalValue();
721 msg.result = RESULT_OK;
722 }
723 SendMsg(msg);
724 }
725
DoGetDataSize()726 void SlaveSM::DoGetDataSize() {
727 DEBUGMSG("\t\t\tSlave DoGetDataSize\n");
728 Message msg;
729 msg.command = GET_DATA_SIZE;
730
731 int stream = input_->msg.arg1;
732 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) ||
733 stream < 0 || stream >= kNumStreams) {
734 msg.result = RESULT_INVALID_PARAMETER;
735 } else {
736 msg.arg1 = stream;
737 msg.arg2 = entry_->GetDataSize(stream);
738 msg.result = RESULT_OK;
739 }
740 SendMsg(msg);
741 }
742
DoReadData()743 void SlaveSM::DoReadData() {
744 DEBUGMSG("\t\t\tSlave DoReadData\n");
745 Message msg;
746 msg.command = READ_DATA;
747
748 int stream = input_->msg.arg1;
749 int size = input_->msg.arg2;
750 if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) ||
751 stream < 0 || stream > 1 || size > kBufferSize) {
752 msg.result = RESULT_INVALID_PARAMETER;
753 } else {
754 scoped_refptr<net::WrappedIOBuffer> buf =
755 new net::WrappedIOBuffer(output_->buffer);
756 int ret = entry_->ReadData(stream, input_->msg.arg3, buf, size, NULL);
757
758 msg.buffer_bytes = (ret < 0) ? 0 : ret;
759 msg.result = RESULT_OK;
760 }
761 SendMsg(msg);
762 }
763
DoEnd()764 void SlaveSM::DoEnd() {
765 DEBUGMSG("\t\t\tSlave DoEnd\n");
766 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
767 }
768
Fail()769 void SlaveSM::Fail() {
770 DEBUGMSG("\t\t\tSlave Fail\n");
771 printf("Unexpected failure\n");
772 state_ = SLAVE_END;
773 if (IsPending()) {
774 CancelIo(channel_);
775 } else {
776 DoEnd();
777 }
778 }
779
780 } // namespace.
781
782 // -----------------------------------------------------------------------
783
CreateServer(std::wstring * pipe_number)784 HANDLE CreateServer(std::wstring* pipe_number) {
785 std::wstring pipe_name(kPipePrefix);
786 srand(static_cast<int>(base::Time::Now().ToInternalValue()));
787 *pipe_number = IntToWString(rand());
788 pipe_name.append(*pipe_number);
789
790 DWORD mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE |
791 FILE_FLAG_OVERLAPPED;
792
793 return CreateNamedPipe(pipe_name.c_str(), mode, 0, 1, kChannelSize,
794 kChannelSize, 0, NULL);
795 }
796
797 // This is the controller process for an upgrade operation.
CopyCache(const std::wstring & output_path,HANDLE pipe,bool copy_to_text)798 int CopyCache(const std::wstring& output_path, HANDLE pipe, bool copy_to_text) {
799 MessageLoop loop(MessageLoop::TYPE_IO);
800
801 MasterSM master(output_path, pipe, copy_to_text);
802 if (!master.DoInit()) {
803 printf("Unable to talk with the helper\n");
804 return -1;
805 }
806
807 loop.Run();
808 return 0;
809 }
810
811 // This process will only execute commands from the controller.
RunSlave(const std::wstring & input_path,const std::wstring & pipe_number)812 int RunSlave(const std::wstring& input_path, const std::wstring& pipe_number) {
813 MessageLoop loop(MessageLoop::TYPE_IO);
814
815 ScopedHandle pipe(OpenServer(pipe_number));
816 if (!pipe.IsValid()) {
817 printf("Unable to open the server pipe\n");
818 return -1;
819 }
820
821 SlaveSM slave(input_path, pipe);
822 if (!slave.DoInit()) {
823 printf("Unable to talk with the main process\n");
824 return -1;
825 }
826
827 loop.Run();
828 return 0;
829 }
830