• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors
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_proxy.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "base/files/file.h"
11 #include "base/files/file_util.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback_helpers.h"
14 #include "base/location.h"
15 #include "base/task/task_runner.h"
16 
17 namespace {
18 
FileDeleter(base::File file)19 void FileDeleter(base::File file) {
20 }
21 
22 }  // namespace
23 
24 namespace base {
25 
26 class FileHelper {
27  public:
FileHelper(base::WeakPtr<FileProxy> proxy,File file)28   FileHelper(base::WeakPtr<FileProxy> proxy, File file)
29       : file_(std::move(file)),
30         task_runner_(proxy->task_runner()),
31         proxy_(proxy) {}
32   FileHelper(const FileHelper&) = delete;
33   FileHelper& operator=(const FileHelper&) = delete;
34 
PassFile()35   void PassFile() {
36     if (proxy_)
37       proxy_->SetFile(std::move(file_));
38     else if (file_.IsValid())
39       task_runner_->PostTask(FROM_HERE,
40                              BindOnce(&FileDeleter, std::move(file_)));
41   }
42 
43  protected:
44   File file_;
45   File::Error error_ = File::FILE_ERROR_FAILED;
46 
47  private:
48   scoped_refptr<TaskRunner> task_runner_;
49   WeakPtr<FileProxy> proxy_;
50 };
51 
52 namespace {
53 
54 class GenericFileHelper : public FileHelper {
55  public:
GenericFileHelper(base::WeakPtr<FileProxy> proxy,File file)56   GenericFileHelper(base::WeakPtr<FileProxy> proxy, File file)
57       : FileHelper(std::move(proxy), std::move(file)) {}
58   GenericFileHelper(const GenericFileHelper&) = delete;
59   GenericFileHelper& operator=(const GenericFileHelper&) = delete;
60 
Close()61   void Close() {
62     file_.Close();
63     error_ = File::FILE_OK;
64   }
65 
SetTimes(Time last_access_time,Time last_modified_time)66   void SetTimes(Time last_access_time, Time last_modified_time) {
67     bool rv = file_.SetTimes(last_access_time, last_modified_time);
68     error_ = rv ? File::FILE_OK : File::FILE_ERROR_FAILED;
69   }
70 
SetLength(int64_t length)71   void SetLength(int64_t length) {
72     if (file_.SetLength(length))
73       error_ = File::FILE_OK;
74   }
75 
Flush()76   void Flush() {
77     if (file_.Flush())
78       error_ = File::FILE_OK;
79   }
80 
Reply(FileProxy::StatusCallback callback)81   void Reply(FileProxy::StatusCallback callback) {
82     PassFile();
83     if (!callback.is_null())
84       std::move(callback).Run(error_);
85   }
86 };
87 
88 class CreateOrOpenHelper : public FileHelper {
89  public:
CreateOrOpenHelper(base::WeakPtr<FileProxy> proxy,File file)90   CreateOrOpenHelper(base::WeakPtr<FileProxy> proxy, File file)
91       : FileHelper(std::move(proxy), std::move(file)) {}
92   CreateOrOpenHelper(const CreateOrOpenHelper&) = delete;
93   CreateOrOpenHelper& operator=(const CreateOrOpenHelper&) = delete;
94 
RunWork(const FilePath & file_path,uint32_t file_flags)95   void RunWork(const FilePath& file_path, uint32_t file_flags) {
96     file_.Initialize(file_path, file_flags);
97     error_ = file_.IsValid() ? File::FILE_OK : file_.error_details();
98   }
99 
Reply(FileProxy::StatusCallback callback)100   void Reply(FileProxy::StatusCallback callback) {
101     DCHECK(!callback.is_null());
102     PassFile();
103     std::move(callback).Run(error_);
104   }
105 };
106 
107 class CreateTemporaryHelper : public FileHelper {
108  public:
CreateTemporaryHelper(base::WeakPtr<FileProxy> proxy,File file)109   CreateTemporaryHelper(base::WeakPtr<FileProxy> proxy, File file)
110       : FileHelper(std::move(proxy), std::move(file)) {}
111   CreateTemporaryHelper(const CreateTemporaryHelper&) = delete;
112   CreateTemporaryHelper& operator=(const CreateTemporaryHelper&) = delete;
113 
RunWork(uint32_t additional_file_flags)114   void RunWork(uint32_t additional_file_flags) {
115     // TODO(darin): file_util should have a variant of CreateTemporaryFile
116     // that returns a FilePath and a File.
117     if (!CreateTemporaryFile(&file_path_)) {
118       // TODO(davidben): base::CreateTemporaryFile should preserve the error
119       // code.
120       error_ = File::FILE_ERROR_FAILED;
121       return;
122     }
123 
124     uint32_t file_flags = File::FLAG_WRITE | File::FLAG_WIN_TEMPORARY |
125                           File::FLAG_CREATE_ALWAYS | additional_file_flags;
126 
127     file_.Initialize(file_path_, file_flags);
128     if (file_.IsValid()) {
129       error_ = File::FILE_OK;
130     } else {
131       error_ = file_.error_details();
132       DeleteFile(file_path_);
133       file_path_.clear();
134     }
135   }
136 
Reply(FileProxy::CreateTemporaryCallback callback)137   void Reply(FileProxy::CreateTemporaryCallback callback) {
138     DCHECK(!callback.is_null());
139     PassFile();
140     std::move(callback).Run(error_, file_path_);
141   }
142 
143  private:
144   FilePath file_path_;
145 };
146 
147 class GetInfoHelper : public FileHelper {
148  public:
GetInfoHelper(base::WeakPtr<FileProxy> proxy,File file)149   GetInfoHelper(base::WeakPtr<FileProxy> proxy, File file)
150       : FileHelper(std::move(proxy), std::move(file)) {}
151   GetInfoHelper(const GetInfoHelper&) = delete;
152   GetInfoHelper& operator=(const GetInfoHelper&) = delete;
153 
RunWork()154   void RunWork() {
155     if (file_.GetInfo(&file_info_))
156       error_  = File::FILE_OK;
157   }
158 
Reply(FileProxy::GetFileInfoCallback callback)159   void Reply(FileProxy::GetFileInfoCallback callback) {
160     PassFile();
161     DCHECK(!callback.is_null());
162     std::move(callback).Run(error_, file_info_);
163   }
164 
165  private:
166   File::Info file_info_;
167 };
168 
169 class ReadHelper : public FileHelper {
170  public:
ReadHelper(base::WeakPtr<FileProxy> proxy,File file,int bytes_to_read)171   ReadHelper(base::WeakPtr<FileProxy> proxy, File file, int bytes_to_read)
172       : FileHelper(std::move(proxy), std::move(file)),
173         buffer_(new char[static_cast<size_t>(bytes_to_read)]),
174         bytes_to_read_(bytes_to_read) {}
175   ReadHelper(const ReadHelper&) = delete;
176   ReadHelper& operator=(const ReadHelper&) = delete;
177 
RunWork(int64_t offset)178   void RunWork(int64_t offset) {
179     bytes_read_ = file_.Read(offset, buffer_.get(), bytes_to_read_);
180     error_ = (bytes_read_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
181   }
182 
Reply(FileProxy::ReadCallback callback)183   void Reply(FileProxy::ReadCallback callback) {
184     PassFile();
185     DCHECK(!callback.is_null());
186     std::move(callback).Run(error_, buffer_.get(), bytes_read_);
187   }
188 
189  private:
190   std::unique_ptr<char[]> buffer_;
191   int bytes_to_read_;
192   int bytes_read_ = 0;
193 };
194 
195 class WriteHelper : public FileHelper {
196  public:
WriteHelper(base::WeakPtr<FileProxy> proxy,File file,const char * buffer,int bytes_to_write)197   WriteHelper(base::WeakPtr<FileProxy> proxy,
198               File file,
199               const char* buffer,
200               int bytes_to_write)
201       : FileHelper(std::move(proxy), std::move(file)),
202         buffer_(new char[static_cast<size_t>(bytes_to_write)]),
203         bytes_to_write_(bytes_to_write) {
204     memcpy(buffer_.get(), buffer, static_cast<size_t>(bytes_to_write));
205   }
206   WriteHelper(const WriteHelper&) = delete;
207   WriteHelper& operator=(const WriteHelper&) = delete;
208 
RunWork(int64_t offset)209   void RunWork(int64_t offset) {
210     bytes_written_ = file_.Write(offset, buffer_.get(), bytes_to_write_);
211     error_ = (bytes_written_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
212   }
213 
Reply(FileProxy::WriteCallback callback)214   void Reply(FileProxy::WriteCallback callback) {
215     PassFile();
216     if (!callback.is_null())
217       std::move(callback).Run(error_, bytes_written_);
218   }
219 
220  private:
221   std::unique_ptr<char[]> buffer_;
222   int bytes_to_write_;
223   int bytes_written_ = 0;
224 };
225 
226 }  // namespace
227 
FileProxy(TaskRunner * task_runner)228 FileProxy::FileProxy(TaskRunner* task_runner) : task_runner_(task_runner) {
229 }
230 
~FileProxy()231 FileProxy::~FileProxy() {
232   if (file_.IsValid())
233     task_runner_->PostTask(FROM_HERE, BindOnce(&FileDeleter, std::move(file_)));
234 }
235 
CreateOrOpen(const FilePath & file_path,uint32_t file_flags,StatusCallback callback)236 bool FileProxy::CreateOrOpen(const FilePath& file_path,
237                              uint32_t file_flags,
238                              StatusCallback callback) {
239   DCHECK(!file_.IsValid());
240   CreateOrOpenHelper* helper =
241       new CreateOrOpenHelper(weak_ptr_factory_.GetWeakPtr(), File());
242   return task_runner_->PostTaskAndReply(
243       FROM_HERE,
244       BindOnce(&CreateOrOpenHelper::RunWork, Unretained(helper), file_path,
245                file_flags),
246       BindOnce(&CreateOrOpenHelper::Reply, Owned(helper), std::move(callback)));
247 }
248 
CreateTemporary(uint32_t additional_file_flags,CreateTemporaryCallback callback)249 bool FileProxy::CreateTemporary(uint32_t additional_file_flags,
250                                 CreateTemporaryCallback callback) {
251   DCHECK(!file_.IsValid());
252   CreateTemporaryHelper* helper =
253       new CreateTemporaryHelper(weak_ptr_factory_.GetWeakPtr(), File());
254   return task_runner_->PostTaskAndReply(
255       FROM_HERE,
256       BindOnce(&CreateTemporaryHelper::RunWork, Unretained(helper),
257                additional_file_flags),
258       BindOnce(&CreateTemporaryHelper::Reply, Owned(helper),
259                std::move(callback)));
260 }
261 
IsValid() const262 bool FileProxy::IsValid() const {
263   return file_.IsValid();
264 }
265 
SetFile(File file)266 void FileProxy::SetFile(File file) {
267   DCHECK(!file_.IsValid());
268   file_ = std::move(file);
269 }
270 
TakeFile()271 File FileProxy::TakeFile() {
272   return std::move(file_);
273 }
274 
DuplicateFile()275 File FileProxy::DuplicateFile() {
276   return file_.Duplicate();
277 }
278 
GetPlatformFile() const279 PlatformFile FileProxy::GetPlatformFile() const {
280   return file_.GetPlatformFile();
281 }
282 
Close(StatusCallback callback)283 bool FileProxy::Close(StatusCallback callback) {
284   DCHECK(file_.IsValid());
285   GenericFileHelper* helper =
286       new GenericFileHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
287   return task_runner_->PostTaskAndReply(
288       FROM_HERE, BindOnce(&GenericFileHelper::Close, Unretained(helper)),
289       BindOnce(&GenericFileHelper::Reply, Owned(helper), std::move(callback)));
290 }
291 
GetInfo(GetFileInfoCallback callback)292 bool FileProxy::GetInfo(GetFileInfoCallback callback) {
293   DCHECK(file_.IsValid());
294   GetInfoHelper* helper =
295       new GetInfoHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
296   return task_runner_->PostTaskAndReply(
297       FROM_HERE, BindOnce(&GetInfoHelper::RunWork, Unretained(helper)),
298       BindOnce(&GetInfoHelper::Reply, Owned(helper), std::move(callback)));
299 }
300 
Read(int64_t offset,int bytes_to_read,ReadCallback callback)301 bool FileProxy::Read(int64_t offset, int bytes_to_read, ReadCallback callback) {
302   DCHECK(file_.IsValid());
303   if (bytes_to_read < 0)
304     return false;
305 
306   ReadHelper* helper = new ReadHelper(weak_ptr_factory_.GetWeakPtr(),
307                                       std::move(file_), bytes_to_read);
308   return task_runner_->PostTaskAndReply(
309       FROM_HERE, BindOnce(&ReadHelper::RunWork, Unretained(helper), offset),
310       BindOnce(&ReadHelper::Reply, Owned(helper), std::move(callback)));
311 }
312 
Write(int64_t offset,const char * buffer,int bytes_to_write,WriteCallback callback)313 bool FileProxy::Write(int64_t offset,
314                       const char* buffer,
315                       int bytes_to_write,
316                       WriteCallback callback) {
317   DCHECK(file_.IsValid());
318   if (bytes_to_write <= 0 || buffer == nullptr)
319     return false;
320 
321   WriteHelper* helper = new WriteHelper(
322       weak_ptr_factory_.GetWeakPtr(), std::move(file_), buffer, bytes_to_write);
323   return task_runner_->PostTaskAndReply(
324       FROM_HERE, BindOnce(&WriteHelper::RunWork, Unretained(helper), offset),
325       BindOnce(&WriteHelper::Reply, Owned(helper), std::move(callback)));
326 }
327 
SetTimes(Time last_access_time,Time last_modified_time,StatusCallback callback)328 bool FileProxy::SetTimes(Time last_access_time,
329                          Time last_modified_time,
330                          StatusCallback callback) {
331   DCHECK(file_.IsValid());
332   GenericFileHelper* helper =
333       new GenericFileHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
334   return task_runner_->PostTaskAndReply(
335       FROM_HERE,
336       BindOnce(&GenericFileHelper::SetTimes, Unretained(helper),
337                last_access_time, last_modified_time),
338       BindOnce(&GenericFileHelper::Reply, Owned(helper), std::move(callback)));
339 }
340 
SetLength(int64_t length,StatusCallback callback)341 bool FileProxy::SetLength(int64_t length, StatusCallback callback) {
342   DCHECK(file_.IsValid());
343   GenericFileHelper* helper =
344       new GenericFileHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
345   return task_runner_->PostTaskAndReply(
346       FROM_HERE,
347       BindOnce(&GenericFileHelper::SetLength, Unretained(helper), length),
348       BindOnce(&GenericFileHelper::Reply, Owned(helper), std::move(callback)));
349 }
350 
Flush(StatusCallback callback)351 bool FileProxy::Flush(StatusCallback callback) {
352   DCHECK(file_.IsValid());
353   GenericFileHelper* helper =
354       new GenericFileHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
355   return task_runner_->PostTaskAndReply(
356       FROM_HERE, BindOnce(&GenericFileHelper::Flush, Unretained(helper)),
357       BindOnce(&GenericFileHelper::Reply, Owned(helper), std::move(callback)));
358 }
359 
360 }  // namespace base
361