Home | History | Annotate | Download | only in fileapi
      1 // Copyright 2013 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 "content/child/fileapi/webfilewriter_base.h"
      6 
      7 #include "base/logging.h"
      8 #include "third_party/WebKit/public/platform/WebFileError.h"
      9 #include "third_party/WebKit/public/platform/WebFileWriterClient.h"
     10 #include "third_party/WebKit/public/platform/WebURL.h"
     11 #include "webkit/common/fileapi/file_system_util.h"
     12 
     13 using fileapi::PlatformFileErrorToWebFileError;
     14 
     15 namespace content {
     16 
     17 WebFileWriterBase::WebFileWriterBase(const GURL& path,
     18                                      blink::WebFileWriterClient* client)
     19     : path_(path),
     20       client_(client),
     21       operation_(kOperationNone),
     22       cancel_state_(kCancelNotInProgress) {}
     23 
     24 WebFileWriterBase::~WebFileWriterBase() {}
     25 
     26 void WebFileWriterBase::truncate(long long length) {
     27   DCHECK(kOperationNone == operation_);
     28   DCHECK(kCancelNotInProgress == cancel_state_);
     29   operation_ = kOperationTruncate;
     30   DoTruncate(path_, length);
     31 }
     32 
     33 void WebFileWriterBase::write(
     34       long long position,
     35       const blink::WebString& id) {
     36   DCHECK_EQ(kOperationNone, operation_);
     37   DCHECK_EQ(kCancelNotInProgress, cancel_state_);
     38   operation_ = kOperationWrite;
     39   DoWrite(path_, id.utf8(), position);
     40 }
     41 
     42 // When we cancel a write/truncate, we always get back the result of the write
     43 // before the result of the cancel, no matter what happens.
     44 // So we'll get back either
     45 //   success [of the write/truncate, in a DidWrite(XXX, true)/DidSucceed() call]
     46 //     followed by failure [of the cancel]; or
     47 //   failure [of the write, either from cancel or other reasons] followed by
     48 //     the result of the cancel.
     49 // In the write case, there could also be queued up non-terminal DidWrite calls
     50 // before any of that comes back, but there will always be a terminal write
     51 // response [success or failure] after them, followed by the cancel result, so
     52 // we can ignore non-terminal write responses, take the terminal write success
     53 // or the first failure as the last write response, then know that the next
     54 // thing to come back is the cancel response.  We only notify the
     55 // AsyncFileWriterClient when it's all over.
     56 void WebFileWriterBase::cancel() {
     57   // Check for the cancel passing the previous operation's return in-flight.
     58   if (kOperationWrite != operation_ && kOperationTruncate != operation_)
     59     return;
     60   if (kCancelNotInProgress != cancel_state_)
     61     return;
     62   cancel_state_ = kCancelSent;
     63   DoCancel();
     64 }
     65 
     66 void WebFileWriterBase::DidFinish(base::PlatformFileError error_code) {
     67   if (error_code == base::PLATFORM_FILE_OK)
     68     DidSucceed();
     69   else
     70     DidFail(error_code);
     71 }
     72 
     73 void WebFileWriterBase::DidWrite(int64 bytes, bool complete) {
     74   DCHECK(kOperationWrite == operation_);
     75   switch (cancel_state_) {
     76     case kCancelNotInProgress:
     77       if (complete)
     78         operation_ = kOperationNone;
     79       client_->didWrite(bytes, complete);
     80       break;
     81     case kCancelSent:
     82       // This is the success call of the write, which we'll eat, even though
     83       // it succeeded before the cancel got there.  We accepted the cancel call,
     84       // so the write will eventually return an error.
     85       if (complete)
     86         cancel_state_ = kCancelReceivedWriteResponse;
     87       break;
     88     case kCancelReceivedWriteResponse:
     89     default:
     90       NOTREACHED();
     91   }
     92 }
     93 
     94 void WebFileWriterBase::DidSucceed() {
     95   // Write never gets a DidSucceed call, so this is either a cancel or truncate
     96   // response.
     97   switch (cancel_state_) {
     98     case kCancelNotInProgress:
     99       // A truncate succeeded, with no complications.
    100       DCHECK(kOperationTruncate == operation_);
    101       operation_ = kOperationNone;
    102       client_->didTruncate();
    103       break;
    104     case kCancelSent:
    105       DCHECK(kOperationTruncate == operation_);
    106       // This is the success call of the truncate, which we'll eat, even though
    107       // it succeeded before the cancel got there.  We accepted the cancel call,
    108       // so the truncate will eventually return an error.
    109       cancel_state_ = kCancelReceivedWriteResponse;
    110       break;
    111     case kCancelReceivedWriteResponse:
    112       // This is the success of the cancel operation.
    113       FinishCancel();
    114       break;
    115     default:
    116       NOTREACHED();
    117   }
    118 }
    119 
    120 void WebFileWriterBase::DidFail(base::PlatformFileError error_code) {
    121   DCHECK(kOperationNone != operation_);
    122   switch (cancel_state_) {
    123     case kCancelNotInProgress:
    124       // A write or truncate failed.
    125       operation_ = kOperationNone;
    126       client_->didFail(PlatformFileErrorToWebFileError(error_code));
    127       break;
    128     case kCancelSent:
    129       // This is the failure of a write or truncate; the next message should be
    130       // the result of the cancel.  We don't assume that it'll be a success, as
    131       // the write/truncate could have failed for other reasons.
    132       cancel_state_ = kCancelReceivedWriteResponse;
    133       break;
    134     case kCancelReceivedWriteResponse:
    135       // The cancel reported failure, meaning that the write or truncate
    136       // finished before the cancel got there.  But we suppressed the
    137       // write/truncate's response, and will now report that it was cancelled.
    138       FinishCancel();
    139       break;
    140     default:
    141       NOTREACHED();
    142   }
    143 }
    144 
    145 void WebFileWriterBase::FinishCancel() {
    146   DCHECK(kCancelReceivedWriteResponse == cancel_state_);
    147   DCHECK(kOperationNone != operation_);
    148   cancel_state_ = kCancelNotInProgress;
    149   operation_ = kOperationNone;
    150   client_->didFail(blink::WebFileErrorAbort);
    151 }
    152 
    153 }  // namespace content
    154