- add sources.
[platform/framework/web/crosswalk.git] / src / content / child / fileapi / webfilewriter_base.cc
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                                      WebKit::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 WebKit::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(WebKit::WebFileErrorAbort);
151 }
152
153 }  // namespace content