blob: be6465d42ad0f7093886d7318ac47210f556d1ae [file] [log] [blame]
finnur@chromium.org899d4e02011-03-15 18:56:27 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
dumi@chromium.orgc980e402010-08-21 07:42:50 +09002// 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_util_proxy.h"
6
dumi@chromium.orgc980e402010-08-21 07:42:50 +09007#include "base/message_loop_proxy.h"
8
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +09009// TODO(jianli): Move the code from anonymous namespace to base namespace so
10// that all of the base:: prefixes would be unnecessary.
dumi@chromium.orgc980e402010-08-21 07:42:50 +090011namespace {
12
kinuko@chromium.org1a078042010-10-07 17:35:09 +090013namespace {
14
15// Performs common checks for move and copy.
16// This also removes the destination directory if it's non-empty and all other
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +090017// checks are passed (so that the copy/move correctly overwrites the
18// destination).
kinuko@chromium.org1a078042010-10-07 17:35:09 +090019static base::PlatformFileError PerformCommonCheckAndPreparationForMoveAndCopy(
20 const FilePath& src_file_path,
21 const FilePath& dest_file_path) {
22 // Exits earlier if the source path does not exist.
23 if (!file_util::PathExists(src_file_path))
24 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
25
26 // The parent of the |dest_file_path| does not exist.
27 if (!file_util::DirectoryExists(dest_file_path.DirName()))
28 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
29
30 // It is an error to try to copy/move an entry into its child.
31 if (src_file_path.IsParent(dest_file_path))
32 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
33
34 // Now it is ok to return if the |dest_file_path| does not exist.
35 if (!file_util::PathExists(dest_file_path))
36 return base::PLATFORM_FILE_OK;
37
38 // |src_file_path| exists and is a directory.
39 // |dest_file_path| exists and is a file.
40 bool src_is_directory = file_util::DirectoryExists(src_file_path);
41 bool dest_is_directory = file_util::DirectoryExists(dest_file_path);
42 if (src_is_directory && !dest_is_directory)
43 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
44
45 // |src_file_path| exists and is a file.
46 // |dest_file_path| exists and is a directory.
47 if (!src_is_directory && dest_is_directory)
48 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
49
50 // It is an error to copy/move an entry into the same path.
51 if (src_file_path.value() == dest_file_path.value())
52 return base::PLATFORM_FILE_ERROR_EXISTS;
53
54 if (dest_is_directory) {
55 // It is an error to copy/move an entry to a non-empty directory.
56 // Otherwise the copy/move attempt must overwrite the destination, but
57 // the file_util's Copy or Move method doesn't perform overwrite
58 // on all platforms, so we delete the destination directory here.
59 // TODO(kinuko): may be better to change the file_util::{Copy,Move}.
60 if (!file_util::Delete(dest_file_path, false /* recursive */)) {
61 if (!file_util::IsDirectoryEmpty(dest_file_path))
62 return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
63 return base::PLATFORM_FILE_ERROR_FAILED;
64 }
65 }
66 return base::PLATFORM_FILE_OK;
67}
68
kkanetkar@chromium.org48710682010-11-03 05:36:52 +090069} // anonymous namespace
kinuko@chromium.org1a078042010-10-07 17:35:09 +090070
dumi@chromium.orgc980e402010-08-21 07:42:50 +090071class MessageLoopRelay
72 : public base::RefCountedThreadSafe<MessageLoopRelay> {
73 public:
74 MessageLoopRelay()
75 : origin_message_loop_proxy_(
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +090076 base::MessageLoopProxy::CreateForCurrentThread()),
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +090077 error_code_(base::PLATFORM_FILE_OK) {
dumi@chromium.orgc980e402010-08-21 07:42:50 +090078 }
79
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +090080 bool Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
dumi@chromium.orgc980e402010-08-21 07:42:50 +090081 const tracked_objects::Location& from_here) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +090082 return message_loop_proxy->PostTask(
dumi@chromium.orgc980e402010-08-21 07:42:50 +090083 from_here,
84 NewRunnableMethod(this, &MessageLoopRelay::ProcessOnTargetThread));
85 }
86
87 protected:
88 friend class base::RefCountedThreadSafe<MessageLoopRelay>;
89 virtual ~MessageLoopRelay() {}
90
91 // Called to perform work on the FILE thread.
92 virtual void RunWork() = 0;
93
94 // Called to notify the callback on the origin thread.
95 virtual void RunCallback() = 0;
96
dumi@chromium.org50f197d2010-09-01 04:30:27 +090097 void set_error_code(base::PlatformFileError error_code) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +090098 error_code_ = error_code;
99 }
100
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900101 base::PlatformFileError error_code() const {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900102 return error_code_;
103 }
104
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900105 private:
106 void ProcessOnTargetThread() {
107 RunWork();
108 origin_message_loop_proxy_->PostTask(
109 FROM_HERE,
110 NewRunnableMethod(this, &MessageLoopRelay::RunCallback));
111 }
112
113 scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_;
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900114 base::PlatformFileError error_code_;
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900115};
116
117class RelayCreateOrOpen : public MessageLoopRelay {
118 public:
119 RelayCreateOrOpen(
120 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
121 const FilePath& file_path,
122 int file_flags,
123 base::FileUtilProxy::CreateOrOpenCallback* callback)
124 : message_loop_proxy_(message_loop_proxy),
125 file_path_(file_path),
126 file_flags_(file_flags),
127 callback_(callback),
128 file_handle_(base::kInvalidPlatformFileValue),
129 created_(false) {
130 DCHECK(callback);
131 }
132
133 protected:
134 virtual ~RelayCreateOrOpen() {
135 if (file_handle_ != base::kInvalidPlatformFileValue)
136 base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
137 }
138
139 virtual void RunWork() {
kinuko@chromium.orgaf334b22010-10-12 11:17:14 +0900140 if (!file_util::DirectoryExists(file_path_.DirName())) {
141 // If its parent does not exist, should return NOT_FOUND error.
142 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
143 return;
144 }
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900145 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
146 file_handle_ = base::CreatePlatformFile(file_path_, file_flags_,
147 &created_, &error_code);
148 set_error_code(error_code);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900149 }
150
151 virtual void RunCallback() {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900152 callback_->Run(error_code(), base::PassPlatformFile(&file_handle_),
153 created_);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900154 delete callback_;
155 }
156
157 private:
158 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
159 FilePath file_path_;
160 int file_flags_;
161 base::FileUtilProxy::CreateOrOpenCallback* callback_;
162 base::PlatformFile file_handle_;
163 bool created_;
164};
165
166class RelayCreateTemporary : public MessageLoopRelay {
167 public:
168 RelayCreateTemporary(
169 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
noelutz@google.comf56dab22011-06-14 05:29:50 +0900170 int additional_file_flags,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900171 base::FileUtilProxy::CreateTemporaryCallback* callback)
172 : message_loop_proxy_(message_loop_proxy),
noelutz@google.comf56dab22011-06-14 05:29:50 +0900173 additional_file_flags_(additional_file_flags),
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900174 callback_(callback),
175 file_handle_(base::kInvalidPlatformFileValue) {
176 DCHECK(callback);
177 }
178
179 protected:
180 virtual ~RelayCreateTemporary() {
181 if (file_handle_ != base::kInvalidPlatformFileValue)
182 base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
183 }
184
185 virtual void RunWork() {
186 // TODO(darin): file_util should have a variant of CreateTemporaryFile
187 // that returns a FilePath and a PlatformFile.
188 file_util::CreateTemporaryFile(&file_path_);
189
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900190 int file_flags =
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900191 base::PLATFORM_FILE_WRITE |
noelutz@google.comf56dab22011-06-14 05:29:50 +0900192 base::PLATFORM_FILE_TEMPORARY |
193 base::PLATFORM_FILE_CREATE_ALWAYS |
194 additional_file_flags_;
195
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900196 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
197 file_handle_ = base::CreatePlatformFile(file_path_, file_flags,
198 NULL, &error_code);
199 set_error_code(error_code);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900200 }
201
202 virtual void RunCallback() {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900203 callback_->Run(error_code(), base::PassPlatformFile(&file_handle_),
204 file_path_);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900205 delete callback_;
206 }
207
208 private:
209 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
noelutz@google.comf56dab22011-06-14 05:29:50 +0900210 int additional_file_flags_;
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900211 base::FileUtilProxy::CreateTemporaryCallback* callback_;
212 base::PlatformFile file_handle_;
213 FilePath file_path_;
214};
215
216class RelayWithStatusCallback : public MessageLoopRelay {
217 public:
218 explicit RelayWithStatusCallback(
219 base::FileUtilProxy::StatusCallback* callback)
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900220 : callback_(callback) {
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900221 // It is OK for callback to be NULL.
222 }
223
224 protected:
225 virtual void RunCallback() {
226 // The caller may not have been interested in the result.
227 if (callback_) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900228 callback_->Run(error_code());
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900229 delete callback_;
230 }
231 }
232
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900233 private:
234 base::FileUtilProxy::StatusCallback* callback_;
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900235};
236
237class RelayClose : public RelayWithStatusCallback {
238 public:
239 RelayClose(base::PlatformFile file_handle,
240 base::FileUtilProxy::StatusCallback* callback)
241 : RelayWithStatusCallback(callback),
242 file_handle_(file_handle) {
243 }
244
245 protected:
246 virtual void RunWork() {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900247 if (!base::ClosePlatformFile(file_handle_))
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900248 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900249 }
250
251 private:
252 base::PlatformFile file_handle_;
253};
254
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900255class RelayEnsureFileExists : public MessageLoopRelay {
256 public:
257 RelayEnsureFileExists(
258 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
259 const FilePath& file_path,
260 base::FileUtilProxy::EnsureFileExistsCallback* callback)
261 : message_loop_proxy_(message_loop_proxy),
262 file_path_(file_path),
263 callback_(callback),
264 created_(false) {
265 DCHECK(callback);
266 }
267
268 protected:
269 virtual void RunWork() {
270 if (!file_util::DirectoryExists(file_path_.DirName())) {
271 // If its parent does not exist, should return NOT_FOUND error.
272 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
273 return;
274 }
275 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
276 // Tries to create the |file_path_| exclusively. This should fail
277 // with PLATFORM_FILE_ERROR_EXISTS if the path already exists.
278 base::PlatformFile handle = base::CreatePlatformFile(
279 file_path_,
280 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ,
281 &created_, &error_code);
282 if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) {
283 // Make sure created_ is false.
284 created_ = false;
285 error_code = base::PLATFORM_FILE_OK;
286 }
287 if (handle != base::kInvalidPlatformFileValue)
288 base::ClosePlatformFile(handle);
289 set_error_code(error_code);
290 }
291
292 virtual void RunCallback() {
293 callback_->Run(error_code(), created_);
294 delete callback_;
295 }
296
297 private:
298 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
299 FilePath file_path_;
300 base::FileUtilProxy::EnsureFileExistsCallback* callback_;
301 bool created_;
302};
303
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900304class RelayDelete : public RelayWithStatusCallback {
305 public:
306 RelayDelete(const FilePath& file_path,
307 bool recursive,
308 base::FileUtilProxy::StatusCallback* callback)
309 : RelayWithStatusCallback(callback),
310 file_path_(file_path),
311 recursive_(recursive) {
312 }
313
314 protected:
315 virtual void RunWork() {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900316 if (!file_util::PathExists(file_path_)) {
317 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
318 return;
319 }
320 if (!file_util::Delete(file_path_, recursive_)) {
321 if (!recursive_ && !file_util::IsDirectoryEmpty(file_path_)) {
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900322 set_error_code(base::PLATFORM_FILE_ERROR_NOT_EMPTY);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900323 return;
324 }
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900325 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900326 }
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900327 }
328
329 private:
330 FilePath file_path_;
331 bool recursive_;
332};
333
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900334class RelayCopy : public RelayWithStatusCallback {
335 public:
336 RelayCopy(const FilePath& src_file_path,
337 const FilePath& dest_file_path,
338 base::FileUtilProxy::StatusCallback* callback)
339 : RelayWithStatusCallback(callback),
340 src_file_path_(src_file_path),
341 dest_file_path_(dest_file_path) {
342 }
343
344 protected:
345 virtual void RunWork() {
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900346 set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy(
347 src_file_path_, dest_file_path_));
348 if (error_code() != base::PLATFORM_FILE_OK)
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900349 return;
kinuko@chromium.org31583c32010-10-07 06:44:35 +0900350 if (!file_util::CopyDirectory(src_file_path_, dest_file_path_,
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900351 true /* recursive */))
kinuko@chromium.org31583c32010-10-07 06:44:35 +0900352 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900353 }
354
355 private:
356 FilePath src_file_path_;
357 FilePath dest_file_path_;
358};
359
360class RelayMove : public RelayWithStatusCallback {
361 public:
362 RelayMove(const FilePath& src_file_path,
363 const FilePath& dest_file_path,
364 base::FileUtilProxy::StatusCallback* callback)
365 : RelayWithStatusCallback(callback),
366 src_file_path_(src_file_path),
367 dest_file_path_(dest_file_path) {
368 }
369
370 protected:
371 virtual void RunWork() {
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900372 set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy(
373 src_file_path_, dest_file_path_));
374 if (error_code() != base::PLATFORM_FILE_OK)
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900375 return;
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900376 if (!file_util::Move(src_file_path_, dest_file_path_))
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900377 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900378 }
379
380 private:
381 FilePath src_file_path_;
382 FilePath dest_file_path_;
383};
384
385class RelayCreateDirectory : public RelayWithStatusCallback {
386 public:
387 RelayCreateDirectory(
388 const FilePath& file_path,
389 bool exclusive,
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900390 bool recursive,
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900391 base::FileUtilProxy::StatusCallback* callback)
392 : RelayWithStatusCallback(callback),
393 file_path_(file_path),
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900394 exclusive_(exclusive),
395 recursive_(recursive) {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900396 }
397
398 protected:
399 virtual void RunWork() {
400 bool path_exists = file_util::PathExists(file_path_);
401 // If parent dir of file doesn't exist.
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900402 if (!recursive_ && !file_util::PathExists(file_path_.DirName())) {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900403 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
404 return;
405 }
406 if (exclusive_ && path_exists) {
407 set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
408 return;
409 }
410 // If file exists at the path.
411 if (path_exists && !file_util::DirectoryExists(file_path_)) {
412 set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
413 return;
414 }
415 if (!file_util::CreateDirectory(file_path_))
416 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
417 }
418
419 private:
420 FilePath file_path_;
421 bool exclusive_;
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900422 bool recursive_;
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900423};
424
425class RelayReadDirectory : public MessageLoopRelay {
426 public:
427 RelayReadDirectory(const FilePath& file_path,
428 base::FileUtilProxy::ReadDirectoryCallback* callback)
429 : callback_(callback), file_path_(file_path) {
430 DCHECK(callback);
431 }
432
433 protected:
434 virtual void RunWork() {
435 // TODO(kkanetkar): Implement directory read in multiple chunks.
436 if (!file_util::DirectoryExists(file_path_)) {
437 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
438 return;
439 }
440
441 file_util::FileEnumerator file_enum(
tfarina@chromium.orga3a4db72011-08-15 22:09:27 +0900442 file_path_, false, static_cast<file_util::FileEnumerator::FileType>(
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900443 file_util::FileEnumerator::FILES |
444 file_util::FileEnumerator::DIRECTORIES));
445 FilePath current;
446 while (!(current = file_enum.Next()).empty()) {
kkanetkar@chromium.org48710682010-11-03 05:36:52 +0900447 base::FileUtilProxy::Entry entry;
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900448 file_util::FileEnumerator::FindInfo info;
449 file_enum.GetFindInfo(&info);
kinuko@chromium.org83604d12010-09-03 07:28:49 +0900450 entry.is_directory = file_enum.IsDirectory(info);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900451 // This will just give the entry's name instead of entire path
452 // if we use current.value().
453 entry.name = file_util::FileEnumerator::GetFilename(info).value();
tzik@chromium.org09987c32011-07-19 14:03:03 +0900454 entry.size = file_util::FileEnumerator::GetFilesize(info);
455 entry.last_modified_time =
456 file_util::FileEnumerator::GetLastModifiedTime(info);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900457 entries_.push_back(entry);
458 }
459 }
460
461 virtual void RunCallback() {
462 callback_->Run(error_code(), entries_);
463 delete callback_;
464 }
465
466 private:
467 base::FileUtilProxy::ReadDirectoryCallback* callback_;
468 FilePath file_path_;
kkanetkar@chromium.org48710682010-11-03 05:36:52 +0900469 std::vector<base::FileUtilProxy::Entry> entries_;
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900470};
471
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900472class RelayGetFileInfo : public MessageLoopRelay {
473 public:
474 RelayGetFileInfo(const FilePath& file_path,
475 base::FileUtilProxy::GetFileInfoCallback* callback)
476 : callback_(callback),
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900477 file_path_(file_path) {
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900478 DCHECK(callback);
479 }
480
481 protected:
482 virtual void RunWork() {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900483 if (!file_util::PathExists(file_path_)) {
484 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
485 return;
486 }
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900487 if (!file_util::GetFileInfo(file_path_, &file_info_))
488 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900489 }
490
491 virtual void RunCallback() {
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900492 callback_->Run(error_code(), file_info_);
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900493 delete callback_;
494 }
495
496 private:
497 base::FileUtilProxy::GetFileInfoCallback* callback_;
498 FilePath file_path_;
dumi@chromium.org97ae2612010-09-03 11:28:37 +0900499 base::PlatformFileInfo file_info_;
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900500};
501
dumi@chromium.org23915982010-09-10 12:01:14 +0900502class RelayGetFileInfoFromPlatformFile : public MessageLoopRelay {
503 public:
504 RelayGetFileInfoFromPlatformFile(
505 base::PlatformFile file,
506 base::FileUtilProxy::GetFileInfoCallback* callback)
507 : callback_(callback),
508 file_(file) {
509 DCHECK(callback);
510 }
511
512 protected:
513 virtual void RunWork() {
514 if (!base::GetPlatformFileInfo(file_, &file_info_))
515 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
516 }
517
518 virtual void RunCallback() {
519 callback_->Run(error_code(), file_info_);
520 delete callback_;
521 }
522
523 private:
524 base::FileUtilProxy::GetFileInfoCallback* callback_;
525 base::PlatformFile file_;
526 base::PlatformFileInfo file_info_;
527};
528
529class RelayRead : public MessageLoopRelay {
530 public:
531 RelayRead(base::PlatformFile file,
532 int64 offset,
dumi@chromium.org23915982010-09-10 12:01:14 +0900533 int bytes_to_read,
darin@chromium.org44a99732011-02-04 09:39:34 +0900534 base::FileUtilProxy::ReadCallback* callback)
dumi@chromium.org23915982010-09-10 12:01:14 +0900535 : file_(file),
536 offset_(offset),
darin@chromium.org44a99732011-02-04 09:39:34 +0900537 buffer_(new char[bytes_to_read]),
dumi@chromium.org23915982010-09-10 12:01:14 +0900538 bytes_to_read_(bytes_to_read),
539 callback_(callback),
540 bytes_read_(0) {
541 }
542
543 protected:
544 virtual void RunWork() {
darin@chromium.org44a99732011-02-04 09:39:34 +0900545 bytes_read_ = base::ReadPlatformFile(file_, offset_, buffer_.get(),
dumi@chromium.org23915982010-09-10 12:01:14 +0900546 bytes_to_read_);
547 if (bytes_read_ < 0)
548 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
549 }
550
551 virtual void RunCallback() {
552 if (callback_) {
darin@chromium.org44a99732011-02-04 09:39:34 +0900553 callback_->Run(error_code(), buffer_.get(), bytes_read_);
dumi@chromium.org23915982010-09-10 12:01:14 +0900554 delete callback_;
555 }
556 }
557
558 private:
559 base::PlatformFile file_;
560 int64 offset_;
darin@chromium.org44a99732011-02-04 09:39:34 +0900561 scoped_array<char> buffer_;
dumi@chromium.org23915982010-09-10 12:01:14 +0900562 int bytes_to_read_;
darin@chromium.org44a99732011-02-04 09:39:34 +0900563 base::FileUtilProxy::ReadCallback* callback_;
dumi@chromium.org23915982010-09-10 12:01:14 +0900564 int bytes_read_;
565};
566
567class RelayWrite : public MessageLoopRelay {
568 public:
569 RelayWrite(base::PlatformFile file,
ericu@google.com6a652222010-10-05 11:26:47 +0900570 int64 offset,
dumi@chromium.org23915982010-09-10 12:01:14 +0900571 const char* buffer,
572 int bytes_to_write,
darin@chromium.org44a99732011-02-04 09:39:34 +0900573 base::FileUtilProxy::WriteCallback* callback)
dumi@chromium.org23915982010-09-10 12:01:14 +0900574 : file_(file),
575 offset_(offset),
darin@chromium.org44a99732011-02-04 09:39:34 +0900576 buffer_(new char[bytes_to_write]),
dumi@chromium.org23915982010-09-10 12:01:14 +0900577 bytes_to_write_(bytes_to_write),
finnur@chromium.org899d4e02011-03-15 18:56:27 +0900578 callback_(callback),
579 bytes_written_(0) {
darin@chromium.org44a99732011-02-04 09:39:34 +0900580 memcpy(buffer_.get(), buffer, bytes_to_write);
dumi@chromium.org23915982010-09-10 12:01:14 +0900581 }
582
583 protected:
584 virtual void RunWork() {
darin@chromium.org44a99732011-02-04 09:39:34 +0900585 bytes_written_ = base::WritePlatformFile(file_, offset_, buffer_.get(),
dumi@chromium.org23915982010-09-10 12:01:14 +0900586 bytes_to_write_);
587 if (bytes_written_ < 0)
588 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
589 }
590
591 virtual void RunCallback() {
592 if (callback_) {
593 callback_->Run(error_code(), bytes_written_);
594 delete callback_;
595 }
596 }
597
598 private:
599 base::PlatformFile file_;
600 int64 offset_;
darin@chromium.org44a99732011-02-04 09:39:34 +0900601 scoped_array<char> buffer_;
dumi@chromium.org23915982010-09-10 12:01:14 +0900602 int bytes_to_write_;
darin@chromium.org44a99732011-02-04 09:39:34 +0900603 base::FileUtilProxy::WriteCallback* callback_;
dumi@chromium.org23915982010-09-10 12:01:14 +0900604 int bytes_written_;
605};
606
607class RelayTouch : public RelayWithStatusCallback {
608 public:
609 RelayTouch(base::PlatformFile file,
610 const base::Time& last_access_time,
611 const base::Time& last_modified_time,
612 base::FileUtilProxy::StatusCallback* callback)
613 : RelayWithStatusCallback(callback),
614 file_(file),
615 last_access_time_(last_access_time),
616 last_modified_time_(last_modified_time) {
617 }
618
619 protected:
620 virtual void RunWork() {
621 if (!base::TouchPlatformFile(file_, last_access_time_, last_modified_time_))
622 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
623 }
624
625 private:
626 base::PlatformFile file_;
627 base::Time last_access_time_;
628 base::Time last_modified_time_;
629};
630
dumi@chromium.org12c2e2b2010-09-24 10:09:32 +0900631class RelayTouchFilePath : public RelayWithStatusCallback {
632 public:
633 RelayTouchFilePath(const FilePath& file_path,
634 const base::Time& last_access_time,
635 const base::Time& last_modified_time,
636 base::FileUtilProxy::StatusCallback* callback)
637 : RelayWithStatusCallback(callback),
evan@chromium.orgd719ede2010-09-25 05:07:41 +0900638 file_path_(file_path),
dumi@chromium.org12c2e2b2010-09-24 10:09:32 +0900639 last_access_time_(last_access_time),
640 last_modified_time_(last_modified_time) {
641 }
642
643 protected:
644 virtual void RunWork() {
645 if (!file_util::TouchFile(
646 file_path_, last_access_time_, last_modified_time_))
647 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
648 }
649
650 private:
651 FilePath file_path_;
652 base::Time last_access_time_;
653 base::Time last_modified_time_;
654};
655
ericu@google.com6a652222010-10-05 11:26:47 +0900656class RelayTruncatePlatformFile : public RelayWithStatusCallback {
dumi@chromium.org23915982010-09-10 12:01:14 +0900657 public:
ericu@google.com6a652222010-10-05 11:26:47 +0900658 RelayTruncatePlatformFile(base::PlatformFile file,
659 int64 length,
660 base::FileUtilProxy::StatusCallback* callback)
dumi@chromium.org23915982010-09-10 12:01:14 +0900661 : RelayWithStatusCallback(callback),
662 file_(file),
663 length_(length) {
664 }
665
666 protected:
667 virtual void RunWork() {
668 if (!base::TruncatePlatformFile(file_, length_))
669 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
670 }
671
672 private:
673 base::PlatformFile file_;
674 int64 length_;
675};
676
ericu@google.com6a652222010-10-05 11:26:47 +0900677class RelayTruncate : public RelayWithStatusCallback {
678 public:
679 RelayTruncate(const FilePath& path,
680 int64 length,
681 base::FileUtilProxy::StatusCallback* callback)
682 : RelayWithStatusCallback(callback),
683 path_(path),
684 length_(length) {
685 }
686
687 protected:
688 virtual void RunWork() {
689 base::PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED);
690 base::PlatformFile file =
691 base::CreatePlatformFile(
692 path_,
693 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
694 NULL,
695 &error_code);
696 if (error_code != base::PLATFORM_FILE_OK) {
697 set_error_code(error_code);
698 return;
699 }
700 if (!base::TruncatePlatformFile(file, length_))
701 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
702 base::ClosePlatformFile(file);
703 }
704
705 private:
706 FilePath path_;
707 int64 length_;
708};
709
dumi@chromium.org23915982010-09-10 12:01:14 +0900710class RelayFlush : public RelayWithStatusCallback {
711 public:
712 RelayFlush(base::PlatformFile file,
713 base::FileUtilProxy::StatusCallback* callback)
714 : RelayWithStatusCallback(callback),
715 file_(file) {
716 }
717
718 protected:
719 virtual void RunWork() {
720 if (!base::FlushPlatformFile(file_))
721 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
722 }
723
724 private:
725 base::PlatformFile file_;
726};
727
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900728bool Start(const tracked_objects::Location& from_here,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900729 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
730 scoped_refptr<MessageLoopRelay> relay) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900731 return relay->Start(message_loop_proxy, from_here);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900732}
733
734} // namespace
735
736namespace base {
737
738// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900739bool FileUtilProxy::CreateOrOpen(
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900740 scoped_refptr<MessageLoopProxy> message_loop_proxy,
741 const FilePath& file_path, int file_flags,
742 CreateOrOpenCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900743 return Start(FROM_HERE, message_loop_proxy, new RelayCreateOrOpen(
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900744 message_loop_proxy, file_path, file_flags, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900745}
746
747// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900748bool FileUtilProxy::CreateTemporary(
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900749 scoped_refptr<MessageLoopProxy> message_loop_proxy,
noelutz@google.comf56dab22011-06-14 05:29:50 +0900750 int additional_file_flags,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900751 CreateTemporaryCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900752 return Start(FROM_HERE, message_loop_proxy,
noelutz@google.comf56dab22011-06-14 05:29:50 +0900753 new RelayCreateTemporary(message_loop_proxy,
754 additional_file_flags,
755 callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900756}
757
758// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900759bool FileUtilProxy::Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900760 base::PlatformFile file_handle,
761 StatusCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900762 return Start(FROM_HERE, message_loop_proxy,
763 new RelayClose(file_handle, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900764}
765
766// static
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900767bool FileUtilProxy::EnsureFileExists(
768 scoped_refptr<MessageLoopProxy> message_loop_proxy,
769 const FilePath& file_path,
770 EnsureFileExistsCallback* callback) {
771 return Start(FROM_HERE, message_loop_proxy, new RelayEnsureFileExists(
772 message_loop_proxy, file_path, callback));
773}
774
erg@google.com37c078e2011-01-11 09:50:59 +0900775// Retrieves the information about a file. It is invalid to pass NULL for the
776// callback.
777bool FileUtilProxy::GetFileInfo(
778 scoped_refptr<MessageLoopProxy> message_loop_proxy,
779 const FilePath& file_path,
780 GetFileInfoCallback* callback) {
781 return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo(
782 file_path, callback));
783}
784
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900785// static
erg@google.com37c078e2011-01-11 09:50:59 +0900786bool FileUtilProxy::GetFileInfoFromPlatformFile(
787 scoped_refptr<MessageLoopProxy> message_loop_proxy,
788 PlatformFile file,
789 GetFileInfoCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900790 return Start(FROM_HERE, message_loop_proxy,
erg@google.com37c078e2011-01-11 09:50:59 +0900791 new RelayGetFileInfoFromPlatformFile(file, callback));
792}
793
794// static
795bool FileUtilProxy::ReadDirectory(
796 scoped_refptr<MessageLoopProxy> message_loop_proxy,
797 const FilePath& file_path,
798 ReadDirectoryCallback* callback) {
799 return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory(
800 file_path, callback));
801}
802
803// static
804bool FileUtilProxy::CreateDirectory(
805 scoped_refptr<MessageLoopProxy> message_loop_proxy,
806 const FilePath& file_path,
807 bool exclusive,
808 bool recursive,
809 StatusCallback* callback) {
810 return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory(
811 file_path, exclusive, recursive, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900812}
813
814// static
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900815bool FileUtilProxy::Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy,
816 const FilePath& src_file_path,
817 const FilePath& dest_file_path,
818 StatusCallback* callback) {
819 return Start(FROM_HERE, message_loop_proxy,
820 new RelayCopy(src_file_path, dest_file_path, callback));
821}
822
823// static
824bool FileUtilProxy::Move(scoped_refptr<MessageLoopProxy> message_loop_proxy,
825 const FilePath& src_file_path,
826 const FilePath& dest_file_path,
827 StatusCallback* callback) {
828 return Start(FROM_HERE, message_loop_proxy,
829 new RelayMove(src_file_path, dest_file_path, callback));
830}
831
832// static
erg@google.com37c078e2011-01-11 09:50:59 +0900833bool FileUtilProxy::Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,
834 const FilePath& file_path,
835 bool recursive,
836 StatusCallback* callback) {
837 return Start(FROM_HERE, message_loop_proxy,
838 new RelayDelete(file_path, recursive, callback));
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900839}
840
841// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900842bool FileUtilProxy::RecursiveDelete(
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900843 scoped_refptr<MessageLoopProxy> message_loop_proxy,
844 const FilePath& file_path,
845 StatusCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900846 return Start(FROM_HERE, message_loop_proxy,
847 new RelayDelete(file_path, true, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900848}
849
dumi@chromium.org23915982010-09-10 12:01:14 +0900850// static
dumi@chromium.org23915982010-09-10 12:01:14 +0900851bool FileUtilProxy::Read(
852 scoped_refptr<MessageLoopProxy> message_loop_proxy,
853 PlatformFile file,
854 int64 offset,
dumi@chromium.org23915982010-09-10 12:01:14 +0900855 int bytes_to_read,
darin@chromium.org44a99732011-02-04 09:39:34 +0900856 ReadCallback* callback) {
dumi@chromium.org23915982010-09-10 12:01:14 +0900857 return Start(FROM_HERE, message_loop_proxy,
darin@chromium.org44a99732011-02-04 09:39:34 +0900858 new RelayRead(file, offset, bytes_to_read, callback));
dumi@chromium.org23915982010-09-10 12:01:14 +0900859}
860
861// static
862bool FileUtilProxy::Write(
863 scoped_refptr<MessageLoopProxy> message_loop_proxy,
864 PlatformFile file,
865 int64 offset,
866 const char* buffer,
867 int bytes_to_write,
darin@chromium.org44a99732011-02-04 09:39:34 +0900868 WriteCallback* callback) {
dumi@chromium.org23915982010-09-10 12:01:14 +0900869 return Start(FROM_HERE, message_loop_proxy,
870 new RelayWrite(file, offset, buffer, bytes_to_write, callback));
871}
872
873// static
874bool FileUtilProxy::Touch(
875 scoped_refptr<MessageLoopProxy> message_loop_proxy,
876 PlatformFile file,
877 const base::Time& last_access_time,
878 const base::Time& last_modified_time,
879 StatusCallback* callback) {
880 return Start(FROM_HERE, message_loop_proxy,
881 new RelayTouch(file, last_access_time, last_modified_time,
882 callback));
883}
884
885// static
dumi@chromium.org12c2e2b2010-09-24 10:09:32 +0900886bool FileUtilProxy::Touch(
887 scoped_refptr<MessageLoopProxy> message_loop_proxy,
888 const FilePath& file_path,
889 const base::Time& last_access_time,
890 const base::Time& last_modified_time,
891 StatusCallback* callback) {
892 return Start(FROM_HERE, message_loop_proxy,
893 new RelayTouchFilePath(file_path, last_access_time,
894 last_modified_time, callback));
895}
896
897// static
dumi@chromium.org23915982010-09-10 12:01:14 +0900898bool FileUtilProxy::Truncate(
899 scoped_refptr<MessageLoopProxy> message_loop_proxy,
900 PlatformFile file,
ericu@google.com6a652222010-10-05 11:26:47 +0900901 int64 length,
dumi@chromium.org23915982010-09-10 12:01:14 +0900902 StatusCallback* callback) {
903 return Start(FROM_HERE, message_loop_proxy,
ericu@google.com6a652222010-10-05 11:26:47 +0900904 new RelayTruncatePlatformFile(file, length, callback));
905}
906
907// static
908bool FileUtilProxy::Truncate(
909 scoped_refptr<MessageLoopProxy> message_loop_proxy,
910 const FilePath& path,
911 int64 length,
912 StatusCallback* callback) {
913 return Start(FROM_HERE, message_loop_proxy,
914 new RelayTruncate(path, length, callback));
dumi@chromium.org23915982010-09-10 12:01:14 +0900915}
916
917// static
918bool FileUtilProxy::Flush(
919 scoped_refptr<MessageLoopProxy> message_loop_proxy,
920 PlatformFile file,
921 StatusCallback* callback) {
922 return Start(FROM_HERE, message_loop_proxy, new RelayFlush(file, callback));
923}
924
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900925} // namespace base