upgrade.cc revision c7f5f8508d98d5952d42ed7648c2a8f30a4da156
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
19namespace {
20
21const wchar_t kPipePrefix[] = L"\\\\.\\pipe\\dump_cache_";
22const int kChannelSize = 64 * 1024;
23const 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
33HANDLE 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.
44struct 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;
57  Message() {
58    memset(this, 0, sizeof(*this));
59  }
60  Message& operator= (const Message& other) {
61    memcpy(this, &other, sizeof(*this));
62    return *this;
63  }
64};
65
66const int kBufferSize = kChannelSize - sizeof(Message);
67struct IoBuffer {
68  Message msg;
69  char buffer[kBufferSize];
70};
71COMPILE_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.
76enum {
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.
101enum {
102  RESULT_OK = 0,
103  RESULT_UNKNOWN_COMMAND,
104  RESULT_INVALID_PARAMETER,
105  RESULT_NAME_OVERFLOW
106};
107
108// -----------------------------------------------------------------------
109
110class 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
134BaseSM::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
148BaseSM::~BaseSM() {
149  if (entry_)
150    entry_->Close();
151}
152
153bool 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
170bool 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
181bool 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
195bool BaseSM::IsPending() {
196  return pending_count_ != 0;
197}
198
199// -----------------------------------------------------------------------
200
201class MasterSM : public BaseSM {
202 public:
203   MasterSM(const std::wstring& path, HANDLE channel, bool dump_to_disk)
204      : BaseSM(channel), path_(path), dump_to_disk_(dump_to_disk) {
205  }
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
253void 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
298bool 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
328void 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
337void 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
356void 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
392void 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
405void 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
415void 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
431void 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
440void 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
461void 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
486void 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
496void MasterSM::DoEnd() {
497  DEBUGMSG("Master DoEnd\n");
498  MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
499}
500
501void MasterSM::Fail() {
502  DEBUGMSG("Master Fail\n");
503  printf("Unexpected failure\n");
504  SendQuit();
505}
506
507// -----------------------------------------------------------------------
508
509class SlaveSM : public BaseSM {
510 public:
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
549SlaveSM::~SlaveSM() {
550  if (iterator_)
551    cache_->EndEnumeration(&iterator_);
552}
553
554void 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
607bool SlaveSM::DoInit() {
608  DEBUGMSG("\t\t\tSlave DoInit\n");
609  DCHECK(state_ == SLAVE_INITIAL);
610  state_ = SLAVE_WAITING;
611  return ReceiveMsg();
612}
613
614void 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
629void 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.
645int32 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
673void 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
689void 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
711void 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
726void 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
743void 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
764void SlaveSM::DoEnd() {
765  DEBUGMSG("\t\t\tSlave DoEnd\n");
766  MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
767}
768
769void 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
784HANDLE 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.
798int 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.
812int 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