13551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "content/child/fileapi/webfilewriter_base.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/common/fileapi/file_system_util.h"
958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "third_party/WebKit/public/platform/WebFileError.h"
1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "third_party/WebKit/public/platform/WebFileWriterClient.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebURL.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using storage::FileErrorToWebFileError;
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)namespace content {
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)WebFileWriterBase::WebFileWriterBase(const GURL& path,
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                     blink::WebFileWriterClient* client)
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    : path_(path),
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      client_(client),
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      operation_(kOperationNone),
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      cancel_state_(kCancelNotInProgress) {}
233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)WebFileWriterBase::~WebFileWriterBase() {}
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebFileWriterBase::truncate(long long length) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kOperationNone == operation_);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kCancelNotInProgress == cancel_state_);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  operation_ = kOperationTruncate;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoTruncate(path_, length);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void WebFileWriterBase::write(
3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      long long position,
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const blink::WebString& id) {
3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK_EQ(kOperationNone, operation_);
3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DCHECK_EQ(kCancelNotInProgress, cancel_state_);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  operation_ = kOperationWrite;
3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  DoWrite(path_, id.utf8(), position);
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// When we cancel a write/truncate, we always get back the result of the write
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before the result of the cancel, no matter what happens.
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// So we'll get back either
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   success [of the write/truncate, in a DidWrite(XXX, true)/DidSucceed() call]
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     followed by failure [of the cancel]; or
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   failure [of the write, either from cancel or other reasons] followed by
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     the result of the cancel.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In the write case, there could also be queued up non-terminal DidWrite calls
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// before any of that comes back, but there will always be a terminal write
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// response [success or failure] after them, followed by the cancel result, so
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we can ignore non-terminal write responses, take the terminal write success
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// or the first failure as the last write response, then know that the next
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thing to come back is the cancel response.  We only notify the
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AsyncFileWriterClient when it's all over.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebFileWriterBase::cancel() {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check for the cancel passing the previous operation's return in-flight.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kOperationWrite != operation_ && kOperationTruncate != operation_)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (kCancelNotInProgress != cancel_state_)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cancel_state_ = kCancelSent;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DoCancel();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebFileWriterBase::DidFinish(base::File::Error error_code) {
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error_code == base::File::FILE_OK)
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DidSucceed();
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  else
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    DidFail(error_code);
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void WebFileWriterBase::DidWrite(int64 bytes, bool complete) {
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DCHECK(kOperationWrite == operation_);
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (cancel_state_) {
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case kCancelNotInProgress:
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (complete)
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        operation_ = kOperationNone;
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      client_->didWrite(bytes, complete);
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case kCancelSent:
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // This is the success call of the write, which we'll eat, even though
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // it succeeded before the cancel got there.  We accepted the cancel call,
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      // so the write will eventually return an error.
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      if (complete)
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)        cancel_state_ = kCancelReceivedWriteResponse;
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    case kCancelReceivedWriteResponse:
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    default:
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      NOTREACHED();
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebFileWriterBase::DidSucceed() {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Write never gets a DidSucceed call, so this is either a cancel or truncate
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // response.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (cancel_state_) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCancelNotInProgress:
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A truncate succeeded, with no complications.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(kOperationTruncate == operation_);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      operation_ = kOperationNone;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_->didTruncate();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCancelSent:
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(kOperationTruncate == operation_);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is the success call of the truncate, which we'll eat, even though
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // it succeeded before the cancel got there.  We accepted the cancel call,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // so the truncate will eventually return an error.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cancel_state_ = kCancelReceivedWriteResponse;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCancelReceivedWriteResponse:
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is the success of the cancel operation.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FinishCancel();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebFileWriterBase::DidFail(base::File::Error error_code) {
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kOperationNone != operation_);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (cancel_state_) {
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCancelNotInProgress:
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // A write or truncate failed.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      operation_ = kOperationNone;
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      client_->didFail(FileErrorToWebFileError(error_code));
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCancelSent:
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is the failure of a write or truncate; the next message should be
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the result of the cancel.  We don't assume that it'll be a success, as
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // the write/truncate could have failed for other reasons.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      cancel_state_ = kCancelReceivedWriteResponse;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case kCancelReceivedWriteResponse:
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The cancel reported failure, meaning that the write or truncate
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // finished before the cancel got there.  But we suppressed the
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // write/truncate's response, and will now report that it was cancelled.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FinishCancel();
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WebFileWriterBase::FinishCancel() {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kCancelReceivedWriteResponse == cancel_state_);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(kOperationNone != operation_);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cancel_state_ = kCancelNotInProgress;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  operation_ = kOperationNone;
150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  client_->didFail(blink::WebFileErrorAbort);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}  // namespace content
154