Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / net / base / file_stream_context.cc
1 // Copyright (c) 2012 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 "net/base/file_stream_context.h"
6
7 #include "base/files/file_path.h"
8 #include "base/location.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "base/task_runner.h"
11 #include "base/task_runner_util.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "base/values.h"
14 #include "net/base/net_errors.h"
15
16 #if defined(OS_ANDROID)
17 #include "base/android/content_uri_utils.h"
18 #endif
19
20 namespace net {
21
22 namespace {
23
24 void CallInt64ToInt(const CompletionCallback& callback, int64 result) {
25   callback.Run(static_cast<int>(result));
26 }
27
28 }  // namespace
29
30 FileStream::Context::IOResult::IOResult()
31     : result(OK),
32       os_error(0) {
33 }
34
35 FileStream::Context::IOResult::IOResult(int64 result, int os_error)
36     : result(result),
37       os_error(os_error) {
38 }
39
40 // static
41 FileStream::Context::IOResult FileStream::Context::IOResult::FromOSError(
42     int64 os_error) {
43   return IOResult(MapSystemError(os_error), os_error);
44 }
45
46 // ---------------------------------------------------------------------
47
48 FileStream::Context::OpenResult::OpenResult() {
49 }
50
51 FileStream::Context::OpenResult::OpenResult(base::File file,
52                                             IOResult error_code)
53     : file(file.Pass()),
54       error_code(error_code) {
55 }
56
57 FileStream::Context::OpenResult::OpenResult(RValue other)
58     : file(other.object->file.Pass()),
59       error_code(other.object->error_code) {
60 }
61
62 FileStream::Context::OpenResult& FileStream::Context::OpenResult::operator=(
63     RValue other) {
64   if (this != other.object) {
65     file = other.object->file.Pass();
66     error_code = other.object->error_code;
67   }
68   return *this;
69 }
70
71 // ---------------------------------------------------------------------
72
73 void FileStream::Context::Orphan() {
74   DCHECK(!orphaned_);
75
76   orphaned_ = true;
77
78   if (!async_in_progress_) {
79     CloseAndDelete();
80   } else if (file_.IsValid()) {
81 #if defined(OS_WIN)
82     CancelIo(file_.GetPlatformFile());
83 #endif
84   }
85 }
86
87 void FileStream::Context::Open(const base::FilePath& path,
88                                int open_flags,
89                                const CompletionCallback& callback) {
90   DCHECK(!async_in_progress_);
91
92   bool posted = base::PostTaskAndReplyWithResult(
93       task_runner_.get(),
94       FROM_HERE,
95       base::Bind(
96           &Context::OpenFileImpl, base::Unretained(this), path, open_flags),
97       base::Bind(&Context::OnOpenCompleted, base::Unretained(this), callback));
98   DCHECK(posted);
99
100   async_in_progress_ = true;
101 }
102
103 void FileStream::Context::Close(const CompletionCallback& callback) {
104   DCHECK(!async_in_progress_);
105   bool posted = base::PostTaskAndReplyWithResult(
106       task_runner_.get(),
107       FROM_HERE,
108       base::Bind(&Context::CloseFileImpl, base::Unretained(this)),
109       base::Bind(&Context::OnAsyncCompleted,
110                  base::Unretained(this),
111                  IntToInt64(callback)));
112   DCHECK(posted);
113
114   async_in_progress_ = true;
115 }
116
117 void FileStream::Context::Seek(base::File::Whence whence,
118                                int64 offset,
119                                const Int64CompletionCallback& callback) {
120   DCHECK(!async_in_progress_);
121
122   bool posted = base::PostTaskAndReplyWithResult(
123       task_runner_.get(),
124       FROM_HERE,
125       base::Bind(
126           &Context::SeekFileImpl, base::Unretained(this), whence, offset),
127       base::Bind(&Context::OnAsyncCompleted,
128                  base::Unretained(this),
129                  callback));
130   DCHECK(posted);
131
132   async_in_progress_ = true;
133 }
134
135 void FileStream::Context::Flush(const CompletionCallback& callback) {
136   DCHECK(!async_in_progress_);
137
138   bool posted = base::PostTaskAndReplyWithResult(
139       task_runner_.get(),
140       FROM_HERE,
141       base::Bind(&Context::FlushFileImpl, base::Unretained(this)),
142       base::Bind(&Context::OnAsyncCompleted,
143                  base::Unretained(this),
144                  IntToInt64(callback)));
145   DCHECK(posted);
146
147   async_in_progress_ = true;
148 }
149
150 FileStream::Context::OpenResult FileStream::Context::OpenFileImpl(
151     const base::FilePath& path, int open_flags) {
152 #if defined(OS_POSIX)
153   // Always use blocking IO.
154   open_flags &= ~base::File::FLAG_ASYNC;
155 #endif
156   base::File file;
157 #if defined(OS_ANDROID)
158   if (path.IsContentUri()) {
159     // Check that only Read flags are set.
160     DCHECK_EQ(open_flags & ~base::File::FLAG_ASYNC,
161               base::File::FLAG_OPEN | base::File::FLAG_READ);
162     file = base::OpenContentUriForRead(path);
163   } else {
164 #endif  // defined(OS_ANDROID)
165     // FileStream::Context actually closes the file asynchronously,
166     // independently from FileStream's destructor. It can cause problems for
167     // users wanting to delete the file right after FileStream deletion. Thus
168     // we are always adding SHARE_DELETE flag to accommodate such use case.
169     // TODO(rvargas): This sounds like a bug, as deleting the file would
170     // presumably happen on the wrong thread. There should be an async delete.
171     open_flags |= base::File::FLAG_SHARE_DELETE;
172     file.Initialize(path, open_flags);
173 #if defined(OS_ANDROID)
174   }
175 #endif  // defined(OS_ANDROID)
176   if (!file.IsValid())
177     return OpenResult(base::File(),
178                       IOResult::FromOSError(logging::GetLastSystemErrorCode()));
179
180   return OpenResult(file.Pass(), IOResult(OK, 0));
181 }
182
183 FileStream::Context::IOResult FileStream::Context::CloseFileImpl() {
184   file_.Close();
185   return IOResult(OK, 0);
186 }
187
188 FileStream::Context::IOResult FileStream::Context::FlushFileImpl() {
189   if (file_.Flush())
190     return IOResult(OK, 0);
191
192   return IOResult::FromOSError(logging::GetLastSystemErrorCode());
193 }
194
195 void FileStream::Context::OnOpenCompleted(const CompletionCallback& callback,
196                                           OpenResult open_result) {
197   file_ = open_result.file.Pass();
198   if (file_.IsValid() && !orphaned_)
199     OnFileOpened();
200
201   OnAsyncCompleted(IntToInt64(callback), open_result.error_code);
202 }
203
204 void FileStream::Context::CloseAndDelete() {
205   DCHECK(!async_in_progress_);
206
207   if (file_.IsValid()) {
208     bool posted = task_runner_.get()->PostTask(
209         FROM_HERE,
210         base::Bind(base::IgnoreResult(&Context::CloseFileImpl),
211                    base::Owned(this)));
212     DCHECK(posted);
213   } else {
214     delete this;
215   }
216 }
217
218 Int64CompletionCallback FileStream::Context::IntToInt64(
219     const CompletionCallback& callback) {
220   return base::Bind(&CallInt64ToInt, callback);
221 }
222
223 void FileStream::Context::OnAsyncCompleted(
224     const Int64CompletionCallback& callback,
225     const IOResult& result) {
226   // Reset this before Run() as Run() may issue a new async operation. Also it
227   // should be reset before Close() because it shouldn't run if any async
228   // operation is in progress.
229   async_in_progress_ = false;
230   if (orphaned_)
231     CloseAndDelete();
232   else
233     callback.Run(result.result);
234 }
235
236 }  // namespace net