Upstream version 6.35.121.0
[platform/framework/web/crosswalk.git] / src / base / files / file_proxy.cc
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.
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
16 namespace base {
17
18 class 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
40 namespace {
41
42 class 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
78 class 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
99 class 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
141 class 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
163 class 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
190 class 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
222 FileProxy::FileProxy() : task_runner_(NULL) {
223 }
224
225 FileProxy::FileProxy(TaskRunner* task_runner) : task_runner_(task_runner) {
226 }
227
228 FileProxy::~FileProxy() {
229 }
230
231 bool 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
243 bool 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
254 bool FileProxy::IsValid() const {
255   return file_.IsValid();
256 }
257
258 File FileProxy::TakeFile() {
259   return file_.Pass();
260 }
261
262 bool 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
271 bool 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
280 bool 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
294 bool 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
310 bool 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
322 bool 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
331 bool 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
340 void FileProxy::SetFile(File file) {
341   DCHECK(!file_.IsValid());
342   file_ = file.Pass();
343 }
344
345 }  // namespace base