OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "webkit/chromeos/fileapi/remote_file_system_operation.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/platform_file.h" | |
9 #include "base/utf_string_conversions.h" | |
10 #include "base/values.h" | |
11 #include "googleurl/src/gurl.h" | |
12 #include "net/url_request/url_request_context.h" | |
13 #include "webkit/browser/fileapi/file_system_url.h" | |
14 #include "webkit/browser/fileapi/file_writer_delegate.h" | |
15 #include "webkit/chromeos/fileapi/remote_file_stream_writer.h" | |
16 | |
17 using fileapi::FileSystemURL; | |
18 | |
19 namespace chromeos { | |
20 | |
21 RemoteFileSystemOperation::RemoteFileSystemOperation( | |
22 scoped_refptr<fileapi::RemoteFileSystemProxyInterface> remote_proxy) | |
23 : remote_proxy_(remote_proxy), | |
24 pending_operation_(kOperationNone) { | |
25 } | |
26 | |
27 RemoteFileSystemOperation::~RemoteFileSystemOperation() { | |
28 } | |
29 | |
30 void RemoteFileSystemOperation::GetMetadata(const FileSystemURL& url, | |
31 const GetMetadataCallback& callback) { | |
32 DCHECK(SetPendingOperationType(kOperationGetMetadata)); | |
33 remote_proxy_->GetFileInfo(url, | |
34 base::Bind(&RemoteFileSystemOperation::DidGetMetadata, | |
35 base::Owned(this), callback)); | |
36 } | |
37 | |
38 void RemoteFileSystemOperation::DirectoryExists(const FileSystemURL& url, | |
39 const StatusCallback& callback) { | |
40 DCHECK(SetPendingOperationType(kOperationDirectoryExists)); | |
41 remote_proxy_->GetFileInfo(url, | |
42 base::Bind(&RemoteFileSystemOperation::DidDirectoryExists, | |
43 base::Owned(this), callback)); | |
44 } | |
45 | |
46 void RemoteFileSystemOperation::FileExists(const FileSystemURL& url, | |
47 const StatusCallback& callback) { | |
48 DCHECK(SetPendingOperationType(kOperationFileExists)); | |
49 remote_proxy_->GetFileInfo(url, | |
50 base::Bind(base::Bind(&RemoteFileSystemOperation::DidFileExists, | |
51 base::Owned(this), callback))); | |
52 } | |
53 | |
54 void RemoteFileSystemOperation::ReadDirectory(const FileSystemURL& url, | |
55 const ReadDirectoryCallback& callback) { | |
56 DCHECK(SetPendingOperationType(kOperationReadDirectory)); | |
57 remote_proxy_->ReadDirectory(url, | |
58 base::Bind(&RemoteFileSystemOperation::DidReadDirectory, | |
59 base::Owned(this), callback)); | |
60 } | |
61 | |
62 void RemoteFileSystemOperation::Remove(const FileSystemURL& url, bool recursive, | |
63 const StatusCallback& callback) { | |
64 DCHECK(SetPendingOperationType(kOperationRemove)); | |
65 remote_proxy_->Remove(url, recursive, | |
66 base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation, | |
67 base::Owned(this), callback)); | |
68 } | |
69 | |
70 | |
71 void RemoteFileSystemOperation::CreateDirectory( | |
72 const FileSystemURL& url, bool exclusive, bool recursive, | |
73 const StatusCallback& callback) { | |
74 DCHECK(SetPendingOperationType(kOperationCreateDirectory)); | |
75 remote_proxy_->CreateDirectory(url, exclusive, recursive, | |
76 base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation, | |
77 base::Owned(this), callback)); | |
78 } | |
79 | |
80 void RemoteFileSystemOperation::CreateFile(const FileSystemURL& url, | |
81 bool exclusive, | |
82 const StatusCallback& callback) { | |
83 DCHECK(SetPendingOperationType(kOperationCreateFile)); | |
84 remote_proxy_->CreateFile(url, exclusive, | |
85 base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation, | |
86 base::Owned(this), callback)); | |
87 } | |
88 | |
89 void RemoteFileSystemOperation::Copy(const FileSystemURL& src_url, | |
90 const FileSystemURL& dest_url, | |
91 const StatusCallback& callback) { | |
92 DCHECK(SetPendingOperationType(kOperationCopy)); | |
93 | |
94 remote_proxy_->Copy(src_url, dest_url, | |
95 base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation, | |
96 base::Owned(this), callback)); | |
97 } | |
98 | |
99 void RemoteFileSystemOperation::Move(const FileSystemURL& src_url, | |
100 const FileSystemURL& dest_url, | |
101 const StatusCallback& callback) { | |
102 DCHECK(SetPendingOperationType(kOperationMove)); | |
103 | |
104 remote_proxy_->Move(src_url, dest_url, | |
105 base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation, | |
106 base::Owned(this), callback)); | |
107 } | |
108 | |
109 void RemoteFileSystemOperation::Write( | |
110 const net::URLRequestContext* url_request_context, | |
111 const FileSystemURL& url, | |
112 const GURL& blob_url, | |
113 int64 offset, | |
114 const WriteCallback& callback) { | |
115 DCHECK(SetPendingOperationType(kOperationWrite)); | |
116 DCHECK(write_callback_.is_null()); | |
117 | |
118 write_callback_ = callback; | |
119 file_writer_delegate_.reset( | |
120 new fileapi::FileWriterDelegate( | |
121 base::Bind(&RemoteFileSystemOperation::DidWrite, | |
122 // FileWriterDelegate is owned by |this|. So Unretained. | |
123 base::Unretained(this)), | |
124 scoped_ptr<fileapi::FileStreamWriter>( | |
125 new fileapi::RemoteFileStreamWriter(remote_proxy_, | |
126 url, | |
127 offset)))); | |
128 | |
129 scoped_ptr<net::URLRequest> blob_request(url_request_context->CreateRequest( | |
130 blob_url, file_writer_delegate_.get())); | |
131 | |
132 file_writer_delegate_->Start(blob_request.Pass()); | |
133 } | |
134 | |
135 void RemoteFileSystemOperation::Truncate(const FileSystemURL& url, | |
136 int64 length, | |
137 const StatusCallback& callback) { | |
138 DCHECK(SetPendingOperationType(kOperationTruncate)); | |
139 | |
140 remote_proxy_->Truncate(url, length, | |
141 base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation, | |
142 base::Owned(this), callback)); | |
143 } | |
144 | |
145 void RemoteFileSystemOperation::Cancel(const StatusCallback& cancel_callback) { | |
146 if (file_writer_delegate_) { | |
147 DCHECK_EQ(kOperationWrite, pending_operation_); | |
148 | |
149 // Writes are done without proxying through FileUtilProxy after the initial | |
150 // opening of the PlatformFile. All state changes are done on this thread, | |
151 // so we're guaranteed to be able to shut down atomically. | |
152 const bool delete_now = file_writer_delegate_->Cancel(); | |
153 | |
154 if (!write_callback_.is_null()) { | |
155 // Notify the failure status to the ongoing operation's callback. | |
156 write_callback_.Run(base::PLATFORM_FILE_ERROR_ABORT, 0, false); | |
157 } | |
158 cancel_callback.Run(base::PLATFORM_FILE_OK); | |
159 write_callback_.Reset(); | |
160 | |
161 if (delete_now) { | |
162 delete this; | |
163 return; | |
164 } | |
165 } else { | |
166 DCHECK_EQ(kOperationTruncate, pending_operation_); | |
167 // We're cancelling a truncate operation, but we can't actually stop it | |
168 // since it's been proxied to another thread. We need to save the | |
169 // cancel_callback so that when the truncate returns, it can see that it's | |
170 // been cancelled, report it, and report that the cancel has succeeded. | |
171 DCHECK(cancel_callback_.is_null()); | |
172 cancel_callback_ = cancel_callback; | |
173 } | |
174 } | |
175 | |
176 void RemoteFileSystemOperation::TouchFile(const FileSystemURL& url, | |
177 const base::Time& last_access_time, | |
178 const base::Time& last_modified_time, | |
179 const StatusCallback& callback) { | |
180 DCHECK(SetPendingOperationType(kOperationTouchFile)); | |
181 remote_proxy_->TouchFile( | |
182 url, | |
183 last_access_time, | |
184 last_modified_time, | |
185 base::Bind(&RemoteFileSystemOperation::DidFinishFileOperation, | |
186 base::Owned(this), callback)); | |
187 } | |
188 | |
189 void RemoteFileSystemOperation::OpenFile(const FileSystemURL& url, | |
190 int file_flags, | |
191 base::ProcessHandle peer_handle, | |
192 const OpenFileCallback& callback) { | |
193 DCHECK(SetPendingOperationType(kOperationOpenFile)); | |
194 remote_proxy_->OpenFile( | |
195 url, | |
196 file_flags, | |
197 peer_handle, | |
198 base::Bind(&RemoteFileSystemOperation::DidOpenFile, | |
199 base::Owned(this), url, callback)); | |
200 } | |
201 | |
202 fileapi::LocalFileSystemOperation* | |
203 RemoteFileSystemOperation::AsLocalFileSystemOperation() { | |
204 NOTIMPLEMENTED(); | |
205 return NULL; | |
206 } | |
207 | |
208 void RemoteFileSystemOperation::CreateSnapshotFile( | |
209 const FileSystemURL& url, | |
210 const SnapshotFileCallback& callback) { | |
211 DCHECK(SetPendingOperationType(kOperationCreateSnapshotFile)); | |
212 remote_proxy_->CreateSnapshotFile( | |
213 url, | |
214 base::Bind(&RemoteFileSystemOperation::DidCreateSnapshotFile, | |
215 base::Owned(this), callback)); | |
216 } | |
217 | |
218 bool RemoteFileSystemOperation::SetPendingOperationType(OperationType type) { | |
219 if (pending_operation_ != kOperationNone) | |
220 return false; | |
221 pending_operation_ = type; | |
222 return true; | |
223 } | |
224 | |
225 void RemoteFileSystemOperation::DidDirectoryExists( | |
226 const StatusCallback& callback, | |
227 base::PlatformFileError rv, | |
228 const base::PlatformFileInfo& file_info, | |
229 const base::FilePath& unused) { | |
230 if (rv == base::PLATFORM_FILE_OK && !file_info.is_directory) | |
231 rv = base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; | |
232 callback.Run(rv); | |
233 } | |
234 | |
235 void RemoteFileSystemOperation::DidFileExists( | |
236 const StatusCallback& callback, | |
237 base::PlatformFileError rv, | |
238 const base::PlatformFileInfo& file_info, | |
239 const base::FilePath& unused) { | |
240 if (rv == base::PLATFORM_FILE_OK && file_info.is_directory) | |
241 rv = base::PLATFORM_FILE_ERROR_NOT_A_FILE; | |
242 callback.Run(rv); | |
243 } | |
244 | |
245 void RemoteFileSystemOperation::DidGetMetadata( | |
246 const GetMetadataCallback& callback, | |
247 base::PlatformFileError rv, | |
248 const base::PlatformFileInfo& file_info, | |
249 const base::FilePath& platform_path) { | |
250 callback.Run(rv, file_info, platform_path); | |
251 } | |
252 | |
253 void RemoteFileSystemOperation::DidReadDirectory( | |
254 const ReadDirectoryCallback& callback, | |
255 base::PlatformFileError rv, | |
256 const std::vector<fileapi::DirectoryEntry>& entries, | |
257 bool has_more) { | |
258 callback.Run(rv, entries, has_more /* has_more */); | |
259 } | |
260 | |
261 void RemoteFileSystemOperation::DidWrite( | |
262 base::PlatformFileError rv, | |
263 int64 bytes, | |
264 FileWriterDelegate::WriteProgressStatus write_status) { | |
265 if (write_callback_.is_null()) { | |
266 // If cancelled, callback is already invoked and set to null in Cancel(). | |
267 // We must not call it twice. Just shut down this operation object. | |
268 delete this; | |
269 return; | |
270 } | |
271 | |
272 bool complete = (write_status != FileWriterDelegate::SUCCESS_IO_PENDING); | |
273 write_callback_.Run(rv, bytes, complete); | |
274 if (rv != base::PLATFORM_FILE_OK || complete) { | |
275 // Other Did*'s doesn't have "delete this", because it is automatic since | |
276 // they are base::Owned by the caller of the callback. For DidWrite, the | |
277 // owner is file_writer_delegate_ which itself is owned by this Operation | |
278 // object. Hence we need manual life time management here. | |
279 // TODO(kinaba): think about refactoring FileWriterDelegate to be self | |
280 // destructing, for avoiding the manual management. | |
281 delete this; | |
282 } | |
283 } | |
284 | |
285 void RemoteFileSystemOperation::DidFinishFileOperation( | |
286 const StatusCallback& callback, | |
287 base::PlatformFileError rv) { | |
288 if (!cancel_callback_.is_null()) { | |
289 DCHECK_EQ(kOperationTruncate, pending_operation_); | |
290 | |
291 callback.Run(base::PLATFORM_FILE_ERROR_ABORT); | |
292 cancel_callback_.Run(base::PLATFORM_FILE_OK); | |
293 cancel_callback_.Reset(); | |
294 } else { | |
295 callback.Run(rv); | |
296 } | |
297 } | |
298 | |
299 void RemoteFileSystemOperation::DidCreateSnapshotFile( | |
300 const SnapshotFileCallback& callback, | |
301 base::PlatformFileError result, | |
302 const base::PlatformFileInfo& file_info, | |
303 const base::FilePath& platform_path, | |
304 const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) { | |
305 callback.Run(result, file_info, platform_path, file_ref); | |
306 } | |
307 | |
308 void RemoteFileSystemOperation::DidOpenFile( | |
309 const fileapi::FileSystemURL& url, | |
310 const OpenFileCallback& callback, | |
311 base::PlatformFileError result, | |
312 base::PlatformFile file, | |
313 base::ProcessHandle peer_handle) { | |
314 callback.Run( | |
315 result, file, | |
316 base::Bind(&fileapi::RemoteFileSystemProxyInterface::NotifyCloseFile, | |
317 remote_proxy_, url), | |
318 peer_handle); | |
319 } | |
320 | |
321 } // namespace chromeos | |
OLD | NEW |