blob: bd089091f73ef550a2e5b7e0aab1fee02a3e2144 [file] [log] [blame]
dumi@chromium.orgc980e402010-08-21 07:42:50 +09001// Copyright (c) 2010 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 "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,
170 base::FileUtilProxy::CreateTemporaryCallback* callback)
171 : message_loop_proxy_(message_loop_proxy),
172 callback_(callback),
173 file_handle_(base::kInvalidPlatformFileValue) {
174 DCHECK(callback);
175 }
176
177 protected:
178 virtual ~RelayCreateTemporary() {
179 if (file_handle_ != base::kInvalidPlatformFileValue)
180 base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
181 }
182
183 virtual void RunWork() {
184 // TODO(darin): file_util should have a variant of CreateTemporaryFile
185 // that returns a FilePath and a PlatformFile.
186 file_util::CreateTemporaryFile(&file_path_);
187
188 // Use a fixed set of flags that are appropriate for writing to a temporary
189 // file from the IO thread using a net::FileStream.
190 int file_flags =
191 base::PLATFORM_FILE_CREATE_ALWAYS |
192 base::PLATFORM_FILE_WRITE |
193 base::PLATFORM_FILE_ASYNC |
194 base::PLATFORM_FILE_TEMPORARY;
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900195 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
196 file_handle_ = base::CreatePlatformFile(file_path_, file_flags,
197 NULL, &error_code);
198 set_error_code(error_code);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900199 }
200
201 virtual void RunCallback() {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900202 callback_->Run(error_code(), base::PassPlatformFile(&file_handle_),
203 file_path_);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900204 delete callback_;
205 }
206
207 private:
208 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
209 base::FileUtilProxy::CreateTemporaryCallback* callback_;
210 base::PlatformFile file_handle_;
211 FilePath file_path_;
212};
213
214class RelayWithStatusCallback : public MessageLoopRelay {
215 public:
216 explicit RelayWithStatusCallback(
217 base::FileUtilProxy::StatusCallback* callback)
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900218 : callback_(callback) {
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900219 // It is OK for callback to be NULL.
220 }
221
222 protected:
223 virtual void RunCallback() {
224 // The caller may not have been interested in the result.
225 if (callback_) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900226 callback_->Run(error_code());
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900227 delete callback_;
228 }
229 }
230
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900231 private:
232 base::FileUtilProxy::StatusCallback* callback_;
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900233};
234
235class RelayClose : public RelayWithStatusCallback {
236 public:
237 RelayClose(base::PlatformFile file_handle,
238 base::FileUtilProxy::StatusCallback* callback)
239 : RelayWithStatusCallback(callback),
240 file_handle_(file_handle) {
241 }
242
243 protected:
244 virtual void RunWork() {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900245 if (!base::ClosePlatformFile(file_handle_))
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900246 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900247 }
248
249 private:
250 base::PlatformFile file_handle_;
251};
252
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900253class RelayEnsureFileExists : public MessageLoopRelay {
254 public:
255 RelayEnsureFileExists(
256 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
257 const FilePath& file_path,
258 base::FileUtilProxy::EnsureFileExistsCallback* callback)
259 : message_loop_proxy_(message_loop_proxy),
260 file_path_(file_path),
261 callback_(callback),
262 created_(false) {
263 DCHECK(callback);
264 }
265
266 protected:
267 virtual void RunWork() {
268 if (!file_util::DirectoryExists(file_path_.DirName())) {
269 // If its parent does not exist, should return NOT_FOUND error.
270 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
271 return;
272 }
273 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
274 // Tries to create the |file_path_| exclusively. This should fail
275 // with PLATFORM_FILE_ERROR_EXISTS if the path already exists.
276 base::PlatformFile handle = base::CreatePlatformFile(
277 file_path_,
278 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ,
279 &created_, &error_code);
280 if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) {
281 // Make sure created_ is false.
282 created_ = false;
283 error_code = base::PLATFORM_FILE_OK;
284 }
285 if (handle != base::kInvalidPlatformFileValue)
286 base::ClosePlatformFile(handle);
287 set_error_code(error_code);
288 }
289
290 virtual void RunCallback() {
291 callback_->Run(error_code(), created_);
292 delete callback_;
293 }
294
295 private:
296 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
297 FilePath file_path_;
298 base::FileUtilProxy::EnsureFileExistsCallback* callback_;
299 bool created_;
300};
301
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900302class RelayDelete : public RelayWithStatusCallback {
303 public:
304 RelayDelete(const FilePath& file_path,
305 bool recursive,
306 base::FileUtilProxy::StatusCallback* callback)
307 : RelayWithStatusCallback(callback),
308 file_path_(file_path),
309 recursive_(recursive) {
310 }
311
312 protected:
313 virtual void RunWork() {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900314 if (!file_util::PathExists(file_path_)) {
315 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
316 return;
317 }
318 if (!file_util::Delete(file_path_, recursive_)) {
319 if (!recursive_ && !file_util::IsDirectoryEmpty(file_path_)) {
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900320 set_error_code(base::PLATFORM_FILE_ERROR_NOT_EMPTY);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900321 return;
322 }
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900323 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900324 }
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900325 }
326
327 private:
328 FilePath file_path_;
329 bool recursive_;
330};
331
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900332class RelayCopy : public RelayWithStatusCallback {
333 public:
334 RelayCopy(const FilePath& src_file_path,
335 const FilePath& dest_file_path,
336 base::FileUtilProxy::StatusCallback* callback)
337 : RelayWithStatusCallback(callback),
338 src_file_path_(src_file_path),
339 dest_file_path_(dest_file_path) {
340 }
341
342 protected:
343 virtual void RunWork() {
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900344 set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy(
345 src_file_path_, dest_file_path_));
346 if (error_code() != base::PLATFORM_FILE_OK)
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900347 return;
kinuko@chromium.org31583c32010-10-07 06:44:35 +0900348 if (!file_util::CopyDirectory(src_file_path_, dest_file_path_,
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900349 true /* recursive */))
kinuko@chromium.org31583c32010-10-07 06:44:35 +0900350 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900351 }
352
353 private:
354 FilePath src_file_path_;
355 FilePath dest_file_path_;
356};
357
358class RelayMove : public RelayWithStatusCallback {
359 public:
360 RelayMove(const FilePath& src_file_path,
361 const FilePath& dest_file_path,
362 base::FileUtilProxy::StatusCallback* callback)
363 : RelayWithStatusCallback(callback),
364 src_file_path_(src_file_path),
365 dest_file_path_(dest_file_path) {
366 }
367
368 protected:
369 virtual void RunWork() {
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900370 set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy(
371 src_file_path_, dest_file_path_));
372 if (error_code() != base::PLATFORM_FILE_OK)
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900373 return;
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900374 if (!file_util::Move(src_file_path_, dest_file_path_))
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900375 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900376 }
377
378 private:
379 FilePath src_file_path_;
380 FilePath dest_file_path_;
381};
382
383class RelayCreateDirectory : public RelayWithStatusCallback {
384 public:
385 RelayCreateDirectory(
386 const FilePath& file_path,
387 bool exclusive,
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900388 bool recursive,
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900389 base::FileUtilProxy::StatusCallback* callback)
390 : RelayWithStatusCallback(callback),
391 file_path_(file_path),
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900392 exclusive_(exclusive),
393 recursive_(recursive) {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900394 }
395
396 protected:
397 virtual void RunWork() {
398 bool path_exists = file_util::PathExists(file_path_);
399 // If parent dir of file doesn't exist.
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900400 if (!recursive_ && !file_util::PathExists(file_path_.DirName())) {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900401 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
402 return;
403 }
404 if (exclusive_ && path_exists) {
405 set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
406 return;
407 }
408 // If file exists at the path.
409 if (path_exists && !file_util::DirectoryExists(file_path_)) {
410 set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
411 return;
412 }
413 if (!file_util::CreateDirectory(file_path_))
414 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
415 }
416
417 private:
418 FilePath file_path_;
419 bool exclusive_;
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900420 bool recursive_;
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900421};
422
423class RelayReadDirectory : public MessageLoopRelay {
424 public:
425 RelayReadDirectory(const FilePath& file_path,
426 base::FileUtilProxy::ReadDirectoryCallback* callback)
427 : callback_(callback), file_path_(file_path) {
428 DCHECK(callback);
429 }
430
431 protected:
432 virtual void RunWork() {
433 // TODO(kkanetkar): Implement directory read in multiple chunks.
434 if (!file_util::DirectoryExists(file_path_)) {
435 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
436 return;
437 }
438
439 file_util::FileEnumerator file_enum(
440 file_path_, false, static_cast<file_util::FileEnumerator::FILE_TYPE>(
441 file_util::FileEnumerator::FILES |
442 file_util::FileEnumerator::DIRECTORIES));
443 FilePath current;
444 while (!(current = file_enum.Next()).empty()) {
kkanetkar@chromium.org48710682010-11-03 05:36:52 +0900445 base::FileUtilProxy::Entry entry;
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900446 file_util::FileEnumerator::FindInfo info;
447 file_enum.GetFindInfo(&info);
kinuko@chromium.org83604d12010-09-03 07:28:49 +0900448 entry.is_directory = file_enum.IsDirectory(info);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900449 // This will just give the entry's name instead of entire path
450 // if we use current.value().
451 entry.name = file_util::FileEnumerator::GetFilename(info).value();
452 entries_.push_back(entry);
453 }
454 }
455
456 virtual void RunCallback() {
457 callback_->Run(error_code(), entries_);
458 delete callback_;
459 }
460
461 private:
462 base::FileUtilProxy::ReadDirectoryCallback* callback_;
463 FilePath file_path_;
kkanetkar@chromium.org48710682010-11-03 05:36:52 +0900464 std::vector<base::FileUtilProxy::Entry> entries_;
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900465};
466
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900467class RelayGetFileInfo : public MessageLoopRelay {
468 public:
469 RelayGetFileInfo(const FilePath& file_path,
470 base::FileUtilProxy::GetFileInfoCallback* callback)
471 : callback_(callback),
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900472 file_path_(file_path) {
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900473 DCHECK(callback);
474 }
475
476 protected:
477 virtual void RunWork() {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900478 if (!file_util::PathExists(file_path_)) {
479 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
480 return;
481 }
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900482 if (!file_util::GetFileInfo(file_path_, &file_info_))
483 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900484 }
485
486 virtual void RunCallback() {
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900487 callback_->Run(error_code(), file_info_);
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900488 delete callback_;
489 }
490
491 private:
492 base::FileUtilProxy::GetFileInfoCallback* callback_;
493 FilePath file_path_;
dumi@chromium.org97ae2612010-09-03 11:28:37 +0900494 base::PlatformFileInfo file_info_;
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900495};
496
dumi@chromium.org23915982010-09-10 12:01:14 +0900497class RelayGetFileInfoFromPlatformFile : public MessageLoopRelay {
498 public:
499 RelayGetFileInfoFromPlatformFile(
500 base::PlatformFile file,
501 base::FileUtilProxy::GetFileInfoCallback* callback)
502 : callback_(callback),
503 file_(file) {
504 DCHECK(callback);
505 }
506
507 protected:
508 virtual void RunWork() {
509 if (!base::GetPlatformFileInfo(file_, &file_info_))
510 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
511 }
512
513 virtual void RunCallback() {
514 callback_->Run(error_code(), file_info_);
515 delete callback_;
516 }
517
518 private:
519 base::FileUtilProxy::GetFileInfoCallback* callback_;
520 base::PlatformFile file_;
521 base::PlatformFileInfo file_info_;
522};
523
524class RelayRead : public MessageLoopRelay {
525 public:
526 RelayRead(base::PlatformFile file,
527 int64 offset,
528 char* buffer,
529 int bytes_to_read,
530 base::FileUtilProxy::ReadWriteCallback* callback)
531 : file_(file),
532 offset_(offset),
533 buffer_(buffer),
534 bytes_to_read_(bytes_to_read),
535 callback_(callback),
536 bytes_read_(0) {
537 }
538
539 protected:
540 virtual void RunWork() {
541 bytes_read_ = base::ReadPlatformFile(file_, offset_, buffer_,
542 bytes_to_read_);
543 if (bytes_read_ < 0)
544 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
545 }
546
547 virtual void RunCallback() {
548 if (callback_) {
549 callback_->Run(error_code(), bytes_read_);
550 delete callback_;
551 }
552 }
553
554 private:
555 base::PlatformFile file_;
556 int64 offset_;
557 char* buffer_;
558 int bytes_to_read_;
559 base::FileUtilProxy::ReadWriteCallback* callback_;
560 int bytes_read_;
561};
562
563class RelayWrite : public MessageLoopRelay {
564 public:
565 RelayWrite(base::PlatformFile file,
ericu@google.com6a652222010-10-05 11:26:47 +0900566 int64 offset,
dumi@chromium.org23915982010-09-10 12:01:14 +0900567 const char* buffer,
568 int bytes_to_write,
569 base::FileUtilProxy::ReadWriteCallback* callback)
570 : file_(file),
571 offset_(offset),
572 buffer_(buffer),
573 bytes_to_write_(bytes_to_write),
574 callback_(callback) {
575 }
576
577 protected:
578 virtual void RunWork() {
579 bytes_written_ = base::WritePlatformFile(file_, offset_, buffer_,
580 bytes_to_write_);
581 if (bytes_written_ < 0)
582 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
583 }
584
585 virtual void RunCallback() {
586 if (callback_) {
587 callback_->Run(error_code(), bytes_written_);
588 delete callback_;
589 }
590 }
591
592 private:
593 base::PlatformFile file_;
594 int64 offset_;
595 const char* buffer_;
596 int bytes_to_write_;
597 base::FileUtilProxy::ReadWriteCallback* callback_;
598 int bytes_written_;
599};
600
601class RelayTouch : public RelayWithStatusCallback {
602 public:
603 RelayTouch(base::PlatformFile file,
604 const base::Time& last_access_time,
605 const base::Time& last_modified_time,
606 base::FileUtilProxy::StatusCallback* callback)
607 : RelayWithStatusCallback(callback),
608 file_(file),
609 last_access_time_(last_access_time),
610 last_modified_time_(last_modified_time) {
611 }
612
613 protected:
614 virtual void RunWork() {
615 if (!base::TouchPlatformFile(file_, last_access_time_, last_modified_time_))
616 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
617 }
618
619 private:
620 base::PlatformFile file_;
621 base::Time last_access_time_;
622 base::Time last_modified_time_;
623};
624
dumi@chromium.org12c2e2b2010-09-24 10:09:32 +0900625class RelayTouchFilePath : public RelayWithStatusCallback {
626 public:
627 RelayTouchFilePath(const FilePath& file_path,
628 const base::Time& last_access_time,
629 const base::Time& last_modified_time,
630 base::FileUtilProxy::StatusCallback* callback)
631 : RelayWithStatusCallback(callback),
evan@chromium.orgd719ede2010-09-25 05:07:41 +0900632 file_path_(file_path),
dumi@chromium.org12c2e2b2010-09-24 10:09:32 +0900633 last_access_time_(last_access_time),
634 last_modified_time_(last_modified_time) {
635 }
636
637 protected:
638 virtual void RunWork() {
639 if (!file_util::TouchFile(
640 file_path_, last_access_time_, last_modified_time_))
641 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
642 }
643
644 private:
645 FilePath file_path_;
646 base::Time last_access_time_;
647 base::Time last_modified_time_;
648};
649
ericu@google.com6a652222010-10-05 11:26:47 +0900650class RelayTruncatePlatformFile : public RelayWithStatusCallback {
dumi@chromium.org23915982010-09-10 12:01:14 +0900651 public:
ericu@google.com6a652222010-10-05 11:26:47 +0900652 RelayTruncatePlatformFile(base::PlatformFile file,
653 int64 length,
654 base::FileUtilProxy::StatusCallback* callback)
dumi@chromium.org23915982010-09-10 12:01:14 +0900655 : RelayWithStatusCallback(callback),
656 file_(file),
657 length_(length) {
658 }
659
660 protected:
661 virtual void RunWork() {
662 if (!base::TruncatePlatformFile(file_, length_))
663 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
664 }
665
666 private:
667 base::PlatformFile file_;
668 int64 length_;
669};
670
ericu@google.com6a652222010-10-05 11:26:47 +0900671class RelayTruncate : public RelayWithStatusCallback {
672 public:
673 RelayTruncate(const FilePath& path,
674 int64 length,
675 base::FileUtilProxy::StatusCallback* callback)
676 : RelayWithStatusCallback(callback),
677 path_(path),
678 length_(length) {
679 }
680
681 protected:
682 virtual void RunWork() {
683 base::PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED);
684 base::PlatformFile file =
685 base::CreatePlatformFile(
686 path_,
687 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
688 NULL,
689 &error_code);
690 if (error_code != base::PLATFORM_FILE_OK) {
691 set_error_code(error_code);
692 return;
693 }
694 if (!base::TruncatePlatformFile(file, length_))
695 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
696 base::ClosePlatformFile(file);
697 }
698
699 private:
700 FilePath path_;
701 int64 length_;
702};
703
dumi@chromium.org23915982010-09-10 12:01:14 +0900704class RelayFlush : public RelayWithStatusCallback {
705 public:
706 RelayFlush(base::PlatformFile file,
707 base::FileUtilProxy::StatusCallback* callback)
708 : RelayWithStatusCallback(callback),
709 file_(file) {
710 }
711
712 protected:
713 virtual void RunWork() {
714 if (!base::FlushPlatformFile(file_))
715 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
716 }
717
718 private:
719 base::PlatformFile file_;
720};
721
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900722bool Start(const tracked_objects::Location& from_here,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900723 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
724 scoped_refptr<MessageLoopRelay> relay) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900725 return relay->Start(message_loop_proxy, from_here);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900726}
727
728} // namespace
729
730namespace base {
731
732// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900733bool FileUtilProxy::CreateOrOpen(
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900734 scoped_refptr<MessageLoopProxy> message_loop_proxy,
735 const FilePath& file_path, int file_flags,
736 CreateOrOpenCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900737 return Start(FROM_HERE, message_loop_proxy, new RelayCreateOrOpen(
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900738 message_loop_proxy, file_path, file_flags, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900739}
740
741// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900742bool FileUtilProxy::CreateTemporary(
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900743 scoped_refptr<MessageLoopProxy> message_loop_proxy,
744 CreateTemporaryCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900745 return Start(FROM_HERE, message_loop_proxy,
746 new RelayCreateTemporary(message_loop_proxy, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900747}
748
749// static
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900750bool FileUtilProxy::CreateDirectory(
751 scoped_refptr<MessageLoopProxy> message_loop_proxy,
752 const FilePath& file_path,
753 bool exclusive,
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900754 bool recursive,
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900755 StatusCallback* callback) {
756 return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory(
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900757 file_path, exclusive, recursive, callback));
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900758}
759
760// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900761bool FileUtilProxy::Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900762 base::PlatformFile file_handle,
763 StatusCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900764 return Start(FROM_HERE, message_loop_proxy,
765 new RelayClose(file_handle, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900766}
767
768// static
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900769bool FileUtilProxy::EnsureFileExists(
770 scoped_refptr<MessageLoopProxy> message_loop_proxy,
771 const FilePath& file_path,
772 EnsureFileExistsCallback* callback) {
773 return Start(FROM_HERE, message_loop_proxy, new RelayEnsureFileExists(
774 message_loop_proxy, file_path, callback));
775}
776
777// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900778bool FileUtilProxy::Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900779 const FilePath& file_path,
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900780 bool recursive,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900781 StatusCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900782 return Start(FROM_HERE, message_loop_proxy,
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900783 new RelayDelete(file_path, recursive, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900784}
785
786// static
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900787bool FileUtilProxy::Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy,
788 const FilePath& src_file_path,
789 const FilePath& dest_file_path,
790 StatusCallback* callback) {
791 return Start(FROM_HERE, message_loop_proxy,
792 new RelayCopy(src_file_path, dest_file_path, callback));
793}
794
795// static
796bool FileUtilProxy::Move(scoped_refptr<MessageLoopProxy> message_loop_proxy,
797 const FilePath& src_file_path,
798 const FilePath& dest_file_path,
799 StatusCallback* callback) {
800 return Start(FROM_HERE, message_loop_proxy,
801 new RelayMove(src_file_path, dest_file_path, callback));
802}
803
804// static
805bool FileUtilProxy::ReadDirectory(
806 scoped_refptr<MessageLoopProxy> message_loop_proxy,
807 const FilePath& file_path,
808 ReadDirectoryCallback* callback) {
809 return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory(
810 file_path, callback));
811}
812
813// Retrieves the information about a file. It is invalid to pass NULL for the
814// callback.
815bool FileUtilProxy::GetFileInfo(
816 scoped_refptr<MessageLoopProxy> message_loop_proxy,
817 const FilePath& file_path,
818 GetFileInfoCallback* callback) {
819 return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo(
820 file_path, callback));
821}
822
823// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900824bool FileUtilProxy::RecursiveDelete(
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900825 scoped_refptr<MessageLoopProxy> message_loop_proxy,
826 const FilePath& file_path,
827 StatusCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900828 return Start(FROM_HERE, message_loop_proxy,
829 new RelayDelete(file_path, true, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900830}
831
dumi@chromium.org23915982010-09-10 12:01:14 +0900832// static
833bool FileUtilProxy::GetFileInfoFromPlatformFile(
834 scoped_refptr<MessageLoopProxy> message_loop_proxy,
835 PlatformFile file,
836 GetFileInfoCallback* callback) {
837 return Start(FROM_HERE, message_loop_proxy,
838 new RelayGetFileInfoFromPlatformFile(file, callback));
839}
840
841// static
842bool FileUtilProxy::Read(
843 scoped_refptr<MessageLoopProxy> message_loop_proxy,
844 PlatformFile file,
845 int64 offset,
846 char* buffer,
847 int bytes_to_read,
848 ReadWriteCallback* callback) {
849 return Start(FROM_HERE, message_loop_proxy,
850 new RelayRead(file, offset, buffer, bytes_to_read, callback));
851}
852
853// static
854bool FileUtilProxy::Write(
855 scoped_refptr<MessageLoopProxy> message_loop_proxy,
856 PlatformFile file,
857 int64 offset,
858 const char* buffer,
859 int bytes_to_write,
860 ReadWriteCallback* callback) {
861 return Start(FROM_HERE, message_loop_proxy,
862 new RelayWrite(file, offset, buffer, bytes_to_write, callback));
863}
864
865// static
866bool FileUtilProxy::Touch(
867 scoped_refptr<MessageLoopProxy> message_loop_proxy,
868 PlatformFile file,
869 const base::Time& last_access_time,
870 const base::Time& last_modified_time,
871 StatusCallback* callback) {
872 return Start(FROM_HERE, message_loop_proxy,
873 new RelayTouch(file, last_access_time, last_modified_time,
874 callback));
875}
876
877// static
dumi@chromium.org12c2e2b2010-09-24 10:09:32 +0900878bool FileUtilProxy::Touch(
879 scoped_refptr<MessageLoopProxy> message_loop_proxy,
880 const FilePath& file_path,
881 const base::Time& last_access_time,
882 const base::Time& last_modified_time,
883 StatusCallback* callback) {
884 return Start(FROM_HERE, message_loop_proxy,
885 new RelayTouchFilePath(file_path, last_access_time,
886 last_modified_time, callback));
887}
888
889// static
dumi@chromium.org23915982010-09-10 12:01:14 +0900890bool FileUtilProxy::Truncate(
891 scoped_refptr<MessageLoopProxy> message_loop_proxy,
892 PlatformFile file,
ericu@google.com6a652222010-10-05 11:26:47 +0900893 int64 length,
dumi@chromium.org23915982010-09-10 12:01:14 +0900894 StatusCallback* callback) {
895 return Start(FROM_HERE, message_loop_proxy,
ericu@google.com6a652222010-10-05 11:26:47 +0900896 new RelayTruncatePlatformFile(file, length, callback));
897}
898
899// static
900bool FileUtilProxy::Truncate(
901 scoped_refptr<MessageLoopProxy> message_loop_proxy,
902 const FilePath& path,
903 int64 length,
904 StatusCallback* callback) {
905 return Start(FROM_HERE, message_loop_proxy,
906 new RelayTruncate(path, length, callback));
dumi@chromium.org23915982010-09-10 12:01:14 +0900907}
908
909// static
910bool FileUtilProxy::Flush(
911 scoped_refptr<MessageLoopProxy> message_loop_proxy,
912 PlatformFile file,
913 StatusCallback* callback) {
914 return Start(FROM_HERE, message_loop_proxy, new RelayFlush(file, callback));
915}
916
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900917} // namespace base