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