| 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/download/download_path_reservation_tracker.h" | 5 #include "chrome/browser/download/download_path_reservation_tracker.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback.h" | 10 #include "base/callback.h" |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 DownloadItem* download_item_; | 63 DownloadItem* download_item_; |
| 64 | 64 |
| 65 // Last known target path for the download. | 65 // Last known target path for the download. |
| 66 base::FilePath last_target_path_; | 66 base::FilePath last_target_path_; |
| 67 | 67 |
| 68 DISALLOW_COPY_AND_ASSIGN(DownloadItemObserver); | 68 DISALLOW_COPY_AND_ASSIGN(DownloadItemObserver); |
| 69 }; | 69 }; |
| 70 | 70 |
| 71 // Returns true if the given path is in use by a path reservation. | 71 // Returns true if the given path is in use by a path reservation. |
| 72 bool IsPathReserved(const base::FilePath& path) { | 72 bool IsPathReserved(const base::FilePath& path) { |
| 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 73 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 74 // No reservation map => no reservations. | 74 // No reservation map => no reservations. |
| 75 if (g_reservation_map == NULL) | 75 if (g_reservation_map == NULL) |
| 76 return false; | 76 return false; |
| 77 // Unfortunately path normalization doesn't work reliably for non-existant | 77 // Unfortunately path normalization doesn't work reliably for non-existant |
| 78 // files. So given a FilePath, we can't derive a normalized key that we can | 78 // files. So given a FilePath, we can't derive a normalized key that we can |
| 79 // use for lookups. We only expect a small number of concurrent downloads at | 79 // use for lookups. We only expect a small number of concurrent downloads at |
| 80 // any given time, so going through all of them shouldn't be too slow. | 80 // any given time, so going through all of them shouldn't be too slow. |
| 81 for (ReservationMap::const_iterator iter = g_reservation_map->begin(); | 81 for (ReservationMap::const_iterator iter = g_reservation_map->begin(); |
| 82 iter != g_reservation_map->end(); ++iter) { | 82 iter != g_reservation_map->end(); ++iter) { |
| 83 if (iter->second == path) | 83 if (iter->second == path) |
| 84 return true; | 84 return true; |
| 85 } | 85 } |
| 86 return false; | 86 return false; |
| 87 } | 87 } |
| 88 | 88 |
| 89 // Returns true if the given path is in use by any path reservation or the | 89 // Returns true if the given path is in use by any path reservation or the |
| 90 // file system. Called on the FILE thread. | 90 // file system. Called on the FILE thread. |
| 91 bool IsPathInUse(const base::FilePath& path) { | 91 bool IsPathInUse(const base::FilePath& path) { |
| 92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 92 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 93 // If there is a reservation, then the path is in use. | 93 // If there is a reservation, then the path is in use. |
| 94 if (IsPathReserved(path)) | 94 if (IsPathReserved(path)) |
| 95 return true; | 95 return true; |
| 96 | 96 |
| 97 // If the path exists in the file system, then the path is in use. | 97 // If the path exists in the file system, then the path is in use. |
| 98 if (base::PathExists(path)) | 98 if (base::PathExists(path)) |
| 99 return true; | 99 return true; |
| 100 | 100 |
| 101 return false; | 101 return false; |
| 102 } | 102 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 // - Truncates the suggested name if it exceeds the filesystem's limit. | 148 // - Truncates the suggested name if it exceeds the filesystem's limit. |
| 149 // - Uniquifies |suggested_path| if |should_uniquify_path| is true. | 149 // - Uniquifies |suggested_path| if |should_uniquify_path| is true. |
| 150 // - Returns true if |reserved_path| has been successfully verified. | 150 // - Returns true if |reserved_path| has been successfully verified. |
| 151 bool CreateReservation( | 151 bool CreateReservation( |
| 152 ReservationKey key, | 152 ReservationKey key, |
| 153 const base::FilePath& suggested_path, | 153 const base::FilePath& suggested_path, |
| 154 const base::FilePath& default_download_path, | 154 const base::FilePath& default_download_path, |
| 155 bool create_directory, | 155 bool create_directory, |
| 156 DownloadPathReservationTracker::FilenameConflictAction conflict_action, | 156 DownloadPathReservationTracker::FilenameConflictAction conflict_action, |
| 157 base::FilePath* reserved_path) { | 157 base::FilePath* reserved_path) { |
| 158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 158 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 159 DCHECK(suggested_path.IsAbsolute()); | 159 DCHECK(suggested_path.IsAbsolute()); |
| 160 | 160 |
| 161 // Create a reservation map if one doesn't exist. It will be automatically | 161 // Create a reservation map if one doesn't exist. It will be automatically |
| 162 // deleted when all the reservations are revoked. | 162 // deleted when all the reservations are revoked. |
| 163 if (g_reservation_map == NULL) | 163 if (g_reservation_map == NULL) |
| 164 g_reservation_map = new ReservationMap; | 164 g_reservation_map = new ReservationMap; |
| 165 | 165 |
| 166 ReservationMap& reservations = *g_reservation_map; | 166 ReservationMap& reservations = *g_reservation_map; |
| 167 DCHECK(!ContainsKey(reservations, key)); | 167 DCHECK(!ContainsKey(reservations, key)); |
| 168 | 168 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 242 | 242 |
| 243 reservations[key] = target_path; | 243 reservations[key] = target_path; |
| 244 bool verified = (is_path_writeable && !has_conflicts && !name_too_long); | 244 bool verified = (is_path_writeable && !has_conflicts && !name_too_long); |
| 245 *reserved_path = target_path; | 245 *reserved_path = target_path; |
| 246 return verified; | 246 return verified; |
| 247 } | 247 } |
| 248 | 248 |
| 249 // Called on the FILE thread to update the path of the reservation associated | 249 // Called on the FILE thread to update the path of the reservation associated |
| 250 // with |key| to |new_path|. | 250 // with |key| to |new_path|. |
| 251 void UpdateReservation(ReservationKey key, const base::FilePath& new_path) { | 251 void UpdateReservation(ReservationKey key, const base::FilePath& new_path) { |
| 252 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 252 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 253 DCHECK(g_reservation_map != NULL); | 253 DCHECK(g_reservation_map != NULL); |
| 254 ReservationMap::iterator iter = g_reservation_map->find(key); | 254 ReservationMap::iterator iter = g_reservation_map->find(key); |
| 255 if (iter != g_reservation_map->end()) { | 255 if (iter != g_reservation_map->end()) { |
| 256 iter->second = new_path; | 256 iter->second = new_path; |
| 257 } else { | 257 } else { |
| 258 // This would happen if an UpdateReservation() notification was scheduled on | 258 // This would happen if an UpdateReservation() notification was scheduled on |
| 259 // the FILE thread before ReserveInternal(), or after a Revoke() | 259 // the FILE thread before ReserveInternal(), or after a Revoke() |
| 260 // call. Neither should happen. | 260 // call. Neither should happen. |
| 261 NOTREACHED(); | 261 NOTREACHED(); |
| 262 } | 262 } |
| 263 } | 263 } |
| 264 | 264 |
| 265 // Called on the FILE thread to remove the path reservation associated with | 265 // Called on the FILE thread to remove the path reservation associated with |
| 266 // |key|. | 266 // |key|. |
| 267 void RevokeReservation(ReservationKey key) { | 267 void RevokeReservation(ReservationKey key) { |
| 268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 268 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 269 DCHECK(g_reservation_map != NULL); | 269 DCHECK(g_reservation_map != NULL); |
| 270 DCHECK(ContainsKey(*g_reservation_map, key)); | 270 DCHECK(ContainsKey(*g_reservation_map, key)); |
| 271 g_reservation_map->erase(key); | 271 g_reservation_map->erase(key); |
| 272 if (g_reservation_map->size() == 0) { | 272 if (g_reservation_map->size() == 0) { |
| 273 // No more reservations. Delete map. | 273 // No more reservations. Delete map. |
| 274 delete g_reservation_map; | 274 delete g_reservation_map; |
| 275 g_reservation_map = NULL; | 275 g_reservation_map = NULL; |
| 276 } | 276 } |
| 277 } | 277 } |
| 278 | 278 |
| 279 void RunGetReservedPathCallback( | 279 void RunGetReservedPathCallback( |
| 280 const DownloadPathReservationTracker::ReservedPathCallback& callback, | 280 const DownloadPathReservationTracker::ReservedPathCallback& callback, |
| 281 const base::FilePath* reserved_path, | 281 const base::FilePath* reserved_path, |
| 282 bool verified) { | 282 bool verified) { |
| 283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 283 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 284 callback.Run(*reserved_path, verified); | 284 callback.Run(*reserved_path, verified); |
| 285 } | 285 } |
| 286 | 286 |
| 287 DownloadItemObserver::DownloadItemObserver(DownloadItem* download_item) | 287 DownloadItemObserver::DownloadItemObserver(DownloadItem* download_item) |
| 288 : download_item_(download_item), | 288 : download_item_(download_item), |
| 289 last_target_path_(download_item->GetTargetFilePath()) { | 289 last_target_path_(download_item->GetTargetFilePath()) { |
| 290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 290 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 291 download_item_->AddObserver(this); | 291 download_item_->AddObserver(this); |
| 292 } | 292 } |
| 293 | 293 |
| 294 DownloadItemObserver::~DownloadItemObserver() { | 294 DownloadItemObserver::~DownloadItemObserver() { |
| 295 download_item_->RemoveObserver(this); | 295 download_item_->RemoveObserver(this); |
| 296 } | 296 } |
| 297 | 297 |
| 298 void DownloadItemObserver::OnDownloadUpdated(DownloadItem* download) { | 298 void DownloadItemObserver::OnDownloadUpdated(DownloadItem* download) { |
| 299 switch (download->GetState()) { | 299 switch (download->GetState()) { |
| 300 case DownloadItem::IN_PROGRESS: { | 300 case DownloadItem::IN_PROGRESS: { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 } // namespace | 343 } // namespace |
| 344 | 344 |
| 345 // static | 345 // static |
| 346 void DownloadPathReservationTracker::GetReservedPath( | 346 void DownloadPathReservationTracker::GetReservedPath( |
| 347 DownloadItem* download_item, | 347 DownloadItem* download_item, |
| 348 const base::FilePath& target_path, | 348 const base::FilePath& target_path, |
| 349 const base::FilePath& default_path, | 349 const base::FilePath& default_path, |
| 350 bool create_directory, | 350 bool create_directory, |
| 351 FilenameConflictAction conflict_action, | 351 FilenameConflictAction conflict_action, |
| 352 const ReservedPathCallback& callback) { | 352 const ReservedPathCallback& callback) { |
| 353 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 353 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 354 // Attach an observer to the download item so that we know when the target | 354 // Attach an observer to the download item so that we know when the target |
| 355 // path changes and/or the download is no longer active. | 355 // path changes and/or the download is no longer active. |
| 356 new DownloadItemObserver(download_item); | 356 new DownloadItemObserver(download_item); |
| 357 // DownloadItemObserver deletes itself. | 357 // DownloadItemObserver deletes itself. |
| 358 | 358 |
| 359 base::FilePath* reserved_path = new base::FilePath; | 359 base::FilePath* reserved_path = new base::FilePath; |
| 360 BrowserThread::PostTaskAndReplyWithResult( | 360 BrowserThread::PostTaskAndReplyWithResult( |
| 361 BrowserThread::FILE, | 361 BrowserThread::FILE, |
| 362 FROM_HERE, | 362 FROM_HERE, |
| 363 base::Bind(&CreateReservation, | 363 base::Bind(&CreateReservation, |
| 364 download_item, | 364 download_item, |
| 365 target_path, | 365 target_path, |
| 366 default_path, | 366 default_path, |
| 367 create_directory, | 367 create_directory, |
| 368 conflict_action, | 368 conflict_action, |
| 369 reserved_path), | 369 reserved_path), |
| 370 base::Bind(&RunGetReservedPathCallback, | 370 base::Bind(&RunGetReservedPathCallback, |
| 371 callback, | 371 callback, |
| 372 base::Owned(reserved_path))); | 372 base::Owned(reserved_path))); |
| 373 } | 373 } |
| 374 | 374 |
| 375 // static | 375 // static |
| 376 bool DownloadPathReservationTracker::IsPathInUseForTesting( | 376 bool DownloadPathReservationTracker::IsPathInUseForTesting( |
| 377 const base::FilePath& path) { | 377 const base::FilePath& path) { |
| 378 return IsPathInUse(path); | 378 return IsPathInUse(path); |
| 379 } | 379 } |
| OLD | NEW |