summaryrefslogtreecommitdiffstats
path: root/net/tools/dump_cache/upgrade.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/tools/dump_cache/upgrade.cc')
-rw-r--r--net/tools/dump_cache/upgrade.cc791
1 files changed, 791 insertions, 0 deletions
diff --git a/net/tools/dump_cache/upgrade.cc b/net/tools/dump_cache/upgrade.cc
new file mode 100644
index 0000000..1495b95
--- /dev/null
+++ b/net/tools/dump_cache/upgrade.cc
@@ -0,0 +1,791 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/string_util.h"
+#include "net/disk_cache/backend_impl.h"
+#include "net/disk_cache/entry_impl.h"
+
+namespace {
+
+const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\dump_cache_";
+const int kChannelSize = 64 * 1024;
+const int kNumStreams = 2;
+
+// Simple macro to print out formatted debug messages. It is similar to a DLOG
+// except that it doesn't include a header.
+#ifdef NDEBUG
+#define DEBUGMSG(...) {}
+#else
+#define DEBUGMSG(...) { printf(__VA_ARGS__); }
+#endif
+
+HANDLE OpenServer(const std::wstring pipe_number) {
+ std::wstring pipe_name(kPipePrefix);
+ pipe_name.append(pipe_number);
+ return CreateFile(pipe_name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+}
+
+// This is the basic message to use between the two processes. It is intended
+// to transmit a single action (like "get the key name for entry xx"), with up
+// to 5 32-bit arguments and 4 64-bit arguments. After this structure, the rest
+// of the message has |buffer_bytes| of length with the actual data.
+struct Message {
+ int32 command;
+ int32 result;
+ int32 buffer_bytes;
+ int32 arg1;
+ int32 arg2;
+ int32 arg3;
+ int32 arg4;
+ int32 arg5;
+ int64 long_arg1;
+ int64 long_arg2;
+ int64 long_arg3;
+ int64 long_arg4;
+ Message() {
+ memset(this, 0, sizeof(*this));
+ }
+ Message& operator= (const Message& other) {
+ memcpy(this, &other, sizeof(*this));
+ return *this;
+ }
+};
+
+const int kBufferSize = kChannelSize - sizeof(Message);
+struct IoBuffer {
+ Message msg;
+ char buffer[kBufferSize];
+};
+COMPILE_ASSERT(sizeof(IoBuffer) == kChannelSize, invalid_io_buffer);
+
+
+// The list of commands.
+// Currently, there is support for working ONLY with one entry at a time.
+enum {
+ // Get the entry from list |arg1| that follows |long_arg1|.
+ // The result is placed on |long_arg1| (closes the previous one).
+ GET_NEXT_ENTRY = 1,
+ // Get the entry from list |arg1| that precedes |long_arg1|.
+ // The result is placed on |long_arg1| (closes the previous one).
+ GET_PREV_ENTRY,
+ // Closes the entry |long_arg1|.
+ CLOSE_ENTRY,
+ // Get the key of the entry |long_arg1|.
+ GET_KEY,
+ // Get last used (long_arg2) and last modified (long_arg3) times for the
+ // entry at |long_arg1|.
+ GET_USE_TIMES,
+ // Returns on |arg2| the data size in bytes if the stream |arg1| of entry at
+ // |long_arg1|.
+ GET_DATA_SIZE,
+ // Returns |arg2| bytes of the stream |arg1| for the entry at |long_arg1|,
+ // starting at offset |arg3|.
+ READ_DATA,
+ // End processing requests.
+ QUIT
+};
+
+// The list of return codes.
+enum {
+ RESULT_OK = 0,
+ RESULT_UNKNOWN_COMMAND,
+ RESULT_INVALID_PARAMETER,
+ RESULT_NAME_OVERFLOW
+};
+
+// -----------------------------------------------------------------------
+
+class BaseSM : public MessageLoopForIO::IOHandler {
+ public:
+ BaseSM(disk_cache::BackendImpl* cache, HANDLE channel);
+ virtual ~BaseSM();
+
+ protected:
+ bool SendMsg(const Message& msg);
+ bool ReceiveMsg();
+ bool ConnectChannel();
+ bool IsPending();
+
+ MessageLoopForIO::IOContext in_context_;
+ MessageLoopForIO::IOContext out_context_;
+ disk_cache::BackendImpl* cache_;
+ disk_cache::EntryImpl* entry_;
+ HANDLE channel_;
+ int state_;
+ int pending_count_;
+ scoped_array<char> in_buffer_;
+ scoped_array<char> out_buffer_;
+ IoBuffer* input_;
+ IoBuffer* output_;
+ DISALLOW_COPY_AND_ASSIGN(BaseSM);
+};
+
+BaseSM::BaseSM(disk_cache::BackendImpl* cache, HANDLE channel)
+ : cache_(cache), entry_(NULL), channel_(channel), state_(0),
+ pending_count_(0) {
+ in_buffer_.reset(new char[kChannelSize]);
+ out_buffer_.reset(new char[kChannelSize]);
+ input_ = reinterpret_cast<IoBuffer*>(in_buffer_.get());
+ output_ = reinterpret_cast<IoBuffer*>(out_buffer_.get());
+
+ memset(&in_context_, 0, sizeof(in_context_));
+ memset(&out_context_, 0, sizeof(out_context_));
+ in_context_.handler = this;
+ out_context_.handler = this;
+ MessageLoopForIO::current()->RegisterIOHandler(channel_, this);
+}
+
+BaseSM::~BaseSM() {
+ if (entry_)
+ entry_->Close();
+}
+
+bool BaseSM::SendMsg(const Message& msg) {
+ // Only one command will be in-flight at a time. Let's start the Read IO here
+ // when we know that it will be pending.
+ if (!ReceiveMsg())
+ return false;
+
+ output_->msg = msg;
+ DWORD written;
+ if (!WriteFile(channel_, output_, sizeof(msg) + msg.buffer_bytes, &written,
+ &out_context_.overlapped)) {
+ if (ERROR_IO_PENDING != GetLastError())
+ return false;
+ }
+ pending_count_++;
+ return true;
+}
+
+bool BaseSM::ReceiveMsg() {
+ DWORD read;
+ if (!ReadFile(channel_, input_, kChannelSize, &read,
+ &in_context_.overlapped)) {
+ if (ERROR_IO_PENDING != GetLastError())
+ return false;
+ }
+ pending_count_++;
+ return true;
+}
+
+bool BaseSM::ConnectChannel() {
+ if (!ConnectNamedPipe(channel_, &in_context_.overlapped)) {
+ DWORD error = GetLastError();
+ if (ERROR_PIPE_CONNECTED == error)
+ return true;
+ // By returning true in case of a generic error, we allow the operation to
+ // fail while sending the first message.
+ if (ERROR_IO_PENDING != error)
+ return true;
+ }
+ pending_count_++;
+ return false;
+}
+
+bool BaseSM::IsPending() {
+ return pending_count_ != 0;
+}
+
+// -----------------------------------------------------------------------
+
+class MasterSM : public BaseSM {
+ public:
+ MasterSM(disk_cache::BackendImpl* cache, HANDLE channel)
+ : BaseSM(cache, channel) {}
+ virtual ~MasterSM() {}
+
+ bool DoInit();
+ virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error);
+
+ private:
+ enum {
+ MASTER_INITIAL = 0,
+ MASTER_CONNECT,
+ MASTER_GET_ENTRY,
+ MASTER_GET_NEXT_ENTRY,
+ MASTER_GET_KEY,
+ MASTER_GET_USE_TIMES,
+ MASTER_GET_DATA_SIZE,
+ MASTER_READ_DATA,
+ MASTER_END
+ };
+
+ void SendGetPrevEntry();
+ void DoGetEntry();
+ void DoGetKey(int bytes_read);
+ void DoGetUseTimes();
+ void SendGetDataSize();
+ void DoGetDataSize();
+ void CloseEntry();
+ void SendReadData();
+ void DoReadData(int bytes_read);
+ void SendQuit();
+ void DoEnd();
+ void Fail();
+
+ base::Time last_used_;
+ base::Time last_modified_;
+ int64 remote_entry_;
+ int stream_;
+ int bytes_remaining_;
+ int offset_;
+ int copied_entries_;
+};
+
+void MasterSM::OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error) {
+ pending_count_--;
+ if (context == &out_context_) {
+ if (!error)
+ return;
+ return Fail();
+ }
+
+ int bytes_read = static_cast<int>(bytes_transfered);
+ if (bytes_read < sizeof(Message) && state_ != MASTER_END &&
+ state_ != MASTER_CONNECT) {
+ printf("Communication breakdown\n");
+ return Fail();
+ }
+
+ switch (state_) {
+ case MASTER_CONNECT:
+ SendGetPrevEntry();
+ break;
+ case MASTER_GET_ENTRY:
+ DoGetEntry();
+ break;
+ case MASTER_GET_KEY:
+ DoGetKey(bytes_read);
+ break;
+ case MASTER_GET_USE_TIMES:
+ DoGetUseTimes();
+ break;
+ case MASTER_GET_DATA_SIZE:
+ DoGetDataSize();
+ break;
+ case MASTER_READ_DATA:
+ DoReadData(bytes_read);
+ break;
+ case MASTER_END:
+ if (!IsPending())
+ DoEnd();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+bool MasterSM::DoInit() {
+ DEBUGMSG("Master DoInit\n");
+ DCHECK(state_ == MASTER_INITIAL);
+
+ copied_entries_ = 0;
+ remote_entry_ = 0;
+
+ if (ConnectChannel()) {
+ SendGetPrevEntry();
+ // If we don't have pending operations we couldn't connect.
+ return IsPending();
+ }
+
+ state_ = MASTER_CONNECT;
+ return true;
+}
+
+void MasterSM::SendGetPrevEntry() {
+ DEBUGMSG("Master SendGetPrevEntry\n");
+ state_ = MASTER_GET_ENTRY;
+ Message msg;
+ msg.command = GET_PREV_ENTRY;
+ msg.long_arg1 = remote_entry_;
+ SendMsg(msg);
+}
+
+void MasterSM::DoGetEntry() {
+ DEBUGMSG("Master DoGetEntry\n");
+ DCHECK(state_ == MASTER_GET_ENTRY);
+ DCHECK(input_->msg.command == GET_PREV_ENTRY);
+ if (input_->msg.result != RESULT_OK)
+ return Fail();
+
+ if (!input_->msg.long_arg1) {
+ printf("Done: %d entries copied over.\n", copied_entries_);
+ return SendQuit();
+ }
+ remote_entry_ = input_->msg.long_arg1;
+ state_ = MASTER_GET_KEY;
+ Message msg;
+ msg.command = GET_KEY;
+ msg.long_arg1 = remote_entry_;
+ SendMsg(msg);
+}
+
+void MasterSM::DoGetKey(int bytes_read) {
+ DEBUGMSG("Master DoGetKey\n");
+ DCHECK(state_ == MASTER_GET_KEY);
+ DCHECK(input_->msg.command == GET_KEY);
+ if (input_->msg.result == RESULT_NAME_OVERFLOW)
+ // The key is too long. Just move on.
+ return SendGetPrevEntry();
+
+ if (input_->msg.result != RESULT_OK)
+ return Fail();
+
+ std::string key(input_->buffer);
+ DCHECK(key.size() == input_->msg.buffer_bytes - 1);
+ if (!cache_->CreateEntry(key, reinterpret_cast<disk_cache::Entry**>(&entry_)))
+ return Fail();
+
+ if (key.size() < 60) {
+ DEBUGMSG("Entry \"%s\" created\n", key.c_str());
+ } else {
+ DEBUGMSG("Entry (long name) created\n", key.c_str());
+ }
+ state_ = MASTER_GET_USE_TIMES;
+ Message msg;
+ msg.command = GET_USE_TIMES;
+ msg.long_arg1 = remote_entry_;
+ SendMsg(msg);
+}
+
+void MasterSM::DoGetUseTimes() {
+ DEBUGMSG("Master DoGetUseTimes\n");
+ DCHECK(state_ == MASTER_GET_USE_TIMES);
+ DCHECK(input_->msg.command == GET_USE_TIMES);
+ if (input_->msg.result != RESULT_OK)
+ return Fail();
+
+ last_used_ = base::Time::FromInternalValue(input_->msg.long_arg2);
+ last_modified_ = base::Time::FromInternalValue(input_->msg.long_arg3);
+ stream_ = 0;
+ SendGetDataSize();
+}
+
+void MasterSM::SendGetDataSize() {
+ DEBUGMSG("Master SendGetDataSize (%d)\n", stream_);
+ state_ = MASTER_GET_DATA_SIZE;
+ Message msg;
+ msg.command = GET_DATA_SIZE;
+ msg.arg1 = stream_;
+ msg.long_arg1 = remote_entry_;
+ SendMsg(msg);
+}
+
+void MasterSM::DoGetDataSize() {
+ DEBUGMSG("Master DoGetDataSize: %d\n", input_->msg.arg2);
+ DCHECK(state_ == MASTER_GET_DATA_SIZE);
+ DCHECK(input_->msg.command == GET_DATA_SIZE);
+ if (input_->msg.result == RESULT_INVALID_PARAMETER)
+ // No more streams, move to the next entry.
+ return CloseEntry();
+
+ if (input_->msg.result != RESULT_OK)
+ return Fail();
+
+ bytes_remaining_ = input_->msg.arg2;
+ offset_ = 0;
+ SendReadData();
+}
+
+void MasterSM::CloseEntry() {
+ DEBUGMSG("Master CloseEntry\n");
+ printf("%c\r", copied_entries_ % 2 ? 'x' : '+');
+ entry_->SetTimes(last_used_, last_modified_);
+ entry_->Close();
+ entry_ = NULL;
+ copied_entries_++;
+ SendGetPrevEntry();
+}
+
+void MasterSM::SendReadData() {
+ int read_size = std::min(bytes_remaining_, kBufferSize);
+ DEBUGMSG("Master SendReadData (%d): %d bytes at %d\n", stream_, read_size,
+ offset_);
+ if (bytes_remaining_ <= 0) {
+ stream_++;
+ if (stream_ >= kNumStreams)
+ return CloseEntry();
+ return SendGetDataSize();
+ }
+
+ state_ = MASTER_READ_DATA;
+ Message msg;
+ msg.command = READ_DATA;
+ msg.arg1 = stream_;
+ msg.arg2 = read_size;
+ msg.arg3 = offset_;
+ msg.long_arg1 = remote_entry_;
+ SendMsg(msg);
+}
+
+void MasterSM::DoReadData(int bytes_read) {
+ DEBUGMSG("Master DoReadData: %d bytes\n", input_->msg.buffer_bytes);
+ DCHECK(state_ == MASTER_READ_DATA);
+ DCHECK(input_->msg.command == READ_DATA);
+ if (input_->msg.result != RESULT_OK)
+ return Fail();
+
+ int read_size = input_->msg.buffer_bytes;
+ if (read_size != entry_->WriteData(stream_, offset_, input_->buffer,
+ read_size, NULL, false))
+ return Fail();
+
+ offset_ += read_size;
+ bytes_remaining_ -= read_size;
+ // Read some more.
+ SendReadData();
+}
+
+void MasterSM::SendQuit() {
+ DEBUGMSG("Master SendQuit\n");
+ state_ = MASTER_END;
+ Message msg;
+ msg.command = QUIT;
+ SendMsg(msg);
+ if (!IsPending())
+ DoEnd();
+}
+
+void MasterSM::DoEnd() {
+ DEBUGMSG("Master DoEnd\n");
+ MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+}
+
+void MasterSM::Fail() {
+ DEBUGMSG("Master Fail\n");
+ printf("Unexpected failure\n");
+ SendQuit();
+}
+
+// -----------------------------------------------------------------------
+
+class SlaveSM : public BaseSM {
+ public:
+ SlaveSM(disk_cache::BackendImpl* cache, HANDLE channel)
+ : BaseSM(cache, channel), iterator_(NULL) {}
+ virtual ~SlaveSM();
+
+ bool DoInit();
+ virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error);
+
+ private:
+ enum {
+ SLAVE_INITIAL = 0,
+ SLAVE_WAITING,
+ SLAVE_END
+ };
+
+ void DoGetNextEntry();
+ void DoGetPrevEntry();
+ int32 GetEntryFromList();
+ void DoCloseEntry();
+ void DoGetKey();
+ void DoGetUseTimes();
+ void DoGetDataSize();
+ void DoReadData();
+ void DoEnd();
+ void Fail();
+
+ void* iterator_;
+};
+
+SlaveSM::~SlaveSM() {
+ if (iterator_)
+ cache_->EndEnumeration(&iterator_);
+}
+
+void SlaveSM::OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error) {
+ pending_count_--;
+ if (state_ == SLAVE_END) {
+ if (IsPending())
+ return;
+ return DoEnd();
+ }
+
+ if (context == &out_context_) {
+ if (!error)
+ return;
+ return Fail();
+ }
+
+ int bytes_read = static_cast<int>(bytes_transfered);
+ if (bytes_read < sizeof(Message)) {
+ printf("Communication breakdown\n");
+ return Fail();
+ }
+ DCHECK(state_ == SLAVE_WAITING);
+
+ switch (input_->msg.command) {
+ case GET_NEXT_ENTRY:
+ DoGetNextEntry();
+ break;
+ case GET_PREV_ENTRY:
+ DoGetPrevEntry();
+ break;
+ case CLOSE_ENTRY:
+ DoCloseEntry();
+ break;
+ case GET_KEY:
+ DoGetKey();
+ break;
+ case GET_USE_TIMES:
+ DoGetUseTimes();
+ break;
+ case GET_DATA_SIZE:
+ DoGetDataSize();
+ break;
+ case READ_DATA:
+ DoReadData();
+ break;
+ case QUIT:
+ DoEnd();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+bool SlaveSM::DoInit() {
+ DEBUGMSG("\t\t\tSlave DoInit\n");
+ DCHECK(state_ == SLAVE_INITIAL);
+ state_ = SLAVE_WAITING;
+ return ReceiveMsg();
+}
+
+void SlaveSM::DoGetNextEntry() {
+ DEBUGMSG("\t\t\tSlave DoGetNextEntry\n");
+ Message msg;
+ msg.command = GET_NEXT_ENTRY;
+
+ if (input_->msg.arg1) {
+ // We only support one list.
+ msg.result = RESULT_UNKNOWN_COMMAND;
+ } else {
+ msg.result = GetEntryFromList();
+ msg.long_arg1 = reinterpret_cast<int64>(entry_);
+ }
+ SendMsg(msg);
+}
+
+void SlaveSM::DoGetPrevEntry() {
+ DEBUGMSG("\t\t\tSlave DoGetPrevEntry\n");
+ Message msg;
+ msg.command = GET_PREV_ENTRY;
+
+ if (input_->msg.arg1) {
+ // We only support one list.
+ msg.result = RESULT_UNKNOWN_COMMAND;
+ } else {
+ msg.result = GetEntryFromList();
+ msg.long_arg1 = reinterpret_cast<int64>(entry_);
+ }
+ SendMsg(msg);
+}
+
+// Move to the next or previous entry on the list.
+int32 SlaveSM::GetEntryFromList() {
+ DEBUGMSG("\t\t\tSlave GetEntryFromList\n");
+ if (input_->msg.long_arg1 != reinterpret_cast<int64>(entry_))
+ return RESULT_INVALID_PARAMETER;
+
+ // We know that the current iteration is valid.
+ if (entry_)
+ entry_->Close();
+
+ bool ret;
+ if (input_->msg.command == GET_NEXT_ENTRY) {
+ ret = cache_->OpenNextEntry(&iterator_,
+ reinterpret_cast<disk_cache::Entry**>(&entry_));
+ } else {
+ DCHECK(input_->msg.command == GET_PREV_ENTRY);
+ ret = cache_->OpenPrevEntry(&iterator_,
+ reinterpret_cast<disk_cache::Entry**>(&entry_));
+ }
+
+ if (!ret)
+ entry_ = NULL;
+
+ if (!entry_)
+ DEBUGMSG("\t\t\tSlave end of list\n");
+
+ return RESULT_OK;
+}
+
+void SlaveSM::DoCloseEntry() {
+ DEBUGMSG("\t\t\tSlave DoCloseEntry\n");
+ Message msg;
+ msg.command = GET_KEY;
+
+ if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) {
+ msg.result = RESULT_INVALID_PARAMETER;
+ } else {
+ entry_->Close();
+ entry_ = NULL;
+ cache_->EndEnumeration(&iterator_);
+ msg.result = RESULT_OK;
+ }
+ SendMsg(msg);
+}
+
+void SlaveSM::DoGetKey() {
+ DEBUGMSG("\t\t\tSlave DoGetKey\n");
+ Message msg;
+ msg.command = GET_KEY;
+
+ if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) {
+ msg.result = RESULT_INVALID_PARAMETER;
+ } else {
+ std::string key = entry_->GetKey();
+ msg.buffer_bytes = std::min(key.size() + 1,
+ static_cast<size_t>(kBufferSize));
+ memcpy(output_->buffer, key.c_str(), msg.buffer_bytes);
+ if (msg.buffer_bytes != key.size() + 1) {
+ // We don't support moving this entry. Just tell the master.
+ msg.result = RESULT_NAME_OVERFLOW;
+ } else {
+ msg.result = RESULT_OK;
+ }
+ }
+ SendMsg(msg);
+}
+
+void SlaveSM::DoGetUseTimes() {
+ DEBUGMSG("\t\t\tSlave DoGetUseTimes\n");
+ Message msg;
+ msg.command = GET_USE_TIMES;
+
+ if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_)) {
+ msg.result = RESULT_INVALID_PARAMETER;
+ } else {
+ msg.long_arg2 = entry_->GetLastUsed().ToInternalValue();
+ msg.long_arg3 = entry_->GetLastModified().ToInternalValue();
+ msg.result = RESULT_OK;
+ }
+ SendMsg(msg);
+}
+
+void SlaveSM::DoGetDataSize() {
+ DEBUGMSG("\t\t\tSlave DoGetDataSize\n");
+ Message msg;
+ msg.command = GET_DATA_SIZE;
+
+ int stream = input_->msg.arg1;
+ if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) ||
+ stream < 0 || stream >= kNumStreams) {
+ msg.result = RESULT_INVALID_PARAMETER;
+ } else {
+ msg.arg1 = stream;
+ msg.arg2 = entry_->GetDataSize(stream);
+ msg.result = RESULT_OK;
+ }
+ SendMsg(msg);
+}
+
+void SlaveSM::DoReadData() {
+ DEBUGMSG("\t\t\tSlave DoReadData\n");
+ Message msg;
+ msg.command = READ_DATA;
+
+ int stream = input_->msg.arg1;
+ int size = input_->msg.arg2;
+ if (!entry_ || input_->msg.long_arg1 != reinterpret_cast<int64>(entry_) ||
+ stream < 0 || stream > 1 || size > kBufferSize) {
+ msg.result = RESULT_INVALID_PARAMETER;
+ } else {
+ int ret = entry_->ReadData(stream, input_->msg.arg3, output_->buffer, size,
+ NULL);
+
+ msg.buffer_bytes = (ret < 0) ? 0 : ret;
+ msg.result = RESULT_OK;
+ }
+ SendMsg(msg);
+}
+
+void SlaveSM::DoEnd() {
+ DEBUGMSG("\t\t\tSlave DoEnd\n");
+ MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+}
+
+void SlaveSM::Fail() {
+ DEBUGMSG("\t\t\tSlave Fail\n");
+ printf("Unexpected failure\n");
+ state_ = SLAVE_END;
+ if (IsPending()) {
+ CancelIo(channel_);
+ } else {
+ DoEnd();
+ }
+}
+
+} // namespace.
+
+// -----------------------------------------------------------------------
+
+HANDLE CreateServer(std::wstring* pipe_number) {
+ std::wstring pipe_name(kPipePrefix);
+ srand(static_cast<int>(base::Time::Now().ToInternalValue()));
+ *pipe_number = IntToWString(rand());
+ pipe_name.append(*pipe_number);
+
+ DWORD mode = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE |
+ FILE_FLAG_OVERLAPPED;
+
+ return CreateNamedPipe(pipe_name.c_str(), mode, 0, 1, kChannelSize,
+ kChannelSize, 0, NULL);
+}
+
+// This is the controller process for an upgrade operation.
+int Upgrade(const std::wstring output_path, HANDLE pipe) {
+ MessageLoop loop(MessageLoop::TYPE_IO);
+ disk_cache::BackendImpl cache(output_path);
+ if (!cache.Init()) {
+ printf("Unable to initialize new files\n");
+ return -1;
+ }
+
+ MasterSM master(&cache, pipe);
+ if (!master.DoInit()) {
+ printf("Unable to talk with the helper\n");
+ return -1;
+ }
+
+ loop.Run();
+ return 0;
+}
+
+// This process will only execute commands from the controller.
+int RunSlave(const std::wstring input_path, const std::wstring pipe_number) {
+ MessageLoop loop(MessageLoop::TYPE_IO);
+
+ ScopedHandle pipe(OpenServer(pipe_number));
+ if (!pipe.IsValid()) {
+ printf("Unable to open the server pipe\n");
+ return -1;
+ }
+
+ disk_cache::BackendImpl cache(input_path);
+ if (!cache.Init()) {
+ printf("Unable to open cache files\n");
+ return -1;
+ }
+ cache.SetUpgradeMode();
+
+ SlaveSM slave(&cache, pipe);
+ if (!slave.DoInit()) {
+ printf("Unable to talk with the main process\n");
+ return -1;
+ }
+
+ loop.Run();
+ return 0;
+}