• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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 
7 #include "base/message_loop_proxy.h"
8 
9 // TODO(jianli): Move the code from anonymous namespace to base namespace so
10 // that all of the base:: prefixes would be unnecessary.
11 namespace {
12 
13 namespace {
14 
15 // Performs common checks for move and copy.
16 // This also removes the destination directory if it's non-empty and all other
17 // checks are passed (so that the copy/move correctly overwrites the
18 // destination).
PerformCommonCheckAndPreparationForMoveAndCopy(const FilePath & src_file_path,const FilePath & dest_file_path)19 static 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 
69 }  // anonymous namespace
70 
71 class MessageLoopRelay
72     : public base::RefCountedThreadSafe<MessageLoopRelay> {
73  public:
MessageLoopRelay()74   MessageLoopRelay()
75       : origin_message_loop_proxy_(
76             base::MessageLoopProxy::CreateForCurrentThread()),
77         error_code_(base::PLATFORM_FILE_OK) {
78   }
79 
Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,const tracked_objects::Location & from_here)80   bool Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
81              const tracked_objects::Location& from_here) {
82     return message_loop_proxy->PostTask(
83         from_here,
84         NewRunnableMethod(this, &MessageLoopRelay::ProcessOnTargetThread));
85   }
86 
87  protected:
88   friend class base::RefCountedThreadSafe<MessageLoopRelay>;
~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 
set_error_code(base::PlatformFileError error_code)97   void set_error_code(base::PlatformFileError error_code) {
98     error_code_ = error_code;
99   }
100 
error_code() const101   base::PlatformFileError error_code() const {
102     return error_code_;
103   }
104 
105  private:
ProcessOnTargetThread()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_;
114   base::PlatformFileError error_code_;
115 };
116 
117 class RelayCreateOrOpen : public MessageLoopRelay {
118  public:
RelayCreateOrOpen(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,const FilePath & file_path,int file_flags,base::FileUtilProxy::CreateOrOpenCallback * callback)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:
~RelayCreateOrOpen()134   virtual ~RelayCreateOrOpen() {
135     if (file_handle_ != base::kInvalidPlatformFileValue)
136       base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
137   }
138 
RunWork()139   virtual void RunWork() {
140     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     }
145     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);
149   }
150 
RunCallback()151   virtual void RunCallback() {
152     callback_->Run(error_code(), base::PassPlatformFile(&file_handle_),
153                    created_);
154     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 
166 class RelayCreateTemporary : public MessageLoopRelay {
167  public:
RelayCreateTemporary(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,base::FileUtilProxy::CreateTemporaryCallback * callback)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:
~RelayCreateTemporary()178   virtual ~RelayCreateTemporary() {
179     if (file_handle_ != base::kInvalidPlatformFileValue)
180       base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
181   }
182 
RunWork()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;
195     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);
199   }
200 
RunCallback()201   virtual void RunCallback() {
202     callback_->Run(error_code(), base::PassPlatformFile(&file_handle_),
203                    file_path_);
204     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 
214 class RelayWithStatusCallback : public MessageLoopRelay {
215  public:
RelayWithStatusCallback(base::FileUtilProxy::StatusCallback * callback)216   explicit RelayWithStatusCallback(
217       base::FileUtilProxy::StatusCallback* callback)
218       : callback_(callback) {
219     // It is OK for callback to be NULL.
220   }
221 
222  protected:
RunCallback()223   virtual void RunCallback() {
224     // The caller may not have been interested in the result.
225     if (callback_) {
226       callback_->Run(error_code());
227       delete callback_;
228     }
229   }
230 
231  private:
232   base::FileUtilProxy::StatusCallback* callback_;
233 };
234 
235 class RelayClose : public RelayWithStatusCallback {
236  public:
RelayClose(base::PlatformFile file_handle,base::FileUtilProxy::StatusCallback * callback)237   RelayClose(base::PlatformFile file_handle,
238              base::FileUtilProxy::StatusCallback* callback)
239       : RelayWithStatusCallback(callback),
240         file_handle_(file_handle) {
241   }
242 
243  protected:
RunWork()244   virtual void RunWork() {
245     if (!base::ClosePlatformFile(file_handle_))
246       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
247   }
248 
249  private:
250   base::PlatformFile file_handle_;
251 };
252 
253 class RelayEnsureFileExists : public MessageLoopRelay {
254  public:
RelayEnsureFileExists(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,const FilePath & file_path,base::FileUtilProxy::EnsureFileExistsCallback * callback)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:
RunWork()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 
RunCallback()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 
302 class RelayDelete : public RelayWithStatusCallback {
303  public:
RelayDelete(const FilePath & file_path,bool recursive,base::FileUtilProxy::StatusCallback * callback)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:
RunWork()313   virtual void RunWork() {
314     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_)) {
320         set_error_code(base::PLATFORM_FILE_ERROR_NOT_EMPTY);
321         return;
322       }
323       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
324     }
325   }
326 
327  private:
328   FilePath file_path_;
329   bool recursive_;
330 };
331 
332 class RelayCopy : public RelayWithStatusCallback {
333  public:
RelayCopy(const FilePath & src_file_path,const FilePath & dest_file_path,base::FileUtilProxy::StatusCallback * callback)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:
RunWork()343   virtual void RunWork() {
344     set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy(
345         src_file_path_, dest_file_path_));
346     if (error_code() != base::PLATFORM_FILE_OK)
347       return;
348     if (!file_util::CopyDirectory(src_file_path_, dest_file_path_,
349         true /* recursive */))
350       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
351   }
352 
353  private:
354   FilePath src_file_path_;
355   FilePath dest_file_path_;
356 };
357 
358 class RelayMove : public RelayWithStatusCallback {
359  public:
RelayMove(const FilePath & src_file_path,const FilePath & dest_file_path,base::FileUtilProxy::StatusCallback * callback)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:
RunWork()369   virtual void RunWork() {
370     set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy(
371         src_file_path_, dest_file_path_));
372     if (error_code() != base::PLATFORM_FILE_OK)
373       return;
374     if (!file_util::Move(src_file_path_, dest_file_path_))
375       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
376   }
377 
378  private:
379   FilePath src_file_path_;
380   FilePath dest_file_path_;
381 };
382 
383 class RelayCreateDirectory : public RelayWithStatusCallback {
384  public:
RelayCreateDirectory(const FilePath & file_path,bool exclusive,bool recursive,base::FileUtilProxy::StatusCallback * callback)385   RelayCreateDirectory(
386       const FilePath& file_path,
387       bool exclusive,
388       bool recursive,
389       base::FileUtilProxy::StatusCallback* callback)
390       : RelayWithStatusCallback(callback),
391         file_path_(file_path),
392         exclusive_(exclusive),
393         recursive_(recursive) {
394   }
395 
396  protected:
RunWork()397   virtual void RunWork() {
398     bool path_exists = file_util::PathExists(file_path_);
399     // If parent dir of file doesn't exist.
400     if (!recursive_ && !file_util::PathExists(file_path_.DirName())) {
401       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_;
420   bool recursive_;
421 };
422 
423 class RelayReadDirectory : public MessageLoopRelay {
424  public:
RelayReadDirectory(const FilePath & file_path,base::FileUtilProxy::ReadDirectoryCallback * callback)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:
RunWork()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()) {
445       base::FileUtilProxy::Entry entry;
446       file_util::FileEnumerator::FindInfo info;
447       file_enum.GetFindInfo(&info);
448       entry.is_directory = file_enum.IsDirectory(info);
449       // 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 
RunCallback()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_;
464   std::vector<base::FileUtilProxy::Entry> entries_;
465 };
466 
467 class RelayGetFileInfo : public MessageLoopRelay {
468  public:
RelayGetFileInfo(const FilePath & file_path,base::FileUtilProxy::GetFileInfoCallback * callback)469   RelayGetFileInfo(const FilePath& file_path,
470                    base::FileUtilProxy::GetFileInfoCallback* callback)
471       : callback_(callback),
472         file_path_(file_path) {
473     DCHECK(callback);
474   }
475 
476  protected:
RunWork()477   virtual void RunWork() {
478     if (!file_util::PathExists(file_path_)) {
479       set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
480       return;
481     }
482     if (!file_util::GetFileInfo(file_path_, &file_info_))
483       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
484   }
485 
RunCallback()486   virtual void RunCallback() {
487     callback_->Run(error_code(), file_info_);
488     delete callback_;
489   }
490 
491  private:
492   base::FileUtilProxy::GetFileInfoCallback* callback_;
493   FilePath file_path_;
494   base::PlatformFileInfo file_info_;
495 };
496 
497 class RelayGetFileInfoFromPlatformFile : public MessageLoopRelay {
498  public:
RelayGetFileInfoFromPlatformFile(base::PlatformFile file,base::FileUtilProxy::GetFileInfoCallback * callback)499   RelayGetFileInfoFromPlatformFile(
500       base::PlatformFile file,
501       base::FileUtilProxy::GetFileInfoCallback* callback)
502       : callback_(callback),
503         file_(file) {
504     DCHECK(callback);
505   }
506 
507  protected:
RunWork()508   virtual void RunWork() {
509     if (!base::GetPlatformFileInfo(file_, &file_info_))
510       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
511   }
512 
RunCallback()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 
524 class RelayRead : public MessageLoopRelay {
525  public:
RelayRead(base::PlatformFile file,int64 offset,int bytes_to_read,base::FileUtilProxy::ReadCallback * callback)526   RelayRead(base::PlatformFile file,
527             int64 offset,
528             int bytes_to_read,
529             base::FileUtilProxy::ReadCallback* callback)
530       : file_(file),
531         offset_(offset),
532         buffer_(new char[bytes_to_read]),
533         bytes_to_read_(bytes_to_read),
534         callback_(callback),
535         bytes_read_(0) {
536   }
537 
538  protected:
RunWork()539   virtual void RunWork() {
540     bytes_read_ = base::ReadPlatformFile(file_, offset_, buffer_.get(),
541                                          bytes_to_read_);
542     if (bytes_read_ < 0)
543       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
544   }
545 
RunCallback()546   virtual void RunCallback() {
547     if (callback_) {
548       callback_->Run(error_code(), buffer_.get(), bytes_read_);
549       delete callback_;
550     }
551   }
552 
553  private:
554   base::PlatformFile file_;
555   int64 offset_;
556   scoped_array<char> buffer_;
557   int bytes_to_read_;
558   base::FileUtilProxy::ReadCallback* callback_;
559   int bytes_read_;
560 };
561 
562 class RelayWrite : public MessageLoopRelay {
563  public:
RelayWrite(base::PlatformFile file,int64 offset,const char * buffer,int bytes_to_write,base::FileUtilProxy::WriteCallback * callback)564   RelayWrite(base::PlatformFile file,
565              int64 offset,
566              const char* buffer,
567              int bytes_to_write,
568              base::FileUtilProxy::WriteCallback* callback)
569       : file_(file),
570         offset_(offset),
571         buffer_(new char[bytes_to_write]),
572         bytes_to_write_(bytes_to_write),
573         callback_(callback),
574         bytes_written_(0) {
575     memcpy(buffer_.get(), buffer, bytes_to_write);
576   }
577 
578  protected:
RunWork()579   virtual void RunWork() {
580     bytes_written_ = base::WritePlatformFile(file_, offset_, buffer_.get(),
581                                              bytes_to_write_);
582     if (bytes_written_ < 0)
583       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
584   }
585 
RunCallback()586   virtual void RunCallback() {
587     if (callback_) {
588       callback_->Run(error_code(), bytes_written_);
589       delete callback_;
590     }
591   }
592 
593  private:
594   base::PlatformFile file_;
595   int64 offset_;
596   scoped_array<char> buffer_;
597   int bytes_to_write_;
598   base::FileUtilProxy::WriteCallback* callback_;
599   int bytes_written_;
600 };
601 
602 class RelayTouch : public RelayWithStatusCallback {
603  public:
RelayTouch(base::PlatformFile file,const base::Time & last_access_time,const base::Time & last_modified_time,base::FileUtilProxy::StatusCallback * callback)604   RelayTouch(base::PlatformFile file,
605              const base::Time& last_access_time,
606              const base::Time& last_modified_time,
607              base::FileUtilProxy::StatusCallback* callback)
608       : RelayWithStatusCallback(callback),
609         file_(file),
610         last_access_time_(last_access_time),
611         last_modified_time_(last_modified_time) {
612   }
613 
614  protected:
RunWork()615   virtual void RunWork() {
616     if (!base::TouchPlatformFile(file_, last_access_time_, last_modified_time_))
617       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
618   }
619 
620  private:
621   base::PlatformFile file_;
622   base::Time last_access_time_;
623   base::Time last_modified_time_;
624 };
625 
626 class RelayTouchFilePath : public RelayWithStatusCallback {
627  public:
RelayTouchFilePath(const FilePath & file_path,const base::Time & last_access_time,const base::Time & last_modified_time,base::FileUtilProxy::StatusCallback * callback)628   RelayTouchFilePath(const FilePath& file_path,
629                      const base::Time& last_access_time,
630                      const base::Time& last_modified_time,
631                      base::FileUtilProxy::StatusCallback* callback)
632       : RelayWithStatusCallback(callback),
633         file_path_(file_path),
634         last_access_time_(last_access_time),
635         last_modified_time_(last_modified_time) {
636   }
637 
638  protected:
RunWork()639   virtual void RunWork() {
640     if (!file_util::TouchFile(
641             file_path_, last_access_time_, last_modified_time_))
642       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
643   }
644 
645  private:
646   FilePath file_path_;
647   base::Time last_access_time_;
648   base::Time last_modified_time_;
649 };
650 
651 class RelayTruncatePlatformFile : public RelayWithStatusCallback {
652  public:
RelayTruncatePlatformFile(base::PlatformFile file,int64 length,base::FileUtilProxy::StatusCallback * callback)653   RelayTruncatePlatformFile(base::PlatformFile file,
654                             int64 length,
655                             base::FileUtilProxy::StatusCallback* callback)
656       : RelayWithStatusCallback(callback),
657         file_(file),
658         length_(length) {
659   }
660 
661  protected:
RunWork()662   virtual void RunWork() {
663     if (!base::TruncatePlatformFile(file_, length_))
664       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
665   }
666 
667  private:
668   base::PlatformFile file_;
669   int64 length_;
670 };
671 
672 class RelayTruncate : public RelayWithStatusCallback {
673  public:
RelayTruncate(const FilePath & path,int64 length,base::FileUtilProxy::StatusCallback * callback)674   RelayTruncate(const FilePath& path,
675                 int64 length,
676                 base::FileUtilProxy::StatusCallback* callback)
677       : RelayWithStatusCallback(callback),
678         path_(path),
679         length_(length) {
680   }
681 
682  protected:
RunWork()683   virtual void RunWork() {
684     base::PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED);
685     base::PlatformFile file =
686         base::CreatePlatformFile(
687             path_,
688             base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
689             NULL,
690             &error_code);
691     if (error_code != base::PLATFORM_FILE_OK) {
692       set_error_code(error_code);
693       return;
694     }
695     if (!base::TruncatePlatformFile(file, length_))
696       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
697     base::ClosePlatformFile(file);
698   }
699 
700  private:
701   FilePath path_;
702   int64 length_;
703 };
704 
705 class RelayFlush : public RelayWithStatusCallback {
706  public:
RelayFlush(base::PlatformFile file,base::FileUtilProxy::StatusCallback * callback)707   RelayFlush(base::PlatformFile file,
708              base::FileUtilProxy::StatusCallback* callback)
709       : RelayWithStatusCallback(callback),
710         file_(file) {
711   }
712 
713  protected:
RunWork()714   virtual void RunWork() {
715     if (!base::FlushPlatformFile(file_))
716       set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
717   }
718 
719  private:
720   base::PlatformFile file_;
721 };
722 
Start(const tracked_objects::Location & from_here,scoped_refptr<base::MessageLoopProxy> message_loop_proxy,scoped_refptr<MessageLoopRelay> relay)723 bool Start(const tracked_objects::Location& from_here,
724            scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
725            scoped_refptr<MessageLoopRelay> relay) {
726   return relay->Start(message_loop_proxy, from_here);
727 }
728 
729 }  // namespace
730 
731 namespace base {
732 
733 // static
CreateOrOpen(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,int file_flags,CreateOrOpenCallback * callback)734 bool FileUtilProxy::CreateOrOpen(
735     scoped_refptr<MessageLoopProxy> message_loop_proxy,
736     const FilePath& file_path, int file_flags,
737     CreateOrOpenCallback* callback) {
738   return Start(FROM_HERE, message_loop_proxy, new RelayCreateOrOpen(
739       message_loop_proxy, file_path, file_flags, callback));
740 }
741 
742 // static
CreateTemporary(scoped_refptr<MessageLoopProxy> message_loop_proxy,CreateTemporaryCallback * callback)743 bool FileUtilProxy::CreateTemporary(
744     scoped_refptr<MessageLoopProxy> message_loop_proxy,
745     CreateTemporaryCallback* callback) {
746   return Start(FROM_HERE, message_loop_proxy,
747                new RelayCreateTemporary(message_loop_proxy, callback));
748 }
749 
750 // static
Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,base::PlatformFile file_handle,StatusCallback * callback)751 bool FileUtilProxy::Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,
752                           base::PlatformFile file_handle,
753                           StatusCallback* callback) {
754   return Start(FROM_HERE, message_loop_proxy,
755                new RelayClose(file_handle, callback));
756 }
757 
758 // static
EnsureFileExists(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,EnsureFileExistsCallback * callback)759 bool FileUtilProxy::EnsureFileExists(
760     scoped_refptr<MessageLoopProxy> message_loop_proxy,
761     const FilePath& file_path,
762     EnsureFileExistsCallback* callback) {
763   return Start(FROM_HERE, message_loop_proxy, new RelayEnsureFileExists(
764       message_loop_proxy, file_path, callback));
765 }
766 
767 // Retrieves the information about a file. It is invalid to pass NULL for the
768 // callback.
GetFileInfo(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,GetFileInfoCallback * callback)769 bool FileUtilProxy::GetFileInfo(
770     scoped_refptr<MessageLoopProxy> message_loop_proxy,
771     const FilePath& file_path,
772     GetFileInfoCallback* callback) {
773   return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo(
774                file_path, callback));
775 }
776 
777 // static
GetFileInfoFromPlatformFile(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,GetFileInfoCallback * callback)778 bool FileUtilProxy::GetFileInfoFromPlatformFile(
779     scoped_refptr<MessageLoopProxy> message_loop_proxy,
780     PlatformFile file,
781     GetFileInfoCallback* callback) {
782   return Start(FROM_HERE, message_loop_proxy,
783                new RelayGetFileInfoFromPlatformFile(file, callback));
784 }
785 
786 // static
ReadDirectory(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,ReadDirectoryCallback * callback)787 bool FileUtilProxy::ReadDirectory(
788     scoped_refptr<MessageLoopProxy> message_loop_proxy,
789     const FilePath& file_path,
790     ReadDirectoryCallback* callback) {
791   return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory(
792                file_path, callback));
793 }
794 
795 // static
CreateDirectory(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,bool exclusive,bool recursive,StatusCallback * callback)796 bool FileUtilProxy::CreateDirectory(
797     scoped_refptr<MessageLoopProxy> message_loop_proxy,
798     const FilePath& file_path,
799     bool exclusive,
800     bool recursive,
801     StatusCallback* callback) {
802   return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory(
803       file_path, exclusive, recursive, callback));
804 }
805 
806 // static
Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & src_file_path,const FilePath & dest_file_path,StatusCallback * callback)807 bool FileUtilProxy::Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy,
808                          const FilePath& src_file_path,
809                          const FilePath& dest_file_path,
810                          StatusCallback* callback) {
811   return Start(FROM_HERE, message_loop_proxy,
812                new RelayCopy(src_file_path, dest_file_path, callback));
813 }
814 
815 // static
Move(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & src_file_path,const FilePath & dest_file_path,StatusCallback * callback)816 bool FileUtilProxy::Move(scoped_refptr<MessageLoopProxy> message_loop_proxy,
817                          const FilePath& src_file_path,
818                          const FilePath& dest_file_path,
819                          StatusCallback* callback) {
820   return Start(FROM_HERE, message_loop_proxy,
821                new RelayMove(src_file_path, dest_file_path, callback));
822 }
823 
824 // static
Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,bool recursive,StatusCallback * callback)825 bool FileUtilProxy::Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,
826                            const FilePath& file_path,
827                            bool recursive,
828                            StatusCallback* callback) {
829   return Start(FROM_HERE, message_loop_proxy,
830                new RelayDelete(file_path, recursive, callback));
831 }
832 
833 // static
RecursiveDelete(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,StatusCallback * callback)834 bool FileUtilProxy::RecursiveDelete(
835     scoped_refptr<MessageLoopProxy> message_loop_proxy,
836     const FilePath& file_path,
837     StatusCallback* callback) {
838   return Start(FROM_HERE, message_loop_proxy,
839                new RelayDelete(file_path, true, callback));
840 }
841 
842 // static
Read(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,int64 offset,int bytes_to_read,ReadCallback * callback)843 bool FileUtilProxy::Read(
844     scoped_refptr<MessageLoopProxy> message_loop_proxy,
845     PlatformFile file,
846     int64 offset,
847     int bytes_to_read,
848     ReadCallback* callback) {
849   return Start(FROM_HERE, message_loop_proxy,
850                new RelayRead(file, offset, bytes_to_read, callback));
851 }
852 
853 // static
Write(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,int64 offset,const char * buffer,int bytes_to_write,WriteCallback * callback)854 bool 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     WriteCallback* callback) {
861   return Start(FROM_HERE, message_loop_proxy,
862                new RelayWrite(file, offset, buffer, bytes_to_write, callback));
863 }
864 
865 // static
Touch(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,const base::Time & last_access_time,const base::Time & last_modified_time,StatusCallback * callback)866 bool 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
Touch(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & file_path,const base::Time & last_access_time,const base::Time & last_modified_time,StatusCallback * callback)878 bool 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
Truncate(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,int64 length,StatusCallback * callback)890 bool FileUtilProxy::Truncate(
891     scoped_refptr<MessageLoopProxy> message_loop_proxy,
892     PlatformFile file,
893     int64 length,
894     StatusCallback* callback) {
895   return Start(FROM_HERE, message_loop_proxy,
896                new RelayTruncatePlatformFile(file, length, callback));
897 }
898 
899 // static
Truncate(scoped_refptr<MessageLoopProxy> message_loop_proxy,const FilePath & path,int64 length,StatusCallback * callback)900 bool 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));
907 }
908 
909 // static
Flush(scoped_refptr<MessageLoopProxy> message_loop_proxy,PlatformFile file,StatusCallback * callback)910 bool 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 
917 }  // namespace base
918