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