1 // Copyright 2012 The Chromium Authors
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 <errno.h>
8
9 #include <optional>
10 #include <utility>
11
12 #include "base/check.h"
13 #include "base/files/file_path.h"
14 #include "base/functional/bind.h"
15 #include "base/functional/callback.h"
16 #include "base/functional/callback_helpers.h"
17 #include "base/location.h"
18 #include "base/numerics/safe_conversions.h"
19 #include "base/posix/eintr_wrapper.h"
20 #include "base/task/task_runner.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/net_errors.h"
23
24 #if BUILDFLAG(IS_MAC)
25 #include "net/base/apple/guarded_fd.h"
26 #endif // BUILDFLAG(IS_MAC)
27
28 namespace net {
29
Context(scoped_refptr<base::TaskRunner> task_runner)30 FileStream::Context::Context(scoped_refptr<base::TaskRunner> task_runner)
31 : Context(base::File(), std::move(task_runner)) {}
32
Context(base::File file,scoped_refptr<base::TaskRunner> task_runner)33 FileStream::Context::Context(base::File file,
34 scoped_refptr<base::TaskRunner> task_runner)
35 : file_(std::move(file)), task_runner_(std::move(task_runner)) {
36 #if BUILDFLAG(IS_MAC)
37 // https://crbug.com/330771755: Guard against a file descriptor being closed
38 // out from underneath the file.
39 if (file_.IsValid()) {
40 guardid_t guardid = reinterpret_cast<guardid_t>(this);
41 PCHECK(change_fdguard_np(file_.GetPlatformFile(), /*guard=*/nullptr,
42 /*guardflags=*/0, &guardid,
43 GUARD_CLOSE | GUARD_DUP,
44 /*fdflagsp=*/nullptr) == 0);
45 }
46 #endif
47 }
48
49 FileStream::Context::~Context() = default;
50
Read(IOBuffer * in_buf,int buf_len,CompletionOnceCallback callback)51 int FileStream::Context::Read(IOBuffer* in_buf,
52 int buf_len,
53 CompletionOnceCallback callback) {
54 DCHECK(!async_in_progress_);
55
56 scoped_refptr<IOBuffer> buf = in_buf;
57 const bool posted = task_runner_->PostTaskAndReplyWithResult(
58 FROM_HERE,
59 base::BindOnce(&Context::ReadFileImpl, base::Unretained(this), buf,
60 buf_len),
61 base::BindOnce(&Context::OnAsyncCompleted, base::Unretained(this),
62 IntToInt64(std::move(callback))));
63 DCHECK(posted);
64
65 async_in_progress_ = true;
66 return ERR_IO_PENDING;
67 }
68
Write(IOBuffer * in_buf,int buf_len,CompletionOnceCallback callback)69 int FileStream::Context::Write(IOBuffer* in_buf,
70 int buf_len,
71 CompletionOnceCallback callback) {
72 DCHECK(!async_in_progress_);
73
74 scoped_refptr<IOBuffer> buf = in_buf;
75 const bool posted = task_runner_->PostTaskAndReplyWithResult(
76 FROM_HERE,
77 base::BindOnce(&Context::WriteFileImpl, base::Unretained(this), buf,
78 buf_len),
79 base::BindOnce(&Context::OnAsyncCompleted, base::Unretained(this),
80 IntToInt64(std::move(callback))));
81 DCHECK(posted);
82
83 async_in_progress_ = true;
84 return ERR_IO_PENDING;
85 }
86
SeekFileImpl(int64_t offset)87 FileStream::Context::IOResult FileStream::Context::SeekFileImpl(
88 int64_t offset) {
89 int64_t res = file_.Seek(base::File::FROM_BEGIN, offset);
90 if (res == -1)
91 return IOResult::FromOSError(errno);
92
93 return IOResult(res, 0);
94 }
95
OnFileOpened()96 void FileStream::Context::OnFileOpened() {
97 }
98
ReadFileImpl(scoped_refptr<IOBuffer> buf,int buf_len)99 FileStream::Context::IOResult FileStream::Context::ReadFileImpl(
100 scoped_refptr<IOBuffer> buf,
101 int buf_len) {
102 std::optional<size_t> res = file_.ReadAtCurrentPosNoBestEffort(
103 buf->span().first(base::checked_cast<size_t>(buf_len)));
104 if (!res.has_value()) {
105 return IOResult::FromOSError(errno);
106 }
107 return IOResult(res.value(), 0);
108 }
109
WriteFileImpl(scoped_refptr<IOBuffer> buf,int buf_len)110 FileStream::Context::IOResult FileStream::Context::WriteFileImpl(
111 scoped_refptr<IOBuffer> buf,
112 int buf_len) {
113 std::optional<size_t> res = file_.WriteAtCurrentPosNoBestEffort(
114 buf->span().first(base::checked_cast<size_t>(buf_len)));
115 if (!res.has_value()) {
116 return IOResult::FromOSError(errno);
117 }
118 return IOResult(res.value(), 0);
119 }
120
121 } // namespace net
122