xref: /aosp_15_r20/external/cronet/base/files/file_proxy.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2014 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_proxy.h"
6 
7 #include <memory>
8 #include <optional>
9 #include <utility>
10 
11 #include "base/containers/heap_array.h"
12 #include "base/files/file.h"
13 #include "base/files/file_util.h"
14 #include "base/functional/bind.h"
15 #include "base/functional/callback_helpers.h"
16 #include "base/location.h"
17 #include "base/numerics/safe_conversions.h"
18 #include "base/task/task_runner.h"
19 
20 namespace {
21 
FileDeleter(base::File file)22 void FileDeleter(base::File file) {
23 }
24 
25 }  // namespace
26 
27 namespace base {
28 
29 class FileHelper {
30  public:
FileHelper(base::WeakPtr<FileProxy> proxy,File file)31   FileHelper(base::WeakPtr<FileProxy> proxy, File file)
32       : file_(std::move(file)),
33         task_runner_(proxy->task_runner()),
34         proxy_(proxy) {}
35   FileHelper(const FileHelper&) = delete;
36   FileHelper& operator=(const FileHelper&) = delete;
37 
PassFile()38   void PassFile() {
39     if (proxy_)
40       proxy_->SetFile(std::move(file_));
41     else if (file_.IsValid())
42       task_runner_->PostTask(FROM_HERE,
43                              BindOnce(&FileDeleter, std::move(file_)));
44   }
45 
46  protected:
47   File file_;
48   File::Error error_ = File::FILE_ERROR_FAILED;
49 
50  private:
51   scoped_refptr<TaskRunner> task_runner_;
52   WeakPtr<FileProxy> proxy_;
53 };
54 
55 namespace {
56 
57 class GenericFileHelper : public FileHelper {
58  public:
GenericFileHelper(base::WeakPtr<FileProxy> proxy,File file)59   GenericFileHelper(base::WeakPtr<FileProxy> proxy, File file)
60       : FileHelper(std::move(proxy), std::move(file)) {}
61   GenericFileHelper(const GenericFileHelper&) = delete;
62   GenericFileHelper& operator=(const GenericFileHelper&) = delete;
63 
Close()64   void Close() {
65     file_.Close();
66     error_ = File::FILE_OK;
67   }
68 
SetTimes(Time last_access_time,Time last_modified_time)69   void SetTimes(Time last_access_time, Time last_modified_time) {
70     bool rv = file_.SetTimes(last_access_time, last_modified_time);
71     error_ = rv ? File::FILE_OK : File::FILE_ERROR_FAILED;
72   }
73 
SetLength(int64_t length)74   void SetLength(int64_t length) {
75     if (file_.SetLength(length))
76       error_ = File::FILE_OK;
77   }
78 
Flush()79   void Flush() {
80     if (file_.Flush())
81       error_ = File::FILE_OK;
82   }
83 
Reply(FileProxy::StatusCallback callback)84   void Reply(FileProxy::StatusCallback callback) {
85     PassFile();
86     if (!callback.is_null())
87       std::move(callback).Run(error_);
88   }
89 };
90 
91 class CreateOrOpenHelper : public FileHelper {
92  public:
CreateOrOpenHelper(base::WeakPtr<FileProxy> proxy,File file)93   CreateOrOpenHelper(base::WeakPtr<FileProxy> proxy, File file)
94       : FileHelper(std::move(proxy), std::move(file)) {}
95   CreateOrOpenHelper(const CreateOrOpenHelper&) = delete;
96   CreateOrOpenHelper& operator=(const CreateOrOpenHelper&) = delete;
97 
RunWork(const FilePath & file_path,uint32_t file_flags)98   void RunWork(const FilePath& file_path, uint32_t file_flags) {
99     file_.Initialize(file_path, file_flags);
100     error_ = file_.IsValid() ? File::FILE_OK : file_.error_details();
101   }
102 
Reply(FileProxy::StatusCallback callback)103   void Reply(FileProxy::StatusCallback callback) {
104     DCHECK(!callback.is_null());
105     PassFile();
106     std::move(callback).Run(error_);
107   }
108 };
109 
110 class CreateTemporaryHelper : public FileHelper {
111  public:
CreateTemporaryHelper(base::WeakPtr<FileProxy> proxy,File file)112   CreateTemporaryHelper(base::WeakPtr<FileProxy> proxy, File file)
113       : FileHelper(std::move(proxy), std::move(file)) {}
114   CreateTemporaryHelper(const CreateTemporaryHelper&) = delete;
115   CreateTemporaryHelper& operator=(const CreateTemporaryHelper&) = delete;
116 
RunWork(uint32_t additional_file_flags)117   void RunWork(uint32_t additional_file_flags) {
118     // TODO(darin): file_util should have a variant of CreateTemporaryFile
119     // that returns a FilePath and a File.
120     if (!CreateTemporaryFile(&file_path_)) {
121       // TODO(davidben): base::CreateTemporaryFile should preserve the error
122       // code.
123       error_ = File::FILE_ERROR_FAILED;
124       return;
125     }
126 
127     uint32_t file_flags = File::FLAG_WRITE | File::FLAG_WIN_TEMPORARY |
128                           File::FLAG_CREATE_ALWAYS | additional_file_flags;
129 
130     file_.Initialize(file_path_, file_flags);
131     if (file_.IsValid()) {
132       error_ = File::FILE_OK;
133     } else {
134       error_ = file_.error_details();
135       DeleteFile(file_path_);
136       file_path_.clear();
137     }
138   }
139 
Reply(FileProxy::CreateTemporaryCallback callback)140   void Reply(FileProxy::CreateTemporaryCallback callback) {
141     DCHECK(!callback.is_null());
142     PassFile();
143     std::move(callback).Run(error_, file_path_);
144   }
145 
146  private:
147   FilePath file_path_;
148 };
149 
150 class GetInfoHelper : public FileHelper {
151  public:
GetInfoHelper(base::WeakPtr<FileProxy> proxy,File file)152   GetInfoHelper(base::WeakPtr<FileProxy> proxy, File file)
153       : FileHelper(std::move(proxy), std::move(file)) {}
154   GetInfoHelper(const GetInfoHelper&) = delete;
155   GetInfoHelper& operator=(const GetInfoHelper&) = delete;
156 
RunWork()157   void RunWork() {
158     if (file_.GetInfo(&file_info_))
159       error_  = File::FILE_OK;
160   }
161 
Reply(FileProxy::GetFileInfoCallback callback)162   void Reply(FileProxy::GetFileInfoCallback callback) {
163     PassFile();
164     DCHECK(!callback.is_null());
165     std::move(callback).Run(error_, file_info_);
166   }
167 
168  private:
169   File::Info file_info_;
170 };
171 
172 class ReadHelper : public FileHelper {
173  public:
ReadHelper(base::WeakPtr<FileProxy> proxy,File file,int bytes_to_read)174   ReadHelper(base::WeakPtr<FileProxy> proxy, File file, int bytes_to_read)
175       : FileHelper(std::move(proxy), std::move(file)),
176         // SAFETY - References to `buffer_` are provided as a span only after
177         // successfully reading some bytes.
178         buffer_(base::HeapArray<uint8_t>::Uninit(
179             static_cast<size_t>(bytes_to_read))) {}
180 
181   ReadHelper(const ReadHelper&) = delete;
182   ReadHelper& operator=(const ReadHelper&) = delete;
183 
RunWork(int64_t offset)184   void RunWork(int64_t offset) {
185     std::optional<size_t> result = file_.Read(offset, buffer_);
186     if (!result.has_value()) {
187       bytes_read_ = -1;
188       error_ = File::FILE_ERROR_FAILED;
189       return;
190     }
191     bytes_read_ = checked_cast<int>(result.value());
192     error_ = File::FILE_OK;
193   }
194 
Reply(FileProxy::ReadCallback callback)195   void Reply(FileProxy::ReadCallback callback) {
196     PassFile();
197     DCHECK(!callback.is_null());
198     base::span<uint8_t> read_span;
199     if (error_ == File::FILE_OK) {
200       read_span = buffer_.first(checked_cast<size_t>(bytes_read_));
201     }
202     std::move(callback).Run(error_, base::as_chars(read_span));
203   }
204 
205  private:
206   base::HeapArray<uint8_t> buffer_;
207   int bytes_read_ = 0;
208 };
209 
210 class WriteHelper : public FileHelper {
211  public:
WriteHelper(base::WeakPtr<FileProxy> proxy,File file,base::span<const uint8_t> data)212   WriteHelper(base::WeakPtr<FileProxy> proxy,
213               File file,
214               base::span<const uint8_t> data)
215       : FileHelper(std::move(proxy), std::move(file)),
216         buffer_(base::HeapArray<uint8_t>::CopiedFrom(data)) {}
217 
218   WriteHelper(const WriteHelper&) = delete;
219   WriteHelper& operator=(const WriteHelper&) = delete;
220 
RunWork(int64_t offset)221   void RunWork(int64_t offset) {
222     std::optional<size_t> result = file_.Write(offset, buffer_);
223     if (!result.has_value()) {
224       bytes_written_ = -1;
225       error_ = File::FILE_ERROR_FAILED;
226       return;
227     }
228     bytes_written_ = checked_cast<int>(result.value());
229     error_ = File::FILE_OK;
230   }
231 
Reply(FileProxy::WriteCallback callback)232   void Reply(FileProxy::WriteCallback callback) {
233     PassFile();
234     if (!callback.is_null())
235       std::move(callback).Run(error_, bytes_written_);
236   }
237 
238  private:
239   base::HeapArray<uint8_t> buffer_;
240   int bytes_written_ = 0;
241 };
242 
243 }  // namespace
244 
FileProxy(TaskRunner * task_runner)245 FileProxy::FileProxy(TaskRunner* task_runner) : task_runner_(task_runner) {}
246 
~FileProxy()247 FileProxy::~FileProxy() {
248   if (file_.IsValid())
249     task_runner_->PostTask(FROM_HERE, BindOnce(&FileDeleter, std::move(file_)));
250 }
251 
CreateOrOpen(const FilePath & file_path,uint32_t file_flags,StatusCallback callback)252 bool FileProxy::CreateOrOpen(const FilePath& file_path,
253                              uint32_t file_flags,
254                              StatusCallback callback) {
255   DCHECK(!file_.IsValid());
256   CreateOrOpenHelper* helper =
257       new CreateOrOpenHelper(weak_ptr_factory_.GetWeakPtr(), File());
258   return task_runner_->PostTaskAndReply(
259       FROM_HERE,
260       BindOnce(&CreateOrOpenHelper::RunWork, Unretained(helper), file_path,
261                file_flags),
262       BindOnce(&CreateOrOpenHelper::Reply, Owned(helper), std::move(callback)));
263 }
264 
CreateTemporary(uint32_t additional_file_flags,CreateTemporaryCallback callback)265 bool FileProxy::CreateTemporary(uint32_t additional_file_flags,
266                                 CreateTemporaryCallback callback) {
267   DCHECK(!file_.IsValid());
268   CreateTemporaryHelper* helper =
269       new CreateTemporaryHelper(weak_ptr_factory_.GetWeakPtr(), File());
270   return task_runner_->PostTaskAndReply(
271       FROM_HERE,
272       BindOnce(&CreateTemporaryHelper::RunWork, Unretained(helper),
273                additional_file_flags),
274       BindOnce(&CreateTemporaryHelper::Reply, Owned(helper),
275                std::move(callback)));
276 }
277 
IsValid() const278 bool FileProxy::IsValid() const {
279   return file_.IsValid();
280 }
281 
SetFile(File file)282 void FileProxy::SetFile(File file) {
283   DCHECK(!file_.IsValid());
284   file_ = std::move(file);
285 }
286 
TakeFile()287 File FileProxy::TakeFile() {
288   return std::move(file_);
289 }
290 
DuplicateFile()291 File FileProxy::DuplicateFile() {
292   return file_.Duplicate();
293 }
294 
GetPlatformFile() const295 PlatformFile FileProxy::GetPlatformFile() const {
296   return file_.GetPlatformFile();
297 }
298 
Close(StatusCallback callback)299 bool FileProxy::Close(StatusCallback callback) {
300   DCHECK(file_.IsValid());
301   GenericFileHelper* helper =
302       new GenericFileHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
303   return task_runner_->PostTaskAndReply(
304       FROM_HERE, BindOnce(&GenericFileHelper::Close, Unretained(helper)),
305       BindOnce(&GenericFileHelper::Reply, Owned(helper), std::move(callback)));
306 }
307 
GetInfo(GetFileInfoCallback callback)308 bool FileProxy::GetInfo(GetFileInfoCallback callback) {
309   DCHECK(file_.IsValid());
310   GetInfoHelper* helper =
311       new GetInfoHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
312   return task_runner_->PostTaskAndReply(
313       FROM_HERE, BindOnce(&GetInfoHelper::RunWork, Unretained(helper)),
314       BindOnce(&GetInfoHelper::Reply, Owned(helper), std::move(callback)));
315 }
316 
Read(int64_t offset,int bytes_to_read,ReadCallback callback)317 bool FileProxy::Read(int64_t offset, int bytes_to_read, ReadCallback callback) {
318   DCHECK(file_.IsValid());
319   if (bytes_to_read < 0)
320     return false;
321 
322   ReadHelper* helper = new ReadHelper(weak_ptr_factory_.GetWeakPtr(),
323                                       std::move(file_), bytes_to_read);
324   return task_runner_->PostTaskAndReply(
325       FROM_HERE, BindOnce(&ReadHelper::RunWork, Unretained(helper), offset),
326       BindOnce(&ReadHelper::Reply, Owned(helper), std::move(callback)));
327 }
328 
Write(int64_t offset,base::span<const uint8_t> data,WriteCallback callback)329 bool FileProxy::Write(int64_t offset,
330                       base::span<const uint8_t> data,
331                       WriteCallback callback) {
332   DCHECK(file_.IsValid());
333   if (data.empty()) {
334     return false;
335   }
336   WriteHelper* helper =
337       new WriteHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_), data);
338 
339   return task_runner_->PostTaskAndReply(
340       FROM_HERE, BindOnce(&WriteHelper::RunWork, Unretained(helper), offset),
341       BindOnce(&WriteHelper::Reply, Owned(helper), std::move(callback)));
342 }
343 
SetTimes(Time last_access_time,Time last_modified_time,StatusCallback callback)344 bool FileProxy::SetTimes(Time last_access_time,
345                          Time last_modified_time,
346                          StatusCallback callback) {
347   DCHECK(file_.IsValid());
348   GenericFileHelper* helper =
349       new GenericFileHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
350   return task_runner_->PostTaskAndReply(
351       FROM_HERE,
352       BindOnce(&GenericFileHelper::SetTimes, Unretained(helper),
353                last_access_time, last_modified_time),
354       BindOnce(&GenericFileHelper::Reply, Owned(helper), std::move(callback)));
355 }
356 
SetLength(int64_t length,StatusCallback callback)357 bool FileProxy::SetLength(int64_t length, StatusCallback callback) {
358   DCHECK(file_.IsValid());
359   GenericFileHelper* helper =
360       new GenericFileHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
361   return task_runner_->PostTaskAndReply(
362       FROM_HERE,
363       BindOnce(&GenericFileHelper::SetLength, Unretained(helper), length),
364       BindOnce(&GenericFileHelper::Reply, Owned(helper), std::move(callback)));
365 }
366 
Flush(StatusCallback callback)367 bool FileProxy::Flush(StatusCallback callback) {
368   DCHECK(file_.IsValid());
369   GenericFileHelper* helper =
370       new GenericFileHelper(weak_ptr_factory_.GetWeakPtr(), std::move(file_));
371   return task_runner_->PostTaskAndReply(
372       FROM_HERE, BindOnce(&GenericFileHelper::Flush, Unretained(helper)),
373       BindOnce(&GenericFileHelper::Reply, Owned(helper), std::move(callback)));
374 }
375 
376 }  // namespace base
377