• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/disk_cache/blockfile/file.h"
6 
7 #include <stdint.h>
8 #include <limits>
9 #include <utility>
10 
11 #include "base/check.h"
12 #include "base/functional/bind.h"
13 #include "base/location.h"
14 #include "base/run_loop.h"
15 #include "base/task/thread_pool.h"
16 #include "base/task/thread_pool/thread_pool_instance.h"
17 #include "net/base/net_errors.h"
18 #include "net/disk_cache/disk_cache.h"
19 
20 namespace disk_cache {
21 
File(base::File file)22 File::File(base::File file)
23     : init_(true), mixed_(true), base_file_(std::move(file)) {}
24 
Init(const base::FilePath & name)25 bool File::Init(const base::FilePath& name) {
26   if (base_file_.IsValid())
27     return false;
28 
29   int flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
30               base::File::FLAG_WRITE;
31   base_file_.Initialize(name, flags);
32   return base_file_.IsValid();
33 }
34 
IsValid() const35 bool File::IsValid() const {
36   return base_file_.IsValid();
37 }
38 
Read(void * buffer,size_t buffer_len,size_t offset)39 bool File::Read(void* buffer, size_t buffer_len, size_t offset) {
40   DCHECK(base_file_.IsValid());
41   if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
42       offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
43     return false;
44   }
45 
46   int ret = base_file_.Read(offset, static_cast<char*>(buffer), buffer_len);
47   return (static_cast<size_t>(ret) == buffer_len);
48 }
49 
Write(const void * buffer,size_t buffer_len,size_t offset)50 bool File::Write(const void* buffer, size_t buffer_len, size_t offset) {
51   DCHECK(base_file_.IsValid());
52   if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
53       offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
54     return false;
55   }
56 
57   int ret = base_file_.Write(offset, static_cast<const char*>(buffer),
58                              buffer_len);
59   return (static_cast<size_t>(ret) == buffer_len);
60 }
61 
Read(void * buffer,size_t buffer_len,size_t offset,FileIOCallback * callback,bool * completed)62 bool File::Read(void* buffer, size_t buffer_len, size_t offset,
63                 FileIOCallback* callback, bool* completed) {
64   DCHECK(base_file_.IsValid());
65   if (!callback) {
66     if (completed)
67       *completed = true;
68     return Read(buffer, buffer_len, offset);
69   }
70 
71   if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
72       offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
73     return false;
74   }
75 
76   base::ThreadPool::PostTaskAndReplyWithResult(
77       FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
78       base::BindOnce(&File::DoRead, base::Unretained(this), buffer, buffer_len,
79                      offset),
80       base::BindOnce(&File::OnOperationComplete, this, callback));
81 
82   *completed = false;
83   return true;
84 }
85 
Write(const void * buffer,size_t buffer_len,size_t offset,FileIOCallback * callback,bool * completed)86 bool File::Write(const void* buffer, size_t buffer_len, size_t offset,
87                  FileIOCallback* callback, bool* completed) {
88   DCHECK(base_file_.IsValid());
89   if (!callback) {
90     if (completed)
91       *completed = true;
92     return Write(buffer, buffer_len, offset);
93   }
94 
95   if (buffer_len > static_cast<size_t>(std::numeric_limits<int32_t>::max()) ||
96       offset > static_cast<size_t>(std::numeric_limits<int32_t>::max())) {
97     return false;
98   }
99 
100   // The priority is USER_BLOCKING because the cache waits for the write to
101   // finish before it reads from the network again.
102   // TODO(fdoray): Consider removing this from the critical path of network
103   // requests and changing the priority to BACKGROUND.
104   base::ThreadPool::PostTaskAndReplyWithResult(
105       FROM_HERE, {base::TaskPriority::USER_BLOCKING, base::MayBlock()},
106       base::BindOnce(&File::DoWrite, base::Unretained(this), buffer, buffer_len,
107                      offset),
108       base::BindOnce(&File::OnOperationComplete, this, callback));
109 
110   *completed = false;
111   return true;
112 }
113 
SetLength(size_t length)114 bool File::SetLength(size_t length) {
115   DCHECK(base_file_.IsValid());
116   if (length > std::numeric_limits<uint32_t>::max())
117     return false;
118 
119   return base_file_.SetLength(length);
120 }
121 
GetLength()122 size_t File::GetLength() {
123   DCHECK(base_file_.IsValid());
124   int64_t len = base_file_.GetLength();
125 
126   if (len < 0)
127     return 0;
128   if (len > static_cast<int64_t>(std::numeric_limits<uint32_t>::max()))
129     return std::numeric_limits<uint32_t>::max();
130 
131   return static_cast<size_t>(len);
132 }
133 
134 // Static.
WaitForPendingIOForTesting(int * num_pending_io)135 void File::WaitForPendingIOForTesting(int* num_pending_io) {
136   // We are running unit tests so we should wait for all callbacks.
137 
138   // This waits for callbacks running on worker threads.
139   base::ThreadPoolInstance::Get()->FlushForTesting();
140   // This waits for the "Reply" tasks running on the current MessageLoop.
141   base::RunLoop().RunUntilIdle();
142 }
143 
144 // Static.
DropPendingIO()145 void File::DropPendingIO() {
146 }
147 
148 File::~File() = default;
149 
platform_file() const150 base::PlatformFile File::platform_file() const {
151   return base_file_.GetPlatformFile();
152 }
153 
154 // Runs on a worker thread.
DoRead(void * buffer,size_t buffer_len,size_t offset)155 int File::DoRead(void* buffer, size_t buffer_len, size_t offset) {
156   if (Read(const_cast<void*>(buffer), buffer_len, offset))
157     return static_cast<int>(buffer_len);
158 
159   return net::ERR_CACHE_READ_FAILURE;
160 }
161 
162 // Runs on a worker thread.
DoWrite(const void * buffer,size_t buffer_len,size_t offset)163 int File::DoWrite(const void* buffer, size_t buffer_len, size_t offset) {
164   if (Write(const_cast<void*>(buffer), buffer_len, offset))
165     return static_cast<int>(buffer_len);
166 
167   return net::ERR_CACHE_WRITE_FAILURE;
168 }
169 
170 // This method actually makes sure that the last reference to the file doesn't
171 // go away on the worker pool.
OnOperationComplete(FileIOCallback * callback,int result)172 void File::OnOperationComplete(FileIOCallback* callback, int result) {
173   callback->OnFileIOComplete(result);
174 }
175 
176 }  // namespace disk_cache
177