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