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