OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/gdata/gdata_cache_metadata.h" | 5 #include "chrome/browser/chromeos/gdata/gdata_cache_metadata.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "chrome/browser/chromeos/gdata/gdata_util.h" | 8 #include "chrome/browser/chromeos/gdata/gdata_util.h" |
9 | 9 |
10 namespace gdata { | 10 namespace gdata { |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 &cache_map_, | 177 &cache_map_, |
178 &outgoing_file_map); | 178 &outgoing_file_map); |
179 | 179 |
180 RemoveInvalidFilesFromPersistentDirectory(persistent_file_map, | 180 RemoveInvalidFilesFromPersistentDirectory(persistent_file_map, |
181 outgoing_file_map, | 181 outgoing_file_map, |
182 &cache_map_); | 182 &cache_map_); |
183 DVLOG(1) << "Directory scan finished"; | 183 DVLOG(1) << "Directory scan finished"; |
184 } | 184 } |
185 | 185 |
186 void GDataCacheMetadataMap::UpdateCache(const std::string& resource_id, | 186 void GDataCacheMetadataMap::UpdateCache(const std::string& resource_id, |
187 const std::string& md5, | 187 const std::string& md5, |
188 GDataCache::CacheSubDirectoryType subdir, | 188 int cache_state) { |
189 int cache_state) { | |
190 AssertOnSequencedWorkerPool(); | 189 AssertOnSequencedWorkerPool(); |
191 | 190 |
192 CacheMap::iterator iter = cache_map_.find(resource_id); | 191 CacheMap::iterator iter = cache_map_.find(resource_id); |
193 if (iter == cache_map_.end()) { // New resource, create new entry. | 192 if (iter == cache_map_.end()) { // New resource, create new entry. |
194 // Makes no sense to create new entry if cache state is NONE. | 193 // Makes no sense to create new entry if cache state is NONE. |
195 DCHECK(cache_state != GDataCache::CACHE_STATE_NONE); | 194 DCHECK(cache_state != GDataCache::CACHE_STATE_NONE); |
196 if (cache_state != GDataCache::CACHE_STATE_NONE) { | 195 if (cache_state != GDataCache::CACHE_STATE_NONE) { |
197 GDataCache::CacheEntry cache_entry(md5, subdir, cache_state); | 196 GDataCache::CacheEntry cache_entry(md5, cache_state); |
198 cache_map_.insert(std::make_pair(resource_id, cache_entry)); | 197 cache_map_.insert(std::make_pair(resource_id, cache_entry)); |
199 DVLOG(1) << "Added res_id=" << resource_id | 198 DVLOG(1) << "Added res_id=" << resource_id |
200 << ", " << cache_entry.ToString(); | 199 << ", " << cache_entry.ToString(); |
201 } | 200 } |
202 } else { // Resource exists. | 201 } else { // Resource exists. |
203 // If cache state is NONE, delete entry from cache map. | 202 // If cache state is NONE, delete entry from cache map. |
204 if (cache_state == GDataCache::CACHE_STATE_NONE) { | 203 if (cache_state == GDataCache::CACHE_STATE_NONE) { |
205 DVLOG(1) << "Deleting res_id=" << resource_id | 204 DVLOG(1) << "Deleting res_id=" << resource_id |
206 << ", " << iter->second.ToString(); | 205 << ", " << iter->second.ToString(); |
207 cache_map_.erase(iter); | 206 cache_map_.erase(iter); |
208 } else { // Otherwise, update entry in cache map. | 207 } else { // Otherwise, update entry in cache map. |
209 iter->second.md5 = md5; | 208 iter->second.md5 = md5; |
210 iter->second.sub_dir_type = subdir; | |
211 iter->second.cache_state = cache_state; | 209 iter->second.cache_state = cache_state; |
212 DVLOG(1) << "Updated res_id=" << resource_id | 210 DVLOG(1) << "Updated res_id=" << resource_id |
213 << ", " << iter->second.ToString(); | 211 << ", " << iter->second.ToString(); |
214 } | 212 } |
215 } | 213 } |
216 } | 214 } |
217 | 215 |
218 void GDataCacheMetadataMap::RemoveFromCache(const std::string& resource_id) { | 216 void GDataCacheMetadataMap::RemoveFromCache(const std::string& resource_id) { |
219 AssertOnSequencedWorkerPool(); | 217 AssertOnSequencedWorkerPool(); |
220 | 218 |
(...skipping 30 matching lines...) Expand all Loading... |
251 << ", " << cache_entry->ToString(); | 249 << ", " << cache_entry->ToString(); |
252 | 250 |
253 return cache_entry.Pass(); | 251 return cache_entry.Pass(); |
254 } | 252 } |
255 | 253 |
256 void GDataCacheMetadataMap::RemoveTemporaryFiles() { | 254 void GDataCacheMetadataMap::RemoveTemporaryFiles() { |
257 AssertOnSequencedWorkerPool(); | 255 AssertOnSequencedWorkerPool(); |
258 | 256 |
259 CacheMap::iterator iter = cache_map_.begin(); | 257 CacheMap::iterator iter = cache_map_.begin(); |
260 while (iter != cache_map_.end()) { | 258 while (iter != cache_map_.end()) { |
261 if (iter->second.sub_dir_type == GDataCache::CACHE_TYPE_TMP) { | 259 if (!iter->second.IsPersistent()) { |
262 // Post-increment the iterator to avoid iterator invalidation. | 260 // Post-increment the iterator to avoid iterator invalidation. |
263 cache_map_.erase(iter++); | 261 cache_map_.erase(iter++); |
264 } else { | 262 } else { |
265 ++iter; | 263 ++iter; |
266 } | 264 } |
267 } | 265 } |
268 } | 266 } |
269 | 267 |
270 void GDataCacheMetadataMap::Iterate(const IterateCallback& callback) { | 268 void GDataCacheMetadataMap::Iterate(const IterateCallback& callback) { |
271 AssertOnSequencedWorkerPool(); | 269 AssertOnSequencedWorkerPool(); |
(...skipping 15 matching lines...) Expand all Loading... |
287 | 285 |
288 file_util::FileEnumerator enumerator( | 286 file_util::FileEnumerator enumerator( |
289 cache_paths[sub_dir_type], | 287 cache_paths[sub_dir_type], |
290 false, // not recursive | 288 false, // not recursive |
291 static_cast<file_util::FileEnumerator::FileType>( | 289 static_cast<file_util::FileEnumerator::FileType>( |
292 file_util::FileEnumerator::FILES | | 290 file_util::FileEnumerator::FILES | |
293 file_util::FileEnumerator::SHOW_SYM_LINKS), | 291 file_util::FileEnumerator::SHOW_SYM_LINKS), |
294 util::kWildCard); | 292 util::kWildCard); |
295 for (FilePath current = enumerator.Next(); !current.empty(); | 293 for (FilePath current = enumerator.Next(); !current.empty(); |
296 current = enumerator.Next()) { | 294 current = enumerator.Next()) { |
297 GDataCache::CacheSubDirectoryType real_sub_dir_type = | |
298 sub_dir_type; | |
299 // Extract resource_id and md5 from filename. | 295 // Extract resource_id and md5 from filename. |
300 std::string resource_id; | 296 std::string resource_id; |
301 std::string md5; | 297 std::string md5; |
302 std::string extra_extension; | 298 std::string extra_extension; |
303 util::ParseCacheFilePath(current, &resource_id, &md5, &extra_extension); | 299 util::ParseCacheFilePath(current, &resource_id, &md5, &extra_extension); |
304 | 300 |
305 // Determine cache state. | 301 // Determine cache state. |
306 int cache_state = GDataCache::CACHE_STATE_NONE; | 302 int cache_state = GDataCache::CACHE_STATE_NONE; |
307 // If we're scanning pinned directory and if entry already exists, just | 303 // If we're scanning pinned directory and if entry already exists, just |
308 // update its pinned state. | 304 // update its pinned state. |
(...skipping 11 matching lines...) Expand all Loading... |
320 iter->second.cache_state = | 316 iter->second.cache_state = |
321 GDataCache::SetCachePinned(iter->second.cache_state); | 317 GDataCache::SetCachePinned(iter->second.cache_state); |
322 | 318 |
323 processed_file_map->insert(std::make_pair(resource_id, current)); | 319 processed_file_map->insert(std::make_pair(resource_id, current)); |
324 continue; | 320 continue; |
325 } | 321 } |
326 // Entry doesn't exist, this is a special symlink that refers to | 322 // Entry doesn't exist, this is a special symlink that refers to |
327 // /dev/null; follow through to create an entry with the PINNED but not | 323 // /dev/null; follow through to create an entry with the PINNED but not |
328 // PRESENT state. | 324 // PRESENT state. |
329 cache_state = GDataCache::SetCachePinned(cache_state); | 325 cache_state = GDataCache::SetCachePinned(cache_state); |
330 // Change the real sub directory type to TMP, as the downloaded file | |
331 // will be stored in 'tmp' directory first. | |
332 real_sub_dir_type = GDataCache::CACHE_TYPE_TMP; | |
333 } else if (sub_dir_type == GDataCache::CACHE_TYPE_OUTGOING) { | 326 } else if (sub_dir_type == GDataCache::CACHE_TYPE_OUTGOING) { |
334 std::string reason; | 327 std::string reason; |
335 if (!IsValidSymbolicLink(current, sub_dir_type, cache_paths, &reason)) { | 328 if (!IsValidSymbolicLink(current, sub_dir_type, cache_paths, &reason)) { |
336 LOG(WARNING) << "Removing an invalid symlink: " << current.value() | 329 LOG(WARNING) << "Removing an invalid symlink: " << current.value() |
337 << ": " << reason; | 330 << ": " << reason; |
338 file_util::Delete(current, false); | 331 file_util::Delete(current, false); |
339 continue; | 332 continue; |
340 } | 333 } |
341 | 334 |
342 // If we're scanning outgoing directory, entry must exist and be dirty. | 335 // If we're scanning outgoing directory, entry must exist and be dirty. |
343 // Otherwise, it's a logic error from previous execution, remove this | 336 // Otherwise, it's a logic error from previous execution, remove this |
344 // outgoing symlink and move on. | 337 // outgoing symlink and move on. |
345 CacheMap::iterator iter = cache_map->find(resource_id); | 338 CacheMap::iterator iter = cache_map->find(resource_id); |
346 if (iter == cache_map->end() || !iter->second.IsDirty()) { | 339 if (iter == cache_map->end() || !iter->second.IsDirty()) { |
347 LOG(WARNING) << "Removing an symlink to a non-dirty file: " | 340 LOG(WARNING) << "Removing an symlink to a non-dirty file: " |
348 << current.value(); | 341 << current.value(); |
349 file_util::Delete(current, false); | 342 file_util::Delete(current, false); |
350 continue; | 343 continue; |
351 } | 344 } |
352 | 345 |
353 processed_file_map->insert(std::make_pair(resource_id, current)); | 346 processed_file_map->insert(std::make_pair(resource_id, current)); |
354 continue; | 347 continue; |
355 } else if (sub_dir_type == GDataCache::CACHE_TYPE_PERSISTENT || | 348 } else if (sub_dir_type == GDataCache::CACHE_TYPE_PERSISTENT || |
356 sub_dir_type == GDataCache::CACHE_TYPE_TMP) { | 349 sub_dir_type == GDataCache::CACHE_TYPE_TMP) { |
| 350 if (sub_dir_type == GDataCache::CACHE_TYPE_PERSISTENT) |
| 351 cache_state = GDataCache::SetCachePersistent(cache_state); |
| 352 |
357 if (file_util::IsLink(current)) { | 353 if (file_util::IsLink(current)) { |
358 LOG(WARNING) << "Removing a symlink in persistent/tmp directory" | 354 LOG(WARNING) << "Removing a symlink in persistent/tmp directory" |
359 << current.value(); | 355 << current.value(); |
360 file_util::Delete(current, false); | 356 file_util::Delete(current, false); |
361 continue; | 357 continue; |
362 } | 358 } |
363 if (extra_extension == util::kMountedArchiveFileExtension) { | 359 if (extra_extension == util::kMountedArchiveFileExtension) { |
364 // Mounted archives in cache should be unmounted upon logout/shutdown. | 360 // Mounted archives in cache should be unmounted upon logout/shutdown. |
365 // But if we encounter a mounted file at start, delete it and create an | 361 // But if we encounter a mounted file at start, delete it and create an |
366 // entry with not PRESENT state. | 362 // entry with not PRESENT state. |
367 DCHECK(sub_dir_type == GDataCache::CACHE_TYPE_PERSISTENT); | 363 DCHECK(sub_dir_type == GDataCache::CACHE_TYPE_PERSISTENT); |
368 file_util::Delete(current, false); | 364 file_util::Delete(current, false); |
369 } else { | 365 } else { |
370 // The cache file is present. | 366 // The cache file is present. |
371 cache_state = GDataCache::SetCachePresent(cache_state); | 367 cache_state = GDataCache::SetCachePresent(cache_state); |
372 | 368 |
373 // Adds the dirty bit if |md5| indicates that the file is dirty, and | 369 // Adds the dirty bit if |md5| indicates that the file is dirty, and |
374 // the file is in the persistent directory. | 370 // the file is in the persistent directory. |
375 if (md5 == util::kLocallyModifiedFileExtension) { | 371 if (md5 == util::kLocallyModifiedFileExtension) { |
376 if (sub_dir_type == GDataCache::CACHE_TYPE_PERSISTENT) { | 372 if (sub_dir_type == GDataCache::CACHE_TYPE_PERSISTENT) { |
377 cache_state |= GDataCache::SetCacheDirty(cache_state); | 373 cache_state = GDataCache::SetCacheDirty(cache_state); |
378 } else { | 374 } else { |
379 LOG(WARNING) << "Removing a dirty file in tmp directory: " | 375 LOG(WARNING) << "Removing a dirty file in tmp directory: " |
380 << current.value(); | 376 << current.value(); |
381 file_util::Delete(current, false); | 377 file_util::Delete(current, false); |
382 continue; | 378 continue; |
383 } | 379 } |
384 } | 380 } |
385 } | 381 } |
386 } else { | 382 } else { |
387 NOTREACHED() << "Unexpected sub directory type: " << sub_dir_type; | 383 NOTREACHED() << "Unexpected sub directory type: " << sub_dir_type; |
388 } | 384 } |
389 | 385 |
390 // Create and insert new entry into cache map. | 386 // Create and insert new entry into cache map. |
391 cache_map->insert(std::make_pair( | 387 cache_map->insert(std::make_pair( |
392 resource_id, GDataCache::CacheEntry( | 388 resource_id, GDataCache::CacheEntry(md5, cache_state))); |
393 md5, real_sub_dir_type, cache_state))); | |
394 processed_file_map->insert(std::make_pair(resource_id, current)); | 389 processed_file_map->insert(std::make_pair(resource_id, current)); |
395 } | 390 } |
396 } | 391 } |
397 | 392 |
398 // static | 393 // static |
399 bool GDataCacheMetadataMap::CheckIfMd5Matches( | 394 bool GDataCacheMetadataMap::CheckIfMd5Matches( |
400 const std::string& md5, | 395 const std::string& md5, |
401 const GDataCache::CacheEntry& cache_entry) { | 396 const GDataCache::CacheEntry& cache_entry) { |
402 if (cache_entry.IsDirty()) { | 397 if (cache_entry.IsDirty()) { |
403 // If the entry is dirty, its MD5 may have been replaced by "local" | 398 // If the entry is dirty, its MD5 may have been replaced by "local" |
404 // during cache initialization, so we don't compare MD5. | 399 // during cache initialization, so we don't compare MD5. |
405 return true; | 400 return true; |
406 } else if (cache_entry.IsPinned() && cache_entry.md5.empty()) { | 401 } else if (cache_entry.IsPinned() && cache_entry.md5.empty()) { |
407 // If the entry is pinned, it's ok for the entry to have an empty | 402 // If the entry is pinned, it's ok for the entry to have an empty |
408 // MD5. This can happen if the pinned file is not fetched. MD5 for pinned | 403 // MD5. This can happen if the pinned file is not fetched. MD5 for pinned |
409 // files are collected from files in "persistent" directory, but the | 404 // files are collected from files in "persistent" directory, but the |
410 // persistent files do not exisit if these are not fetched yet. | 405 // persistent files do not exisit if these are not fetched yet. |
411 return true; | 406 return true; |
412 } else if (md5.empty()) { | 407 } else if (md5.empty()) { |
413 // If the MD5 matching is not requested, don't check MD5. | 408 // If the MD5 matching is not requested, don't check MD5. |
414 return true; | 409 return true; |
415 } else if (md5 == cache_entry.md5) { | 410 } else if (md5 == cache_entry.md5) { |
416 // Otherwise, compare the MD5. | 411 // Otherwise, compare the MD5. |
417 return true; | 412 return true; |
418 } | 413 } |
419 return false; | 414 return false; |
420 } | 415 } |
421 | 416 |
422 } // namespace gdata | 417 } // namespace gdata |
OLD | NEW |