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"
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"
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.
37 #define DEBUGMSG(...) {}
39 #define DEBUGMSG(...) { printf(__VA_ARGS__); }
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.
67 memset(this, 0, sizeof(*this));
69 Message
& operator= (const Message
& other
) {
70 memcpy(this, &other
, sizeof(*this));
75 const int kBufferSize
= kChannelSize
- sizeof(Message
);
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.
86 // Get the entry from list |arg1| that follows |long_arg1|.
87 // The result is placed on |long_arg1| (closes the previous one).
89 // Get the entry from list |arg1| that precedes |long_arg1|.
90 // The result is placed on |long_arg1| (closes the previous one).
92 // Closes the entry |long_arg1|.
94 // Get the key of the entry |long_arg1|.
96 // Get last used (long_arg2) and last modified (long_arg3) times for the
97 // entry at |long_arg1|.
99 // Returns on |arg2| the data size in bytes if the stream |arg1| of entry at
102 // Returns |arg2| bytes of the stream |arg1| for the entry at |long_arg1|,
103 // starting at offset |arg3|.
105 // End processing requests.
109 // The list of return codes.
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
{
122 explicit BaseSM(HANDLE channel
);
126 bool SendMsg(const Message
& msg
);
128 bool ConnectChannel();
131 base::MessageLoopForIO::IOContext in_context_
;
132 base::MessageLoopForIO::IOContext out_context_
;
133 disk_cache::EntryImpl
* entry_
;
137 scoped_ptr
<char[]> in_buffer_
;
138 scoped_ptr
<char[]> out_buffer_
;
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)));
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.
176 if (!WriteFile(channel_
, output_
, sizeof(msg
) + msg
.buffer_bytes
, &written
,
177 &out_context_
.overlapped
)) {
178 if (ERROR_IO_PENDING
!= GetLastError())
185 bool BaseSM::ReceiveMsg() {
187 if (!ReadFile(channel_
, input_
, kChannelSize
, &read
,
188 &in_context_
.overlapped
)) {
189 if (ERROR_IO_PENDING
!= GetLastError())
196 bool BaseSM::ConnectChannel() {
197 if (!ConnectNamedPipe(channel_
, &in_context_
.overlapped
)) {
198 DWORD error
= GetLastError();
199 if (ERROR_PIPE_CONNECTED
== error
)
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
)
210 bool BaseSM::IsPending() {
211 return pending_count_
!= 0;
214 // -----------------------------------------------------------------------
216 class MasterSM
: public BaseSM
{
218 MasterSM(const base::FilePath
& path
, HANDLE channel
)
222 virtual ~MasterSM() {
227 virtual void OnIOCompleted(base::MessageLoopForIO::IOContext
* context
,
228 DWORD bytes_transfered
,
236 MASTER_GET_NEXT_ENTRY
,
238 MASTER_GET_USE_TIMES
,
239 MASTER_GET_DATA_SIZE
,
244 void SendGetPrevEntry();
246 void DoGetKey(int bytes_read
);
247 void DoCreateEntryComplete(int result
);
248 void DoGetUseTimes();
249 void SendGetDataSize();
250 void DoGetDataSize();
253 void DoReadData(int bytes_read
);
254 void DoReadDataComplete(int ret
);
259 base::Time last_used_
;
260 base::Time last_modified_
;
263 int bytes_remaining_
;
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
,
276 if (context
== &out_context_
) {
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");
293 case MASTER_GET_ENTRY
:
297 DoGetKey(bytes_read
);
299 case MASTER_GET_USE_TIMES
:
302 case MASTER_GET_DATA_SIZE
:
305 case MASTER_READ_DATA
:
306 DoReadData(bytes_read
);
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,
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");
333 cache_
= cache
.Pass();
334 writer_
= new CacheDumper(cache_
.get());
339 if (ConnectChannel()) {
341 // If we don't have pending operations we couldn't connect.
345 state_
= MASTER_CONNECT
;
349 void MasterSM::SendGetPrevEntry() {
350 DEBUGMSG("Master SendGetPrevEntry\n");
351 state_
= MASTER_GET_ENTRY
;
353 msg
.command
= GET_PREV_ENTRY
;
354 msg
.long_arg1
= remote_entry_
;
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
)
365 if (!input_
->msg
.long_arg1
) {
366 printf("Done: %d entries copied over.\n", copied_entries_
);
369 remote_entry_
= input_
->msg
.long_arg1
;
370 state_
= MASTER_GET_KEY
;
372 msg
.command
= GET_KEY
;
373 msg
.long_arg1
= remote_entry_
;
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
)
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) {
414 DEBUGMSG("Entry \"%s\" created\n", key
.c_str());
415 state_
= MASTER_GET_USE_TIMES
;
417 msg
.command
= GET_USE_TIMES
;
418 msg
.long_arg1
= remote_entry_
;
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
)
429 last_used_
= base::Time::FromInternalValue(input_
->msg
.long_arg2
);
430 last_modified_
= base::Time::FromInternalValue(input_
->msg
.long_arg3
);
435 void MasterSM::SendGetDataSize() {
436 DEBUGMSG("Master SendGetDataSize (%d)\n", stream_
);
437 state_
= MASTER_GET_DATA_SIZE
;
439 msg
.command
= GET_DATA_SIZE
;
441 msg
.long_arg1
= remote_entry_
;
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.
453 if (input_
->msg
.result
!= RESULT_OK
)
456 bytes_remaining_
= input_
->msg
.arg2
;
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_
);
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
,
474 if (bytes_remaining_
<= 0) {
476 if (stream_
>= kNumStreams
)
478 return SendGetDataSize();
481 state_
= MASTER_READ_DATA
;
483 msg
.command
= READ_DATA
;
485 msg
.arg2
= read_size
;
487 msg
.long_arg1
= remote_entry_
;
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
)
498 int read_size
= input_
->msg
.buffer_bytes
;
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
;
519 offset_
+= read_size
;
520 bytes_remaining_
-= read_size
;
525 void MasterSM::DoReadDataComplete(int ret
) {
526 if (ret
!= read_size_
)
530 bytes_remaining_
-= ret
;
535 void MasterSM::SendQuit() {
536 DEBUGMSG("Master SendQuit\n");
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");
557 // -----------------------------------------------------------------------
559 class SlaveSM
: public BaseSM
{
561 SlaveSM(const base::FilePath
& path
, HANDLE channel
);
565 virtual void OnIOCompleted(base::MessageLoopForIO::IOContext
* context
,
566 DWORD bytes_transfered
,
576 void DoGetNextEntry();
577 void DoGetPrevEntry();
578 int32
GetEntryFromList();
579 void DoGetEntryComplete(int result
);
582 void DoGetUseTimes();
583 void DoGetDataSize();
585 void DoReadDataComplete(int ret
);
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,
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");
608 cache_
.reset(reinterpret_cast<disk_cache::BackendImpl
*>(cache
.release()));
609 cache_
->SetUpgradeMode();
612 SlaveSM::~SlaveSM() {
614 cache_
->EndEnumeration(&iterator_
);
617 void SlaveSM::OnIOCompleted(base::MessageLoopForIO::IOContext
* context
,
618 DWORD bytes_transfered
,
621 if (state_
== SLAVE_END
) {
627 if (context
== &out_context_
) {
633 int bytes_read
= static_cast<int>(bytes_transfered
);
634 if (bytes_read
< sizeof(Message
)) {
635 printf("Communication breakdown\n");
638 DCHECK(state_
== SLAVE_WAITING
);
640 switch (input_
->msg
.command
) {
671 bool SlaveSM::DoInit() {
672 DEBUGMSG("\t\t\tSlave DoInit\n");
673 DCHECK(state_
== SLAVE_INITIAL
);
674 state_
= SLAVE_WAITING
;
681 void SlaveSM::DoGetNextEntry() {
682 DEBUGMSG("\t\t\tSlave DoGetNextEntry\n");
684 msg
.command
= GET_NEXT_ENTRY
;
686 if (input_
->msg
.arg1
) {
687 // We only support one list.
688 msg
.result
= RESULT_UNKNOWN_COMMAND
;
690 msg
.result
= GetEntryFromList();
691 msg
.long_arg1
= reinterpret_cast<int64
>(entry_
);
696 void SlaveSM::DoGetPrevEntry() {
697 DEBUGMSG("\t\t\tSlave DoGetPrevEntry\n");
699 msg
.command
= GET_PREV_ENTRY
;
701 if (input_
->msg
.arg1
) {
702 // We only support one list.
703 msg
.result
= RESULT_UNKNOWN_COMMAND
;
705 msg
.result
= GetEntryFromList();
706 if (msg
.result
== RESULT_PENDING
) {
707 // We are not done yet.
711 msg
.long_arg1
= reinterpret_cast<int64
>(entry_
);
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.
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)));
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
) {
746 DEBUGMSG("\t\t\tSlave end of list\n");
749 msg_
.result
= RESULT_OK
;
750 msg_
.long_arg1
= reinterpret_cast<int64
>(entry_
);
754 void SlaveSM::DoCloseEntry() {
755 DEBUGMSG("\t\t\tSlave DoCloseEntry\n");
757 msg
.command
= GET_KEY
;
759 if (!entry_
|| input_
->msg
.long_arg1
!= reinterpret_cast<int64
>(entry_
)) {
760 msg
.result
= RESULT_INVALID_PARAMETER
;
764 cache_
->EndEnumeration(&iterator_
);
765 msg
.result
= RESULT_OK
;
770 void SlaveSM::DoGetKey() {
771 DEBUGMSG("\t\t\tSlave DoGetKey\n");
773 msg
.command
= GET_KEY
;
775 if (!entry_
|| input_
->msg
.long_arg1
!= reinterpret_cast<int64
>(entry_
)) {
776 msg
.result
= RESULT_INVALID_PARAMETER
;
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
;
786 msg
.result
= RESULT_OK
;
792 void SlaveSM::DoGetUseTimes() {
793 DEBUGMSG("\t\t\tSlave DoGetUseTimes\n");
795 msg
.command
= GET_USE_TIMES
;
797 if (!entry_
|| input_
->msg
.long_arg1
!= reinterpret_cast<int64
>(entry_
)) {
798 msg
.result
= RESULT_INVALID_PARAMETER
;
800 msg
.long_arg2
= entry_
->GetLastUsed().ToInternalValue();
801 msg
.long_arg3
= entry_
->GetLastModified().ToInternalValue();
802 msg
.result
= RESULT_OK
;
807 void SlaveSM::DoGetDataSize() {
808 DEBUGMSG("\t\t\tSlave DoGetDataSize\n");
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
;
818 msg
.arg2
= entry_
->GetDataSize(stream
);
819 msg
.result
= RESULT_OK
;
824 void SlaveSM::DoReadData() {
825 DEBUGMSG("\t\t\tSlave DoReadData\n");
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
;
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.
846 msg
.buffer_bytes
= (ret
< 0) ? 0 : ret
;
847 msg
.result
= RESULT_OK
;
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
;
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");
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");
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");
919 SlaveSM
slave(input_path
, pipe
);
920 if (!slave
.DoInit()) {
921 printf("Unable to talk with the main process\n");