• 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