1 // Copyright 2011 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 "base/files/file.h"
6
7 #include <utility>
8
9 #include "base/check_op.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_tracing.h"
12 #include "base/metrics/histogram.h"
13 #include "base/notreached.h"
14 #include "base/numerics/safe_conversions.h"
15 #include "base/timer/elapsed_timer.h"
16 #include "base/trace_event/base_tracing.h"
17 #include "build/build_config.h"
18
19 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
20 #include <errno.h>
21 #endif
22
23 namespace base {
24
25 File::Info::Info() = default;
26
27 File::Info::~Info() = default;
28
29 File::File() = default;
30
31 #if !BUILDFLAG(IS_NACL)
File(const FilePath & path,uint32_t flags)32 File::File(const FilePath& path, uint32_t flags) : error_details_(FILE_OK) {
33 Initialize(path, flags);
34 }
35 #endif
36
File(ScopedPlatformFile platform_file)37 File::File(ScopedPlatformFile platform_file)
38 : File(std::move(platform_file), false) {}
39
File(PlatformFile platform_file)40 File::File(PlatformFile platform_file) : File(platform_file, false) {}
41
File(ScopedPlatformFile platform_file,bool async)42 File::File(ScopedPlatformFile platform_file, bool async)
43 : file_(std::move(platform_file)), error_details_(FILE_OK), async_(async) {
44 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
45 DCHECK_GE(file_.get(), -1);
46 #endif
47 }
48
File(PlatformFile platform_file,bool async)49 File::File(PlatformFile platform_file, bool async)
50 : file_(platform_file),
51 error_details_(FILE_OK),
52 async_(async) {
53 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
54 DCHECK_GE(platform_file, -1);
55 #endif
56 }
57
File(Error error_details)58 File::File(Error error_details) : error_details_(error_details) {}
59
File(File && other)60 File::File(File&& other)
61 : file_(other.TakePlatformFile()),
62 path_(other.path_),
63 error_details_(other.error_details()),
64 created_(other.created()),
65 async_(other.async_) {}
66
~File()67 File::~File() {
68 // Go through the AssertIOAllowed logic.
69 Close();
70 }
71
operator =(File && other)72 File& File::operator=(File&& other) {
73 Close();
74 SetPlatformFile(other.TakePlatformFile());
75 path_ = other.path_;
76 error_details_ = other.error_details();
77 created_ = other.created();
78 async_ = other.async_;
79 return *this;
80 }
81
82 #if !BUILDFLAG(IS_NACL)
Initialize(const FilePath & path,uint32_t flags)83 void File::Initialize(const FilePath& path, uint32_t flags) {
84 if (path.ReferencesParent()) {
85 #if BUILDFLAG(IS_WIN)
86 ::SetLastError(ERROR_ACCESS_DENIED);
87 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
88 errno = EACCES;
89 #else
90 #error Unsupported platform
91 #endif
92 error_details_ = FILE_ERROR_ACCESS_DENIED;
93 return;
94 }
95 if (FileTracing::IsCategoryEnabled()
96 #if BUILDFLAG(IS_ANDROID)
97 || path.IsContentUri()
98 #endif
99 ) {
100 path_ = path;
101 }
102 SCOPED_FILE_TRACE("Initialize");
103 DoInitialize(path, flags);
104 }
105 #endif
106
Read(int64_t offset,span<uint8_t> data)107 std::optional<size_t> File::Read(int64_t offset, span<uint8_t> data) {
108 span<char> chars = base::as_writable_chars(data);
109 int size = checked_cast<int>(chars.size());
110 // SAFETY: `chars.size()` describes valid portion of `chars.data()`.
111 int result = UNSAFE_BUFFERS(Read(offset, chars.data(), size));
112 if (result < 0) {
113 return std::nullopt;
114 }
115 return checked_cast<size_t>(result);
116 }
117
ReadAndCheck(int64_t offset,span<uint8_t> data)118 bool File::ReadAndCheck(int64_t offset, span<uint8_t> data) {
119 // Size checked in span form of Read() above.
120 return Read(offset, data) == static_cast<int>(data.size());
121 }
122
ReadAtCurrentPos(span<uint8_t> data)123 std::optional<size_t> File::ReadAtCurrentPos(span<uint8_t> data) {
124 span<char> chars = base::as_writable_chars(data);
125 int size = checked_cast<int>(chars.size());
126 // SAFETY: `chars.size()` describes valid portion of `chars.data()`.
127 int result = UNSAFE_BUFFERS(ReadAtCurrentPos(chars.data(), size));
128 if (result < 0) {
129 return std::nullopt;
130 }
131 return checked_cast<size_t>(result);
132 }
133
ReadAtCurrentPosAndCheck(span<uint8_t> data)134 bool File::ReadAtCurrentPosAndCheck(span<uint8_t> data) {
135 // Size checked in span form of ReadAtCurrentPos() above.
136 return ReadAtCurrentPos(data) == static_cast<int>(data.size());
137 }
138
Write(int64_t offset,span<const uint8_t> data)139 std::optional<size_t> File::Write(int64_t offset, span<const uint8_t> data) {
140 span<const char> chars = base::as_chars(data);
141 int size = checked_cast<int>(chars.size());
142 // SAFETY: `chars.size()` describes valid portion of `chars.data()`.
143 int result = UNSAFE_BUFFERS(Write(offset, chars.data(), size));
144 if (result < 0) {
145 return std::nullopt;
146 }
147 return checked_cast<size_t>(result);
148 }
149
WriteAndCheck(int64_t offset,span<const uint8_t> data)150 bool File::WriteAndCheck(int64_t offset, span<const uint8_t> data) {
151 // Size checked in span form of Write() above.
152 return Write(offset, data) == static_cast<int>(data.size());
153 }
154
WriteAtCurrentPos(span<const uint8_t> data)155 std::optional<size_t> File::WriteAtCurrentPos(span<const uint8_t> data) {
156 span<const char> chars = base::as_chars(data);
157 int size = checked_cast<int>(chars.size());
158 // SAFETY: `chars.size()` describes valid portion of `chars.data()`.
159 int result = UNSAFE_BUFFERS(WriteAtCurrentPos(chars.data(), size));
160 if (result < 0) {
161 return std::nullopt;
162 }
163 return checked_cast<size_t>(result);
164 }
165
WriteAtCurrentPosAndCheck(span<const uint8_t> data)166 bool File::WriteAtCurrentPosAndCheck(span<const uint8_t> data) {
167 // Size checked in span form of WriteAtCurrentPos() above.
168 return WriteAtCurrentPos(data) == static_cast<int>(data.size());
169 }
170
ReadNoBestEffort(int64_t offset,base::span<uint8_t> data)171 std::optional<size_t> File::ReadNoBestEffort(int64_t offset,
172 base::span<uint8_t> data) {
173 span<char> chars = base::as_writable_chars(data);
174 int size = checked_cast<int>(chars.size());
175 // SAFETY: `chars.size()` describes valid portion of `chars.data()`.
176 int result = UNSAFE_BUFFERS(ReadNoBestEffort(offset, chars.data(), size));
177 if (result < 0) {
178 return std::nullopt;
179 }
180 return checked_cast<size_t>(result);
181 }
182
ReadAtCurrentPosNoBestEffort(base::span<uint8_t> data)183 std::optional<size_t> File::ReadAtCurrentPosNoBestEffort(
184 base::span<uint8_t> data) {
185 span<char> chars = base::as_writable_chars(data);
186 int size = checked_cast<int>(chars.size());
187 // SAFETY: `chars.size()` describes valid portion of `chars.data()`.
188 int result = UNSAFE_BUFFERS(ReadAtCurrentPosNoBestEffort(chars.data(), size));
189 if (result < 0) {
190 return std::nullopt;
191 }
192 return checked_cast<size_t>(result);
193 }
194
WriteAtCurrentPosNoBestEffort(base::span<const uint8_t> data)195 std::optional<size_t> File::WriteAtCurrentPosNoBestEffort(
196 base::span<const uint8_t> data) {
197 span<const char> chars = base::as_chars(data);
198 int size = checked_cast<int>(chars.size());
199 // SAFETY: `chars.size()` describes valid portion of `chars.data()`.
200 int result =
201 UNSAFE_BUFFERS(WriteAtCurrentPosNoBestEffort(chars.data(), size));
202 if (result < 0) {
203 return std::nullopt;
204 }
205 return checked_cast<size_t>(result);
206 }
207
208 // static
ErrorToString(Error error)209 std::string File::ErrorToString(Error error) {
210 switch (error) {
211 case FILE_OK:
212 return "FILE_OK";
213 case FILE_ERROR_FAILED:
214 return "FILE_ERROR_FAILED";
215 case FILE_ERROR_IN_USE:
216 return "FILE_ERROR_IN_USE";
217 case FILE_ERROR_EXISTS:
218 return "FILE_ERROR_EXISTS";
219 case FILE_ERROR_NOT_FOUND:
220 return "FILE_ERROR_NOT_FOUND";
221 case FILE_ERROR_ACCESS_DENIED:
222 return "FILE_ERROR_ACCESS_DENIED";
223 case FILE_ERROR_TOO_MANY_OPENED:
224 return "FILE_ERROR_TOO_MANY_OPENED";
225 case FILE_ERROR_NO_MEMORY:
226 return "FILE_ERROR_NO_MEMORY";
227 case FILE_ERROR_NO_SPACE:
228 return "FILE_ERROR_NO_SPACE";
229 case FILE_ERROR_NOT_A_DIRECTORY:
230 return "FILE_ERROR_NOT_A_DIRECTORY";
231 case FILE_ERROR_INVALID_OPERATION:
232 return "FILE_ERROR_INVALID_OPERATION";
233 case FILE_ERROR_SECURITY:
234 return "FILE_ERROR_SECURITY";
235 case FILE_ERROR_ABORT:
236 return "FILE_ERROR_ABORT";
237 case FILE_ERROR_NOT_A_FILE:
238 return "FILE_ERROR_NOT_A_FILE";
239 case FILE_ERROR_NOT_EMPTY:
240 return "FILE_ERROR_NOT_EMPTY";
241 case FILE_ERROR_INVALID_URL:
242 return "FILE_ERROR_INVALID_URL";
243 case FILE_ERROR_IO:
244 return "FILE_ERROR_IO";
245 case FILE_ERROR_MAX:
246 break;
247 }
248
249 NOTREACHED();
250 }
251
WriteIntoTrace(perfetto::TracedValue context) const252 void File::WriteIntoTrace(perfetto::TracedValue context) const {
253 auto dict = std::move(context).WriteDictionary();
254 dict.Add("is_valid", IsValid());
255 dict.Add("created", created_);
256 dict.Add("async", async_);
257 dict.Add("error_details", ErrorToString(error_details_));
258 }
259
260 } // namespace base
261