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