• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/files/file_util_proxy.h"
6 
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/file_util.h"
10 #include "base/location.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/task_runner.h"
13 #include "base/task_runner_util.h"
14 
15 namespace base {
16 
17 namespace {
18 
CallWithTranslatedParameter(const FileUtilProxy::StatusCallback & callback,bool value)19 void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback,
20                                  bool value) {
21   DCHECK(!callback.is_null());
22   callback.Run(value ? PLATFORM_FILE_OK : PLATFORM_FILE_ERROR_FAILED);
23 }
24 
25 // Helper classes or routines for individual methods.
26 class CreateOrOpenHelper {
27  public:
CreateOrOpenHelper(TaskRunner * task_runner,const FileUtilProxy::CloseTask & close_task)28   CreateOrOpenHelper(TaskRunner* task_runner,
29                      const FileUtilProxy::CloseTask& close_task)
30       : task_runner_(task_runner),
31         close_task_(close_task),
32         file_handle_(kInvalidPlatformFileValue),
33         created_(false),
34         error_(PLATFORM_FILE_OK) {}
35 
~CreateOrOpenHelper()36   ~CreateOrOpenHelper() {
37     if (file_handle_ != kInvalidPlatformFileValue) {
38       task_runner_->PostTask(
39           FROM_HERE,
40           base::Bind(base::IgnoreResult(close_task_), file_handle_));
41     }
42   }
43 
RunWork(const FileUtilProxy::CreateOrOpenTask & task)44   void RunWork(const FileUtilProxy::CreateOrOpenTask& task) {
45     error_ = task.Run(&file_handle_, &created_);
46   }
47 
Reply(const FileUtilProxy::CreateOrOpenCallback & callback)48   void Reply(const FileUtilProxy::CreateOrOpenCallback& callback) {
49     DCHECK(!callback.is_null());
50     callback.Run(error_, PassPlatformFile(&file_handle_), created_);
51   }
52 
53  private:
54   scoped_refptr<TaskRunner> task_runner_;
55   FileUtilProxy::CloseTask close_task_;
56   PlatformFile file_handle_;
57   bool created_;
58   PlatformFileError error_;
59   DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper);
60 };
61 
62 class CreateTemporaryHelper {
63  public:
CreateTemporaryHelper(TaskRunner * task_runner)64   explicit CreateTemporaryHelper(TaskRunner* task_runner)
65       : task_runner_(task_runner),
66         file_handle_(kInvalidPlatformFileValue),
67         error_(PLATFORM_FILE_OK) {}
68 
~CreateTemporaryHelper()69   ~CreateTemporaryHelper() {
70     if (file_handle_ != kInvalidPlatformFileValue) {
71       FileUtilProxy::Close(
72           task_runner_.get(), file_handle_, FileUtilProxy::StatusCallback());
73     }
74   }
75 
RunWork(int additional_file_flags)76   void RunWork(int additional_file_flags) {
77     // TODO(darin): file_util should have a variant of CreateTemporaryFile
78     // that returns a FilePath and a PlatformFile.
79     base::CreateTemporaryFile(&file_path_);
80 
81     int file_flags =
82         PLATFORM_FILE_WRITE |
83         PLATFORM_FILE_TEMPORARY |
84         PLATFORM_FILE_CREATE_ALWAYS |
85         additional_file_flags;
86 
87     error_ = PLATFORM_FILE_OK;
88     file_handle_ = CreatePlatformFile(file_path_, file_flags, NULL, &error_);
89   }
90 
Reply(const FileUtilProxy::CreateTemporaryCallback & callback)91   void Reply(const FileUtilProxy::CreateTemporaryCallback& callback) {
92     DCHECK(!callback.is_null());
93     callback.Run(error_, PassPlatformFile(&file_handle_), file_path_);
94   }
95 
96  private:
97   scoped_refptr<TaskRunner> task_runner_;
98   PlatformFile file_handle_;
99   FilePath file_path_;
100   PlatformFileError error_;
101   DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper);
102 };
103 
104 class GetFileInfoHelper {
105  public:
GetFileInfoHelper()106   GetFileInfoHelper()
107       : error_(PLATFORM_FILE_OK) {}
108 
RunWorkForFilePath(const FilePath & file_path)109   void RunWorkForFilePath(const FilePath& file_path) {
110     if (!PathExists(file_path)) {
111       error_ = PLATFORM_FILE_ERROR_NOT_FOUND;
112       return;
113     }
114     if (!GetFileInfo(file_path, &file_info_))
115       error_ = PLATFORM_FILE_ERROR_FAILED;
116   }
117 
RunWorkForPlatformFile(PlatformFile file)118   void RunWorkForPlatformFile(PlatformFile file) {
119     if (!GetPlatformFileInfo(file, &file_info_))
120       error_ = PLATFORM_FILE_ERROR_FAILED;
121   }
122 
Reply(const FileUtilProxy::GetFileInfoCallback & callback)123   void Reply(const FileUtilProxy::GetFileInfoCallback& callback) {
124     if (!callback.is_null()) {
125       callback.Run(error_, file_info_);
126     }
127   }
128 
129  private:
130   PlatformFileError error_;
131   PlatformFileInfo file_info_;
132   DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper);
133 };
134 
135 class ReadHelper {
136  public:
ReadHelper(int bytes_to_read)137   explicit ReadHelper(int bytes_to_read)
138       : buffer_(new char[bytes_to_read]),
139         bytes_to_read_(bytes_to_read),
140         bytes_read_(0) {}
141 
RunWork(PlatformFile file,int64 offset)142   void RunWork(PlatformFile file, int64 offset) {
143     bytes_read_ = ReadPlatformFile(file, offset, buffer_.get(), bytes_to_read_);
144   }
145 
Reply(const FileUtilProxy::ReadCallback & callback)146   void Reply(const FileUtilProxy::ReadCallback& callback) {
147     if (!callback.is_null()) {
148       PlatformFileError error =
149           (bytes_read_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK;
150       callback.Run(error, buffer_.get(), bytes_read_);
151     }
152   }
153 
154  private:
155   scoped_ptr<char[]> buffer_;
156   int bytes_to_read_;
157   int bytes_read_;
158   DISALLOW_COPY_AND_ASSIGN(ReadHelper);
159 };
160 
161 class WriteHelper {
162  public:
WriteHelper(const char * buffer,int bytes_to_write)163   WriteHelper(const char* buffer, int bytes_to_write)
164       : buffer_(new char[bytes_to_write]),
165         bytes_to_write_(bytes_to_write),
166         bytes_written_(0) {
167     memcpy(buffer_.get(), buffer, bytes_to_write);
168   }
169 
RunWork(PlatformFile file,int64 offset)170   void RunWork(PlatformFile file, int64 offset) {
171     bytes_written_ = WritePlatformFile(file, offset, buffer_.get(),
172                                        bytes_to_write_);
173   }
174 
Reply(const FileUtilProxy::WriteCallback & callback)175   void Reply(const FileUtilProxy::WriteCallback& callback) {
176     if (!callback.is_null()) {
177       PlatformFileError error =
178           (bytes_written_ < 0) ? PLATFORM_FILE_ERROR_FAILED : PLATFORM_FILE_OK;
179       callback.Run(error, bytes_written_);
180     }
181   }
182 
183  private:
184   scoped_ptr<char[]> buffer_;
185   int bytes_to_write_;
186   int bytes_written_;
187   DISALLOW_COPY_AND_ASSIGN(WriteHelper);
188 };
189 
CreateOrOpenAdapter(const FilePath & file_path,int file_flags,PlatformFile * file_handle,bool * created)190 PlatformFileError CreateOrOpenAdapter(
191     const FilePath& file_path, int file_flags,
192     PlatformFile* file_handle, bool* created) {
193   DCHECK(file_handle);
194   DCHECK(created);
195   if (!DirectoryExists(file_path.DirName())) {
196     // If its parent does not exist, should return NOT_FOUND error.
197     return PLATFORM_FILE_ERROR_NOT_FOUND;
198   }
199   PlatformFileError error = PLATFORM_FILE_OK;
200   *file_handle = CreatePlatformFile(file_path, file_flags, created, &error);
201   return error;
202 }
203 
CloseAdapter(PlatformFile file_handle)204 PlatformFileError CloseAdapter(PlatformFile file_handle) {
205   if (!ClosePlatformFile(file_handle)) {
206     return PLATFORM_FILE_ERROR_FAILED;
207   }
208   return PLATFORM_FILE_OK;
209 }
210 
DeleteAdapter(const FilePath & file_path,bool recursive)211 PlatformFileError DeleteAdapter(const FilePath& file_path, bool recursive) {
212   if (!PathExists(file_path)) {
213     return PLATFORM_FILE_ERROR_NOT_FOUND;
214   }
215   if (!base::DeleteFile(file_path, recursive)) {
216     if (!recursive && !base::IsDirectoryEmpty(file_path)) {
217       return PLATFORM_FILE_ERROR_NOT_EMPTY;
218     }
219     return PLATFORM_FILE_ERROR_FAILED;
220   }
221   return PLATFORM_FILE_OK;
222 }
223 
224 }  // namespace
225 
226 // static
CreateOrOpen(TaskRunner * task_runner,const FilePath & file_path,int file_flags,const CreateOrOpenCallback & callback)227 bool FileUtilProxy::CreateOrOpen(
228     TaskRunner* task_runner,
229     const FilePath& file_path, int file_flags,
230     const CreateOrOpenCallback& callback) {
231   return RelayCreateOrOpen(
232       task_runner,
233       base::Bind(&CreateOrOpenAdapter, file_path, file_flags),
234       base::Bind(&CloseAdapter),
235       callback);
236 }
237 
238 // static
CreateTemporary(TaskRunner * task_runner,int additional_file_flags,const CreateTemporaryCallback & callback)239 bool FileUtilProxy::CreateTemporary(
240     TaskRunner* task_runner,
241     int additional_file_flags,
242     const CreateTemporaryCallback& callback) {
243   CreateTemporaryHelper* helper = new CreateTemporaryHelper(task_runner);
244   return task_runner->PostTaskAndReply(
245       FROM_HERE,
246       Bind(&CreateTemporaryHelper::RunWork, Unretained(helper),
247            additional_file_flags),
248       Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback));
249 }
250 
251 // static
Close(TaskRunner * task_runner,base::PlatformFile file_handle,const StatusCallback & callback)252 bool FileUtilProxy::Close(
253     TaskRunner* task_runner,
254     base::PlatformFile file_handle,
255     const StatusCallback& callback) {
256   return RelayClose(
257       task_runner,
258       base::Bind(&CloseAdapter),
259       file_handle, callback);
260 }
261 
262 // Retrieves the information about a file. It is invalid to pass NULL for the
263 // callback.
GetFileInfo(TaskRunner * task_runner,const FilePath & file_path,const GetFileInfoCallback & callback)264 bool FileUtilProxy::GetFileInfo(
265     TaskRunner* task_runner,
266     const FilePath& file_path,
267     const GetFileInfoCallback& callback) {
268   GetFileInfoHelper* helper = new GetFileInfoHelper;
269   return task_runner->PostTaskAndReply(
270       FROM_HERE,
271       Bind(&GetFileInfoHelper::RunWorkForFilePath,
272            Unretained(helper), file_path),
273       Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
274 }
275 
276 // static
GetFileInfoFromPlatformFile(TaskRunner * task_runner,PlatformFile file,const GetFileInfoCallback & callback)277 bool FileUtilProxy::GetFileInfoFromPlatformFile(
278     TaskRunner* task_runner,
279     PlatformFile file,
280     const GetFileInfoCallback& callback) {
281   GetFileInfoHelper* helper = new GetFileInfoHelper;
282   return task_runner->PostTaskAndReply(
283       FROM_HERE,
284       Bind(&GetFileInfoHelper::RunWorkForPlatformFile,
285            Unretained(helper), file),
286       Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
287 }
288 
289 // static
DeleteFile(TaskRunner * task_runner,const FilePath & file_path,bool recursive,const StatusCallback & callback)290 bool FileUtilProxy::DeleteFile(TaskRunner* task_runner,
291                                const FilePath& file_path,
292                                bool recursive,
293                                const StatusCallback& callback) {
294   return base::PostTaskAndReplyWithResult(
295       task_runner, FROM_HERE,
296       Bind(&DeleteAdapter, file_path, recursive),
297       callback);
298 }
299 
300 // static
Read(TaskRunner * task_runner,PlatformFile file,int64 offset,int bytes_to_read,const ReadCallback & callback)301 bool FileUtilProxy::Read(
302     TaskRunner* task_runner,
303     PlatformFile file,
304     int64 offset,
305     int bytes_to_read,
306     const ReadCallback& callback) {
307   if (bytes_to_read < 0) {
308     return false;
309   }
310   ReadHelper* helper = new ReadHelper(bytes_to_read);
311   return task_runner->PostTaskAndReply(
312       FROM_HERE,
313       Bind(&ReadHelper::RunWork, Unretained(helper), file, offset),
314       Bind(&ReadHelper::Reply, Owned(helper), callback));
315 }
316 
317 // static
Write(TaskRunner * task_runner,PlatformFile file,int64 offset,const char * buffer,int bytes_to_write,const WriteCallback & callback)318 bool FileUtilProxy::Write(
319     TaskRunner* task_runner,
320     PlatformFile file,
321     int64 offset,
322     const char* buffer,
323     int bytes_to_write,
324     const WriteCallback& callback) {
325   if (bytes_to_write <= 0 || buffer == NULL) {
326     return false;
327   }
328   WriteHelper* helper = new WriteHelper(buffer, bytes_to_write);
329   return task_runner->PostTaskAndReply(
330       FROM_HERE,
331       Bind(&WriteHelper::RunWork, Unretained(helper), file, offset),
332       Bind(&WriteHelper::Reply, Owned(helper), callback));
333 }
334 
335 // static
Touch(TaskRunner * task_runner,PlatformFile file,const Time & last_access_time,const Time & last_modified_time,const StatusCallback & callback)336 bool FileUtilProxy::Touch(
337     TaskRunner* task_runner,
338     PlatformFile file,
339     const Time& last_access_time,
340     const Time& last_modified_time,
341     const StatusCallback& callback) {
342   return base::PostTaskAndReplyWithResult(
343       task_runner,
344       FROM_HERE,
345       Bind(&TouchPlatformFile, file,
346            last_access_time, last_modified_time),
347       Bind(&CallWithTranslatedParameter, callback));
348 }
349 
350 // static
Touch(TaskRunner * task_runner,const FilePath & file_path,const Time & last_access_time,const Time & last_modified_time,const StatusCallback & callback)351 bool FileUtilProxy::Touch(
352     TaskRunner* task_runner,
353     const FilePath& file_path,
354     const Time& last_access_time,
355     const Time& last_modified_time,
356     const StatusCallback& callback) {
357   return base::PostTaskAndReplyWithResult(
358       task_runner,
359       FROM_HERE,
360       Bind(&TouchFile, file_path, last_access_time, last_modified_time),
361       Bind(&CallWithTranslatedParameter, callback));
362 }
363 
364 // static
Truncate(TaskRunner * task_runner,PlatformFile file,int64 length,const StatusCallback & callback)365 bool FileUtilProxy::Truncate(
366     TaskRunner* task_runner,
367     PlatformFile file,
368     int64 length,
369     const StatusCallback& callback) {
370   return base::PostTaskAndReplyWithResult(
371       task_runner,
372       FROM_HERE,
373       Bind(&TruncatePlatformFile, file, length),
374       Bind(&CallWithTranslatedParameter, callback));
375 }
376 
377 // static
Flush(TaskRunner * task_runner,PlatformFile file,const StatusCallback & callback)378 bool FileUtilProxy::Flush(
379     TaskRunner* task_runner,
380     PlatformFile file,
381     const StatusCallback& callback) {
382   return base::PostTaskAndReplyWithResult(
383       task_runner,
384       FROM_HERE,
385       Bind(&FlushPlatformFile, file),
386       Bind(&CallWithTranslatedParameter, callback));
387 }
388 
389 // static
RelayCreateOrOpen(TaskRunner * task_runner,const CreateOrOpenTask & open_task,const CloseTask & close_task,const CreateOrOpenCallback & callback)390 bool FileUtilProxy::RelayCreateOrOpen(
391     TaskRunner* task_runner,
392     const CreateOrOpenTask& open_task,
393     const CloseTask& close_task,
394     const CreateOrOpenCallback& callback) {
395   CreateOrOpenHelper* helper = new CreateOrOpenHelper(
396       task_runner, close_task);
397   return task_runner->PostTaskAndReply(
398       FROM_HERE,
399       Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), open_task),
400       Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback));
401 }
402 
403 // static
RelayClose(TaskRunner * task_runner,const CloseTask & close_task,PlatformFile file_handle,const StatusCallback & callback)404 bool FileUtilProxy::RelayClose(
405     TaskRunner* task_runner,
406     const CloseTask& close_task,
407     PlatformFile file_handle,
408     const StatusCallback& callback) {
409   return base::PostTaskAndReplyWithResult(
410       task_runner, FROM_HERE, Bind(close_task, file_handle), callback);
411 }
412 
413 }  // namespace base
414