Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / base / files / file_proxy.cc
blobf995735d5bcd695a153e1e40133d09e577ee2cc9
1 // Copyright 2014 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.
5 #include "base/files/file_proxy.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/files/file.h"
10 #include "base/files/file_util.h"
11 #include "base/location.h"
12 #include "base/task_runner.h"
13 #include "base/task_runner_util.h"
15 namespace {
17 void FileDeleter(base::File file) {
20 } // namespace
22 namespace base {
24 class FileHelper {
25 public:
26 FileHelper(FileProxy* proxy, File file)
27 : file_(file.Pass()),
28 error_(File::FILE_ERROR_FAILED),
29 task_runner_(proxy->task_runner()),
30 proxy_(AsWeakPtr(proxy)) {
33 void PassFile() {
34 if (proxy_)
35 proxy_->SetFile(file_.Pass());
36 else if (file_.IsValid())
37 task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_)));
40 protected:
41 File file_;
42 File::Error error_;
44 private:
45 scoped_refptr<TaskRunner> task_runner_;
46 WeakPtr<FileProxy> proxy_;
47 DISALLOW_COPY_AND_ASSIGN(FileHelper);
50 namespace {
52 class GenericFileHelper : public FileHelper {
53 public:
54 GenericFileHelper(FileProxy* proxy, File file)
55 : FileHelper(proxy, file.Pass()) {
58 void Close() {
59 file_.Close();
60 error_ = File::FILE_OK;
63 void SetTimes(Time last_access_time, Time last_modified_time) {
64 bool rv = file_.SetTimes(last_access_time, last_modified_time);
65 error_ = rv ? File::FILE_OK : File::FILE_ERROR_FAILED;
68 void SetLength(int64 length) {
69 if (file_.SetLength(length))
70 error_ = File::FILE_OK;
73 void Flush() {
74 if (file_.Flush())
75 error_ = File::FILE_OK;
78 void Reply(const FileProxy::StatusCallback& callback) {
79 PassFile();
80 if (!callback.is_null())
81 callback.Run(error_);
84 private:
85 DISALLOW_COPY_AND_ASSIGN(GenericFileHelper);
88 class CreateOrOpenHelper : public FileHelper {
89 public:
90 CreateOrOpenHelper(FileProxy* proxy, File file)
91 : FileHelper(proxy, file.Pass()) {
94 void RunWork(const FilePath& file_path, int file_flags) {
95 file_.Initialize(file_path, file_flags);
96 error_ = file_.IsValid() ? File::FILE_OK : file_.error_details();
99 void Reply(const FileProxy::StatusCallback& callback) {
100 DCHECK(!callback.is_null());
101 PassFile();
102 callback.Run(error_);
105 private:
106 DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper);
109 class CreateTemporaryHelper : public FileHelper {
110 public:
111 CreateTemporaryHelper(FileProxy* proxy, File file)
112 : FileHelper(proxy, file.Pass()) {
115 void RunWork(uint32 additional_file_flags) {
116 // TODO(darin): file_util should have a variant of CreateTemporaryFile
117 // that returns a FilePath and a File.
118 if (!CreateTemporaryFile(&file_path_)) {
119 // TODO(davidben): base::CreateTemporaryFile should preserve the error
120 // code.
121 error_ = File::FILE_ERROR_FAILED;
122 return;
125 uint32 file_flags = File::FLAG_WRITE |
126 File::FLAG_TEMPORARY |
127 File::FLAG_CREATE_ALWAYS |
128 additional_file_flags;
130 file_.Initialize(file_path_, file_flags);
131 if (file_.IsValid()) {
132 error_ = File::FILE_OK;
133 } else {
134 error_ = file_.error_details();
135 DeleteFile(file_path_, false);
136 file_path_.clear();
140 void Reply(const FileProxy::CreateTemporaryCallback& callback) {
141 DCHECK(!callback.is_null());
142 PassFile();
143 callback.Run(error_, file_path_);
146 private:
147 FilePath file_path_;
148 DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper);
151 class GetInfoHelper : public FileHelper {
152 public:
153 GetInfoHelper(FileProxy* proxy, File file)
154 : FileHelper(proxy, file.Pass()) {
157 void RunWork() {
158 if (file_.GetInfo(&file_info_))
159 error_ = File::FILE_OK;
162 void Reply(const FileProxy::GetFileInfoCallback& callback) {
163 PassFile();
164 DCHECK(!callback.is_null());
165 callback.Run(error_, file_info_);
168 private:
169 File::Info file_info_;
170 DISALLOW_COPY_AND_ASSIGN(GetInfoHelper);
173 class ReadHelper : public FileHelper {
174 public:
175 ReadHelper(FileProxy* proxy, File file, int bytes_to_read)
176 : FileHelper(proxy, file.Pass()),
177 buffer_(new char[bytes_to_read]),
178 bytes_to_read_(bytes_to_read),
179 bytes_read_(0) {
182 void RunWork(int64 offset) {
183 bytes_read_ = file_.Read(offset, buffer_.get(), bytes_to_read_);
184 error_ = (bytes_read_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
187 void Reply(const FileProxy::ReadCallback& callback) {
188 PassFile();
189 DCHECK(!callback.is_null());
190 callback.Run(error_, buffer_.get(), bytes_read_);
193 private:
194 scoped_ptr<char[]> buffer_;
195 int bytes_to_read_;
196 int bytes_read_;
197 DISALLOW_COPY_AND_ASSIGN(ReadHelper);
200 class WriteHelper : public FileHelper {
201 public:
202 WriteHelper(FileProxy* proxy,
203 File file,
204 const char* buffer, int bytes_to_write)
205 : FileHelper(proxy, file.Pass()),
206 buffer_(new char[bytes_to_write]),
207 bytes_to_write_(bytes_to_write),
208 bytes_written_(0) {
209 memcpy(buffer_.get(), buffer, bytes_to_write);
212 void RunWork(int64 offset) {
213 bytes_written_ = file_.Write(offset, buffer_.get(), bytes_to_write_);
214 error_ = (bytes_written_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
217 void Reply(const FileProxy::WriteCallback& callback) {
218 PassFile();
219 if (!callback.is_null())
220 callback.Run(error_, bytes_written_);
223 private:
224 scoped_ptr<char[]> buffer_;
225 int bytes_to_write_;
226 int bytes_written_;
227 DISALLOW_COPY_AND_ASSIGN(WriteHelper);
230 } // namespace
232 FileProxy::FileProxy(TaskRunner* task_runner) : task_runner_(task_runner) {
235 FileProxy::~FileProxy() {
236 if (file_.IsValid())
237 task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_)));
240 bool FileProxy::CreateOrOpen(const FilePath& file_path,
241 uint32 file_flags,
242 const StatusCallback& callback) {
243 DCHECK(!file_.IsValid());
244 CreateOrOpenHelper* helper = new CreateOrOpenHelper(this, File());
245 return task_runner_->PostTaskAndReply(
246 FROM_HERE,
247 Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), file_path,
248 file_flags),
249 Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback));
252 bool FileProxy::CreateTemporary(uint32 additional_file_flags,
253 const CreateTemporaryCallback& callback) {
254 DCHECK(!file_.IsValid());
255 CreateTemporaryHelper* helper = new CreateTemporaryHelper(this, File());
256 return task_runner_->PostTaskAndReply(
257 FROM_HERE,
258 Bind(&CreateTemporaryHelper::RunWork, Unretained(helper),
259 additional_file_flags),
260 Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback));
263 bool FileProxy::IsValid() const {
264 return file_.IsValid();
267 void FileProxy::SetFile(File file) {
268 DCHECK(!file_.IsValid());
269 file_ = file.Pass();
272 File FileProxy::TakeFile() {
273 return file_.Pass();
276 PlatformFile FileProxy::GetPlatformFile() const {
277 return file_.GetPlatformFile();
280 bool FileProxy::Close(const StatusCallback& callback) {
281 DCHECK(file_.IsValid());
282 GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
283 return task_runner_->PostTaskAndReply(
284 FROM_HERE,
285 Bind(&GenericFileHelper::Close, Unretained(helper)),
286 Bind(&GenericFileHelper::Reply, Owned(helper), callback));
289 bool FileProxy::GetInfo(const GetFileInfoCallback& callback) {
290 DCHECK(file_.IsValid());
291 GetInfoHelper* helper = new GetInfoHelper(this, file_.Pass());
292 return task_runner_->PostTaskAndReply(
293 FROM_HERE,
294 Bind(&GetInfoHelper::RunWork, Unretained(helper)),
295 Bind(&GetInfoHelper::Reply, Owned(helper), callback));
298 bool FileProxy::Read(int64 offset,
299 int bytes_to_read,
300 const ReadCallback& callback) {
301 DCHECK(file_.IsValid());
302 if (bytes_to_read < 0)
303 return false;
305 ReadHelper* helper = new ReadHelper(this, file_.Pass(), bytes_to_read);
306 return task_runner_->PostTaskAndReply(
307 FROM_HERE,
308 Bind(&ReadHelper::RunWork, Unretained(helper), offset),
309 Bind(&ReadHelper::Reply, Owned(helper), callback));
312 bool FileProxy::Write(int64 offset,
313 const char* buffer,
314 int bytes_to_write,
315 const WriteCallback& callback) {
316 DCHECK(file_.IsValid());
317 if (bytes_to_write <= 0 || buffer == NULL)
318 return false;
320 WriteHelper* helper =
321 new WriteHelper(this, file_.Pass(), buffer, bytes_to_write);
322 return task_runner_->PostTaskAndReply(
323 FROM_HERE,
324 Bind(&WriteHelper::RunWork, Unretained(helper), offset),
325 Bind(&WriteHelper::Reply, Owned(helper), callback));
328 bool FileProxy::SetTimes(Time last_access_time,
329 Time last_modified_time,
330 const StatusCallback& callback) {
331 DCHECK(file_.IsValid());
332 GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
333 return task_runner_->PostTaskAndReply(
334 FROM_HERE,
335 Bind(&GenericFileHelper::SetTimes, Unretained(helper), last_access_time,
336 last_modified_time),
337 Bind(&GenericFileHelper::Reply, Owned(helper), callback));
340 bool FileProxy::SetLength(int64 length, const StatusCallback& callback) {
341 DCHECK(file_.IsValid());
342 GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
343 return task_runner_->PostTaskAndReply(
344 FROM_HERE,
345 Bind(&GenericFileHelper::SetLength, Unretained(helper), length),
346 Bind(&GenericFileHelper::Reply, Owned(helper), callback));
349 bool FileProxy::Flush(const StatusCallback& callback) {
350 DCHECK(file_.IsValid());
351 GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
352 return task_runner_->PostTaskAndReply(
353 FROM_HERE,
354 Bind(&GenericFileHelper::Flush, Unretained(helper)),
355 Bind(&GenericFileHelper::Reply, Owned(helper), callback));
358 } // namespace base