xref: /aosp_15_r20/external/cronet/base/files/file.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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       tracing_path_(other.tracing_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   tracing_path_ = other.tracing_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     tracing_path_ = path;
97   SCOPED_FILE_TRACE("Initialize");
98   DoInitialize(path, flags);
99 }
100 #endif
101 
Read(int64_t offset,span<uint8_t> data)102 std::optional<size_t> File::Read(int64_t offset, span<uint8_t> data) {
103   span<char> chars = base::as_writable_chars(data);
104   int size = checked_cast<int>(chars.size());
105   int result = Read(offset, chars.data(), size);
106   if (result < 0) {
107     return std::nullopt;
108   }
109   return checked_cast<size_t>(result);
110 }
111 
ReadAndCheck(int64_t offset,span<uint8_t> data)112 bool File::ReadAndCheck(int64_t offset, span<uint8_t> data) {
113   // Size checked in span form of Read() above.
114   return Read(offset, data) == static_cast<int>(data.size());
115 }
116 
ReadAtCurrentPos(span<uint8_t> data)117 std::optional<size_t> File::ReadAtCurrentPos(span<uint8_t> data) {
118   span<char> chars = base::as_writable_chars(data);
119   int size = checked_cast<int>(chars.size());
120   int result = ReadAtCurrentPos(chars.data(), size);
121   if (result < 0) {
122     return std::nullopt;
123   }
124   return checked_cast<size_t>(result);
125 }
126 
ReadAtCurrentPosAndCheck(span<uint8_t> data)127 bool File::ReadAtCurrentPosAndCheck(span<uint8_t> data) {
128   // Size checked in span form of ReadAtCurrentPos() above.
129   return ReadAtCurrentPos(data) == static_cast<int>(data.size());
130 }
131 
Write(int64_t offset,span<const uint8_t> data)132 std::optional<size_t> File::Write(int64_t offset, span<const uint8_t> data) {
133   span<const char> chars = base::as_chars(data);
134   int size = checked_cast<int>(chars.size());
135   int result = Write(offset, chars.data(), size);
136   if (result < 0) {
137     return std::nullopt;
138   }
139   return checked_cast<size_t>(result);
140 }
141 
WriteAndCheck(int64_t offset,span<const uint8_t> data)142 bool File::WriteAndCheck(int64_t offset, span<const uint8_t> data) {
143   // Size checked in span form of Write() above.
144   return Write(offset, data) == static_cast<int>(data.size());
145 }
146 
WriteAtCurrentPos(span<const uint8_t> data)147 std::optional<size_t> File::WriteAtCurrentPos(span<const uint8_t> data) {
148   span<const char> chars = base::as_chars(data);
149   int size = checked_cast<int>(chars.size());
150   int result = WriteAtCurrentPos(chars.data(), size);
151   if (result < 0) {
152     return std::nullopt;
153   }
154   return checked_cast<size_t>(result);
155 }
156 
WriteAtCurrentPosAndCheck(span<const uint8_t> data)157 bool File::WriteAtCurrentPosAndCheck(span<const uint8_t> data) {
158   // Size checked in span form of WriteAtCurrentPos() above.
159   return WriteAtCurrentPos(data) == static_cast<int>(data.size());
160 }
161 
162 // static
ErrorToString(Error error)163 std::string File::ErrorToString(Error error) {
164   switch (error) {
165     case FILE_OK:
166       return "FILE_OK";
167     case FILE_ERROR_FAILED:
168       return "FILE_ERROR_FAILED";
169     case FILE_ERROR_IN_USE:
170       return "FILE_ERROR_IN_USE";
171     case FILE_ERROR_EXISTS:
172       return "FILE_ERROR_EXISTS";
173     case FILE_ERROR_NOT_FOUND:
174       return "FILE_ERROR_NOT_FOUND";
175     case FILE_ERROR_ACCESS_DENIED:
176       return "FILE_ERROR_ACCESS_DENIED";
177     case FILE_ERROR_TOO_MANY_OPENED:
178       return "FILE_ERROR_TOO_MANY_OPENED";
179     case FILE_ERROR_NO_MEMORY:
180       return "FILE_ERROR_NO_MEMORY";
181     case FILE_ERROR_NO_SPACE:
182       return "FILE_ERROR_NO_SPACE";
183     case FILE_ERROR_NOT_A_DIRECTORY:
184       return "FILE_ERROR_NOT_A_DIRECTORY";
185     case FILE_ERROR_INVALID_OPERATION:
186       return "FILE_ERROR_INVALID_OPERATION";
187     case FILE_ERROR_SECURITY:
188       return "FILE_ERROR_SECURITY";
189     case FILE_ERROR_ABORT:
190       return "FILE_ERROR_ABORT";
191     case FILE_ERROR_NOT_A_FILE:
192       return "FILE_ERROR_NOT_A_FILE";
193     case FILE_ERROR_NOT_EMPTY:
194       return "FILE_ERROR_NOT_EMPTY";
195     case FILE_ERROR_INVALID_URL:
196       return "FILE_ERROR_INVALID_URL";
197     case FILE_ERROR_IO:
198       return "FILE_ERROR_IO";
199     case FILE_ERROR_MAX:
200       break;
201   }
202 
203   NOTREACHED();
204   return "";
205 }
206 
WriteIntoTrace(perfetto::TracedValue context) const207 void File::WriteIntoTrace(perfetto::TracedValue context) const {
208   auto dict = std::move(context).WriteDictionary();
209   dict.Add("is_valid", IsValid());
210   dict.Add("created", created_);
211   dict.Add("async", async_);
212   dict.Add("error_details", ErrorToString(error_details_));
213 }
214 
215 }  // namespace base
216