OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2013 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 "net/disk_cache/simple/simple_synchronous_entry.h" | |
6 | |
7 #include <algorithm> | |
8 #include <cstring> | |
9 | |
10 #include "base/basictypes.h" | |
11 #include "base/file_util.h" | |
12 #include "base/hash.h" | |
13 #include "base/location.h" | |
14 #include "base/message_loop_proxy.h" | |
15 #include "base/sha1.h" | |
16 #include "base/stringprintf.h" | |
17 #include "base/task_runner.h" | |
18 #include "net/base/io_buffer.h" | |
19 #include "net/base/net_errors.h" | |
20 #include "net/disk_cache/simple/simple_disk_format.h" | |
21 | |
22 using base::ClosePlatformFile; | |
23 using base::GetPlatformFileInfo; | |
24 using base::PlatformFileError; | |
25 using base::PlatformFileInfo; | |
26 using base::PLATFORM_FILE_CREATE_ALWAYS; | |
27 using base::PLATFORM_FILE_OK; | |
28 using base::PLATFORM_FILE_OPEN; | |
29 using base::PLATFORM_FILE_READ; | |
30 using base::PLATFORM_FILE_WRITE; | |
31 using base::ReadPlatformFile; | |
32 using base::TaskRunner; | |
33 using base::Time; | |
34 using base::TruncatePlatformFile; | |
35 using base::WritePlatformFile; | |
36 | |
37 namespace { | |
38 | |
39 std::string GetFilenameForKeyAndIndex(const std::string& key, int index) { | |
40 const std::string sha_hash = base::SHA1HashString(key); | |
41 return StringPrintf("%02x%02x%02x%02x%02x_%1d", | |
42 implicit_cast<unsigned char>(sha_hash[0]), | |
43 implicit_cast<unsigned char>(sha_hash[1]), | |
44 implicit_cast<unsigned char>(sha_hash[2]), | |
45 implicit_cast<unsigned char>(sha_hash[3]), | |
46 implicit_cast<unsigned char>(sha_hash[4]), index); | |
47 } | |
48 | |
49 int32 DataSizeFromKeyAndFileSize(size_t key_size, int64 file_size) { | |
50 return file_size - key_size - sizeof(disk_cache::SimpleFileHeader); | |
51 } | |
52 | |
53 int64 FileOffsetFromDataOffset(size_t key_size, int offset) { | |
54 const int64 headers_size = sizeof(disk_cache::SimpleFileHeader) + | |
55 key_size; | |
56 return headers_size + offset; | |
57 } | |
58 | |
59 } // namespace | |
60 | |
61 namespace disk_cache { | |
62 | |
63 // static | |
64 void SimpleSynchronousEntry::OpenEntry( | |
65 const FilePath& path, | |
66 const std::string& key, | |
67 const scoped_refptr<TaskRunner>& callback_runner, | |
68 const SynchronousEntryCallback& callback) { | |
69 SimpleSynchronousEntry* sync_entry = | |
70 new SimpleSynchronousEntry(callback_runner, path, key); | |
71 | |
72 if (!sync_entry->InitializeForOpen()) { | |
73 delete sync_entry; | |
74 sync_entry = NULL; | |
75 } | |
76 callback_runner->PostTask(FROM_HERE, | |
77 base::Bind(callback, sync_entry, | |
78 sync_entry ? net::OK : net::ERR_FAILED)); | |
79 } | |
80 | |
81 // static | |
82 void SimpleSynchronousEntry::CreateEntry( | |
83 const FilePath& path, | |
84 const std::string& key, | |
85 const scoped_refptr<TaskRunner>& callback_runner, | |
86 const SynchronousEntryCallback& callback) { | |
87 SimpleSynchronousEntry* sync_entry = | |
88 new SimpleSynchronousEntry(callback_runner, path, key); | |
89 | |
90 if (!sync_entry->InitializeForCreate()) { | |
91 delete sync_entry; | |
92 sync_entry = NULL; | |
93 } | |
94 callback_runner->PostTask(FROM_HERE, | |
95 base::Bind(callback, sync_entry, | |
96 sync_entry ? net::OK : net::ERR_FAILED)); | |
97 } | |
98 | |
99 // static | |
100 void SimpleSynchronousEntry::DoomEntry( | |
101 const FilePath& path, | |
102 const std::string& key, | |
103 scoped_refptr<TaskRunner> callback_runner, | |
104 const net::CompletionCallback& callback) { | |
105 for (int i = 0; i < kIndexCount; ++i) { | |
106 bool delete_result = | |
107 file_util::Delete(path.AppendASCII(GetFilenameForKeyAndIndex(key, i)), | |
108 false); | |
109 DCHECK(delete_result); | |
110 } | |
111 if (!callback.is_null()) | |
112 callback_runner->PostTask(FROM_HERE, base::Bind(callback, net::OK)); | |
113 } | |
114 | |
115 void SimpleSynchronousEntry::DoomAndClose() { | |
116 scoped_refptr<TaskRunner> callback_runner = callback_runner_; | |
117 FilePath path = path_; | |
118 std::string key = key_; | |
119 | |
120 Close(); | |
121 // |this| is now deleted. | |
122 | |
123 DoomEntry(path, key, callback_runner, net::CompletionCallback()); | |
124 } | |
125 | |
126 void SimpleSynchronousEntry::Close() { | |
127 for (int i = 0; i < kIndexCount; ++i) { | |
128 bool result = ClosePlatformFile(files_[i]); | |
129 DCHECK(result); | |
130 } | |
131 delete this; | |
132 } | |
133 | |
134 void SimpleSynchronousEntry::ReadData( | |
135 int index, | |
136 int offset, | |
137 net::IOBuffer* buf, | |
138 int buf_len, | |
139 const SynchronousEntryCallback& callback) { | |
140 DCHECK(initialized_); | |
141 if (status_[index].mode != EntryStatus::ENTRY_READER) | |
142 status_[index].data_offset = 0; | |
143 DCHECK_EQ(status_[index].data_offset, offset); | |
144 status_[index].mode = EntryStatus::ENTRY_READER; | |
145 | |
146 int64 file_offset = FileOffsetFromDataOffset(key_.size(), offset); | |
147 int bytes_read = ReadPlatformFile(files_[index], file_offset, | |
148 buf->data(), buf_len); | |
149 if (bytes_read > 0) { | |
150 last_used_ = Time::Now(); | |
151 status_[index].data_offset += bytes_read; | |
152 } | |
153 int result = (bytes_read >= 0) ? bytes_read : net::ERR_FAILED; | |
154 callback_runner_->PostTask(FROM_HERE, base::Bind(callback, this, result)); | |
155 } | |
156 | |
157 void SimpleSynchronousEntry::WriteData( | |
158 int index, | |
159 int offset, | |
160 net::IOBuffer* buf, | |
161 int buf_len, | |
162 const SynchronousEntryCallback& callback, | |
163 bool truncate) { | |
164 DCHECK(initialized_); | |
165 if (status_[index].mode != EntryStatus::ENTRY_WRITER) | |
166 status_[index].data_offset = 0; | |
167 DCHECK_EQ(status_[index].data_offset, offset); | |
168 status_[index].mode = EntryStatus::ENTRY_WRITER; | |
169 | |
170 int64 file_offset = FileOffsetFromDataOffset(key_.size(), offset); | |
171 if (buf_len > 0) { | |
172 if (WritePlatformFile(files_[index], file_offset, buf->data(), buf_len) != | |
173 buf_len) { | |
174 callback_runner_->PostTask(FROM_HERE, | |
175 base::Bind(callback, this, net::ERR_FAILED)); | |
pasko-google - do not use
2013/02/11 13:59:25
I am wondering why some errors are logged and some
gavinp
2013/02/11 17:55:50
The rule is that there's logging in code that has
| |
176 return; | |
177 } | |
178 data_size_[index] = std::max(data_size_[index], offset + buf_len); | |
179 status_[index].data_offset += buf_len; | |
180 } | |
181 if (truncate) { | |
182 data_size_[index] = offset + buf_len; | |
183 if (!TruncatePlatformFile(files_[index], file_offset + buf_len)) { | |
184 callback_runner_->PostTask(FROM_HERE, | |
185 base::Bind(callback, this, net::ERR_FAILED)); | |
186 return; | |
187 } | |
188 } | |
189 last_modified_ = Time::Now(); | |
190 callback_runner_->PostTask(FROM_HERE, base::Bind(callback, this, buf_len)); | |
191 } | |
192 | |
193 SimpleSynchronousEntry::EntryStatus::EntryStatus() | |
194 : mode(ENTRY_UNINITIALIZED), | |
195 data_offset(0) { | |
196 } | |
197 | |
198 SimpleSynchronousEntry::SimpleSynchronousEntry( | |
199 const scoped_refptr<TaskRunner>& callback_runner, | |
200 const FilePath& path, | |
201 const std::string& key) : callback_runner_(callback_runner), | |
202 path_(path), | |
203 key_(key), | |
204 initialized_(false) { | |
205 } | |
206 | |
207 SimpleSynchronousEntry::~SimpleSynchronousEntry() { | |
208 } | |
209 | |
210 bool SimpleSynchronousEntry::OpenOrCreateFiles(bool create) { | |
211 for (int i = 0; i < kIndexCount; ++i) { | |
212 FilePath filename = path_.AppendASCII(GetFilenameForKeyAndIndex(key_, i)); | |
213 int flags = PLATFORM_FILE_READ | PLATFORM_FILE_WRITE; | |
214 if (create) | |
215 flags |= PLATFORM_FILE_CREATE_ALWAYS; | |
216 else | |
217 flags |= PLATFORM_FILE_OPEN; | |
218 PlatformFileError error; | |
219 files_[i] = CreatePlatformFile(filename, flags, NULL, &error); | |
220 if (error != PLATFORM_FILE_OK) { | |
221 while (--i >= 0) { | |
222 bool did_close = ClosePlatformFile(files_[i]); | |
223 DCHECK(did_close); | |
224 } | |
225 return false; | |
226 } | |
227 } | |
228 | |
229 for (int i = 0; i < kIndexCount; ++i) { | |
230 PlatformFileInfo file_info; | |
231 CHECK(GetPlatformFileInfo(files_[i], &file_info)); | |
232 last_used_ = std::max(last_used_, file_info.last_accessed); | |
pasko-google - do not use
2013/02/11 13:59:25
I am wondering how last_used is actually used. Her
gavinp
2013/02/11 17:55:50
Yeah. Tricky. Could force this issue with filesyst
| |
233 last_modified_ = std::max(last_modified_, file_info.last_modified); | |
234 data_size_[i] = DataSizeFromKeyAndFileSize(key_.size(), file_info.size); | |
235 } | |
236 | |
237 return true; | |
238 } | |
239 | |
240 bool SimpleSynchronousEntry::InitializeForOpen() { | |
241 DCHECK(!initialized_); | |
242 if (!OpenOrCreateFiles(false)) | |
243 return false; | |
244 | |
245 for (int i = 0; i < kIndexCount; ++i) { | |
246 SimpleFileHeader header; | |
247 if (ReadPlatformFile(files_[i], 0, reinterpret_cast<char*>(&header), | |
248 sizeof(header)) != sizeof(header)) { | |
249 return false; | |
250 } | |
251 if (header.initial_magic_number != kSimpleInitialMagicNumber || | |
252 header.version != kSimpleVersion) { | |
253 DVLOG(6) << "Error: No magic number."; | |
pasko-google - do not use
2013/02/11 13:59:25
This is a pretty serious error, so sounds rather L
gavinp
2013/02/11 17:55:50
I'll leave it LOG(WARNING) for now with a TODO. We
| |
254 return false; | |
255 } | |
256 | |
257 char key[1024]; | |
258 DCHECK_LE(header.key_length, sizeof(key)); | |
259 if (ReadPlatformFile(files_[i], sizeof(header), key, header.key_length) != | |
260 implicit_cast<int>(header.key_length)) { | |
261 DVLOG(6) << "Error: No key."; | |
262 return false; | |
263 } | |
264 if (std::memcmp(static_cast<const void*>(key_.data()), | |
265 static_cast<const void*>(key), | |
266 key_.size()) != 0) { | |
267 DVLOG(6) << "Error: Bad key."; | |
268 return false; | |
269 } | |
270 | |
271 if (base::Hash(key, header.key_length) == header.key_hash) { | |
272 DVLOG(6) << "Error: Bad key hash."; | |
273 return false; | |
274 } | |
275 } | |
276 | |
277 initialized_ = true; | |
278 return true; | |
279 } | |
280 | |
281 bool SimpleSynchronousEntry::InitializeForCreate() { | |
282 DCHECK(!initialized_); | |
283 if (!OpenOrCreateFiles(true)) | |
284 return false; | |
285 | |
286 for (int i = 0; i < kIndexCount; ++i) { | |
287 SimpleFileHeader header; | |
288 header.initial_magic_number = kSimpleInitialMagicNumber; | |
289 header.version = kSimpleVersion; | |
290 | |
291 header.key_length = key_.size(); | |
292 header.key_hash = base::Hash(key_); | |
293 | |
294 if (WritePlatformFile(files_[i], 0, reinterpret_cast<char*>(&header), | |
295 sizeof(header)) != sizeof(header)) { | |
pasko-google - do not use
2013/02/11 13:59:25
would be helpful: LOG(WARNING) or explanation wher
gavinp
2013/02/11 17:55:50
Done.
| |
296 return false; | |
297 } | |
298 | |
299 if (WritePlatformFile(files_[i], sizeof(header), key_.data(), | |
300 key_.size()) != implicit_cast<int>(key_.size())) { | |
301 return false; | |
302 } | |
303 } | |
304 | |
305 initialized_ = true; | |
306 return true; | |
307 } | |
308 | |
309 } // namespace disk_cache | |
OLD | NEW |