| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 "build/build_config.h" | |
| 6 | |
| 7 #include "chrome/browser/download/save_file_manager.h" | |
| 8 | |
| 9 #include "base/file_util.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/stl_util-inl.h" | |
| 12 #include "base/string_util.h" | |
| 13 #include "base/task.h" | |
| 14 #include "base/threading/thread.h" | |
| 15 #include "chrome/browser/download/save_file.h" | |
| 16 #include "chrome/browser/download/save_package.h" | |
| 17 #include "chrome/browser/platform_util.h" | |
| 18 #include "chrome/browser/tab_contents/tab_util.h" | |
| 19 #include "chrome/browser/ui/download/download_tab_helper.h" | |
| 20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | |
| 21 #include "chrome/common/chrome_paths.h" | |
| 22 #include "content/browser/browser_thread.h" | |
| 23 #include "content/browser/renderer_host/resource_dispatcher_host.h" | |
| 24 #include "content/browser/tab_contents/tab_contents.h" | |
| 25 #include "googleurl/src/gurl.h" | |
| 26 #include "net/base/net_util.h" | |
| 27 #include "net/base/io_buffer.h" | |
| 28 | |
| 29 SaveFileManager::SaveFileManager(ResourceDispatcherHost* rdh) | |
| 30 : next_id_(0), | |
| 31 resource_dispatcher_host_(rdh) { | |
| 32 DCHECK(resource_dispatcher_host_); | |
| 33 } | |
| 34 | |
| 35 SaveFileManager::~SaveFileManager() { | |
| 36 // Check for clean shutdown. | |
| 37 DCHECK(save_file_map_.empty()); | |
| 38 } | |
| 39 | |
| 40 // Called during the browser shutdown process to clean up any state (open files, | |
| 41 // timers) that live on the saving thread (file thread). | |
| 42 void SaveFileManager::Shutdown() { | |
| 43 BrowserThread::PostTask( | |
| 44 BrowserThread::FILE, FROM_HERE, | |
| 45 NewRunnableMethod(this, &SaveFileManager::OnShutdown)); | |
| 46 } | |
| 47 | |
| 48 // Stop file thread operations. | |
| 49 void SaveFileManager::OnShutdown() { | |
| 50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 51 STLDeleteValues(&save_file_map_); | |
| 52 } | |
| 53 | |
| 54 SaveFile* SaveFileManager::LookupSaveFile(int save_id) { | |
| 55 SaveFileMap::iterator it = save_file_map_.find(save_id); | |
| 56 return it == save_file_map_.end() ? NULL : it->second; | |
| 57 } | |
| 58 | |
| 59 // Called on the IO thread when | |
| 60 // a) The ResourceDispatcherHost has decided that a request is savable. | |
| 61 // b) The resource does not come from the network, but we still need a | |
| 62 // save ID for for managing the status of the saving operation. So we | |
| 63 // file a request from the file thread to the IO thread to generate a | |
| 64 // unique save ID. | |
| 65 int SaveFileManager::GetNextId() { | |
| 66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 67 return next_id_++; | |
| 68 } | |
| 69 | |
| 70 void SaveFileManager::RegisterStartingRequest(const GURL& save_url, | |
| 71 SavePackage* save_package) { | |
| 72 // Make sure it runs in the UI thread. | |
| 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 74 int tab_id = save_package->tab_id(); | |
| 75 | |
| 76 // Register this starting request. | |
| 77 StartingRequestsMap& starting_requests = tab_starting_requests_[tab_id]; | |
| 78 bool never_present = starting_requests.insert( | |
| 79 StartingRequestsMap::value_type(save_url.spec(), save_package)).second; | |
| 80 DCHECK(never_present); | |
| 81 } | |
| 82 | |
| 83 SavePackage* SaveFileManager::UnregisterStartingRequest( | |
| 84 const GURL& save_url, int tab_id) { | |
| 85 // Make sure it runs in UI thread. | |
| 86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 87 | |
| 88 TabToStartingRequestsMap::iterator it = tab_starting_requests_.find(tab_id); | |
| 89 if (it != tab_starting_requests_.end()) { | |
| 90 StartingRequestsMap& requests = it->second; | |
| 91 StartingRequestsMap::iterator sit = requests.find(save_url.spec()); | |
| 92 if (sit == requests.end()) | |
| 93 return NULL; | |
| 94 | |
| 95 // Found, erase it from starting list and return SavePackage. | |
| 96 SavePackage* save_package = sit->second; | |
| 97 requests.erase(sit); | |
| 98 // If there is no element in requests, remove it | |
| 99 if (requests.empty()) | |
| 100 tab_starting_requests_.erase(it); | |
| 101 return save_package; | |
| 102 } | |
| 103 | |
| 104 return NULL; | |
| 105 } | |
| 106 | |
| 107 // Look up a SavePackage according to a save id. | |
| 108 SavePackage* SaveFileManager::LookupPackage(int save_id) { | |
| 109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 110 SavePackageMap::iterator it = packages_.find(save_id); | |
| 111 if (it != packages_.end()) | |
| 112 return it->second; | |
| 113 return NULL; | |
| 114 } | |
| 115 | |
| 116 // Call from SavePackage for starting a saving job | |
| 117 void SaveFileManager::SaveURL( | |
| 118 const GURL& url, | |
| 119 const GURL& referrer, | |
| 120 int render_process_host_id, | |
| 121 int render_view_id, | |
| 122 SaveFileCreateInfo::SaveFileSource save_source, | |
| 123 const FilePath& file_full_path, | |
| 124 const content::ResourceContext& context, | |
| 125 SavePackage* save_package) { | |
| 126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 127 | |
| 128 // Register a saving job. | |
| 129 RegisterStartingRequest(url, save_package); | |
| 130 if (save_source == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { | |
| 131 DCHECK(url.is_valid()); | |
| 132 | |
| 133 BrowserThread::PostTask( | |
| 134 BrowserThread::IO, FROM_HERE, | |
| 135 NewRunnableMethod(this, | |
| 136 &SaveFileManager::OnSaveURL, | |
| 137 url, | |
| 138 referrer, | |
| 139 render_process_host_id, | |
| 140 render_view_id, | |
| 141 &context)); | |
| 142 } else { | |
| 143 // We manually start the save job. | |
| 144 SaveFileCreateInfo* info = new SaveFileCreateInfo(file_full_path, | |
| 145 url, | |
| 146 save_source, | |
| 147 -1); | |
| 148 info->render_process_id = render_process_host_id; | |
| 149 info->render_view_id = render_view_id; | |
| 150 | |
| 151 // Since the data will come from render process, so we need to start | |
| 152 // this kind of save job by ourself. | |
| 153 BrowserThread::PostTask( | |
| 154 BrowserThread::IO, FROM_HERE, | |
| 155 NewRunnableMethod( | |
| 156 this, &SaveFileManager::OnRequireSaveJobFromOtherSource, info)); | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 // Utility function for look up table maintenance, called on the UI thread. | |
| 161 // A manager may have multiple save page job (SavePackage) in progress, | |
| 162 // so we just look up the save id and remove it from the tracking table. | |
| 163 // If the save id is -1, it means we just send a request to save, but the | |
| 164 // saving action has still not happened, need to call UnregisterStartingRequest | |
| 165 // to remove it from the tracking map. | |
| 166 void SaveFileManager::RemoveSaveFile(int save_id, const GURL& save_url, | |
| 167 SavePackage* package) { | |
| 168 DCHECK(package); | |
| 169 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 170 // A save page job (SavePackage) can only have one manager, | |
| 171 // so remove it if it exists. | |
| 172 if (save_id == -1) { | |
| 173 SavePackage* old_package = UnregisterStartingRequest(save_url, | |
| 174 package->tab_id()); | |
| 175 DCHECK_EQ(old_package, package); | |
| 176 } else { | |
| 177 SavePackageMap::iterator it = packages_.find(save_id); | |
| 178 if (it != packages_.end()) | |
| 179 packages_.erase(it); | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 // Static | |
| 184 // Utility function for converting request IDs to a TabContents. Must be called | |
| 185 // only on the UI thread. | |
| 186 SavePackage* SaveFileManager::GetSavePackageFromRenderIds( | |
| 187 int render_process_id, int render_view_id) { | |
| 188 TabContents* contents = tab_util::GetTabContentsByID(render_process_id, | |
| 189 render_view_id); | |
| 190 if (contents) { | |
| 191 TabContentsWrapper* wrapper = | |
| 192 TabContentsWrapper::GetCurrentWrapperForContents(contents); | |
| 193 return wrapper->download_tab_helper()->save_package(); | |
| 194 } | |
| 195 | |
| 196 return NULL; | |
| 197 } | |
| 198 | |
| 199 // Utility function for deleting specified file. | |
| 200 void SaveFileManager::DeleteDirectoryOrFile(const FilePath& full_path, | |
| 201 bool is_dir) { | |
| 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 203 BrowserThread::PostTask( | |
| 204 BrowserThread::FILE, FROM_HERE, | |
| 205 NewRunnableMethod( | |
| 206 this, &SaveFileManager::OnDeleteDirectoryOrFile, full_path, is_dir)); | |
| 207 } | |
| 208 | |
| 209 void SaveFileManager::SendCancelRequest(int save_id) { | |
| 210 // Cancel the request which has specific save id. | |
| 211 DCHECK_GT(save_id, -1); | |
| 212 BrowserThread::PostTask( | |
| 213 BrowserThread::FILE, FROM_HERE, | |
| 214 NewRunnableMethod(this, &SaveFileManager::CancelSave, save_id)); | |
| 215 } | |
| 216 | |
| 217 // Notifications sent from the IO thread and run on the file thread: | |
| 218 | |
| 219 // The IO thread created |info|, but the file thread (this method) uses it | |
| 220 // to create a SaveFile which will hold and finally destroy |info|. It will | |
| 221 // then passes |info| to the UI thread for reporting saving status. | |
| 222 void SaveFileManager::StartSave(SaveFileCreateInfo* info) { | |
| 223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 224 DCHECK(info); | |
| 225 SaveFile* save_file = new SaveFile(info); | |
| 226 | |
| 227 // TODO(phajdan.jr): We should check the return value and handle errors here. | |
| 228 save_file->Initialize(false); // No need to calculate hash. | |
| 229 | |
| 230 DCHECK(!LookupSaveFile(info->save_id)); | |
| 231 save_file_map_[info->save_id] = save_file; | |
| 232 info->path = save_file->full_path(); | |
| 233 | |
| 234 BrowserThread::PostTask( | |
| 235 BrowserThread::UI, FROM_HERE, | |
| 236 NewRunnableMethod(this, &SaveFileManager::OnStartSave, info)); | |
| 237 } | |
| 238 | |
| 239 // We do forward an update to the UI thread here, since we do not use timer to | |
| 240 // update the UI. If the user has canceled the saving action (in the UI | |
| 241 // thread). We may receive a few more updates before the IO thread gets the | |
| 242 // cancel message. We just delete the data since the SaveFile has been deleted. | |
| 243 void SaveFileManager::UpdateSaveProgress(int save_id, | |
| 244 net::IOBuffer* data, | |
| 245 int data_len) { | |
| 246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 247 SaveFile* save_file = LookupSaveFile(save_id); | |
| 248 if (save_file) { | |
| 249 bool write_success = save_file->AppendDataToFile(data->data(), data_len); | |
| 250 BrowserThread::PostTask( | |
| 251 BrowserThread::UI, FROM_HERE, | |
| 252 NewRunnableMethod( | |
| 253 this, &SaveFileManager::OnUpdateSaveProgress, save_file->save_id(), | |
| 254 save_file->bytes_so_far(), write_success)); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 // The IO thread will call this when saving is completed or it got error when | |
| 259 // fetching data. In the former case, we forward the message to OnSaveFinished | |
| 260 // in UI thread. In the latter case, the save ID will be -1, which means the | |
| 261 // saving action did not even start, so we need to call OnErrorFinished in UI | |
| 262 // thread, which will use the save URL to find corresponding request record and | |
| 263 // delete it. | |
| 264 void SaveFileManager::SaveFinished(int save_id, | |
| 265 const GURL& save_url, | |
| 266 int render_process_id, | |
| 267 bool is_success) { | |
| 268 VLOG(20) << " " << __FUNCTION__ << "()" | |
| 269 << " save_id = " << save_id | |
| 270 << " save_url = \"" << save_url.spec() << "\"" | |
| 271 << " is_success = " << is_success; | |
| 272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 273 SaveFileMap::iterator it = save_file_map_.find(save_id); | |
| 274 if (it != save_file_map_.end()) { | |
| 275 SaveFile* save_file = it->second; | |
| 276 VLOG(20) << " " << __FUNCTION__ << "()" | |
| 277 << " save_file = " << save_file->DebugString(); | |
| 278 BrowserThread::PostTask( | |
| 279 BrowserThread::UI, FROM_HERE, | |
| 280 NewRunnableMethod( | |
| 281 this, &SaveFileManager::OnSaveFinished, save_id, | |
| 282 save_file->bytes_so_far(), is_success)); | |
| 283 | |
| 284 save_file->Finish(); | |
| 285 save_file->Detach(); | |
| 286 } else if (save_id == -1) { | |
| 287 // Before saving started, we got error. We still call finish process. | |
| 288 DCHECK(!save_url.is_empty()); | |
| 289 BrowserThread::PostTask( | |
| 290 BrowserThread::UI, FROM_HERE, | |
| 291 NewRunnableMethod( | |
| 292 this, &SaveFileManager::OnErrorFinished, save_url, | |
| 293 render_process_id)); | |
| 294 } | |
| 295 } | |
| 296 | |
| 297 // Notifications sent from the file thread and run on the UI thread. | |
| 298 | |
| 299 void SaveFileManager::OnStartSave(const SaveFileCreateInfo* info) { | |
| 300 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 301 SavePackage* save_package = | |
| 302 GetSavePackageFromRenderIds(info->render_process_id, | |
| 303 info->render_view_id); | |
| 304 if (!save_package) { | |
| 305 // Cancel this request. | |
| 306 SendCancelRequest(info->save_id); | |
| 307 return; | |
| 308 } | |
| 309 | |
| 310 // Insert started saving job to tracking list. | |
| 311 SavePackageMap::iterator sit = packages_.find(info->save_id); | |
| 312 if (sit == packages_.end()) { | |
| 313 // Find the registered request. If we can not find, it means we have | |
| 314 // canceled the job before. | |
| 315 SavePackage* old_save_package = UnregisterStartingRequest(info->url, | |
| 316 info->render_process_id); | |
| 317 if (!old_save_package) { | |
| 318 // Cancel this request. | |
| 319 SendCancelRequest(info->save_id); | |
| 320 return; | |
| 321 } | |
| 322 DCHECK_EQ(old_save_package, save_package); | |
| 323 packages_[info->save_id] = save_package; | |
| 324 } else { | |
| 325 NOTREACHED(); | |
| 326 } | |
| 327 | |
| 328 // Forward this message to SavePackage. | |
| 329 save_package->StartSave(info); | |
| 330 } | |
| 331 | |
| 332 void SaveFileManager::OnUpdateSaveProgress(int save_id, int64 bytes_so_far, | |
| 333 bool write_success) { | |
| 334 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 335 SavePackage* package = LookupPackage(save_id); | |
| 336 if (package) | |
| 337 package->UpdateSaveProgress(save_id, bytes_so_far, write_success); | |
| 338 else | |
| 339 SendCancelRequest(save_id); | |
| 340 } | |
| 341 | |
| 342 void SaveFileManager::OnSaveFinished(int save_id, | |
| 343 int64 bytes_so_far, | |
| 344 bool is_success) { | |
| 345 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 346 SavePackage* package = LookupPackage(save_id); | |
| 347 if (package) | |
| 348 package->SaveFinished(save_id, bytes_so_far, is_success); | |
| 349 } | |
| 350 | |
| 351 void SaveFileManager::OnErrorFinished(const GURL& save_url, int tab_id) { | |
| 352 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 353 SavePackage* save_package = UnregisterStartingRequest(save_url, tab_id); | |
| 354 if (save_package) | |
| 355 save_package->SaveFailed(save_url); | |
| 356 } | |
| 357 | |
| 358 // Notifications sent from the UI thread and run on the IO thread. | |
| 359 | |
| 360 void SaveFileManager::OnSaveURL( | |
| 361 const GURL& url, | |
| 362 const GURL& referrer, | |
| 363 int render_process_host_id, | |
| 364 int render_view_id, | |
| 365 const content::ResourceContext* context) { | |
| 366 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 367 resource_dispatcher_host_->BeginSaveFile(url, | |
| 368 referrer, | |
| 369 render_process_host_id, | |
| 370 render_view_id, | |
| 371 *context); | |
| 372 } | |
| 373 | |
| 374 void SaveFileManager::OnRequireSaveJobFromOtherSource( | |
| 375 SaveFileCreateInfo* info) { | |
| 376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 377 DCHECK_EQ(info->save_id, -1); | |
| 378 // Generate a unique save id. | |
| 379 info->save_id = GetNextId(); | |
| 380 // Start real saving action. | |
| 381 BrowserThread::PostTask( | |
| 382 BrowserThread::FILE, FROM_HERE, | |
| 383 NewRunnableMethod(this, &SaveFileManager::StartSave, info)); | |
| 384 } | |
| 385 | |
| 386 void SaveFileManager::ExecuteCancelSaveRequest(int render_process_id, | |
| 387 int request_id) { | |
| 388 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 389 resource_dispatcher_host_->CancelRequest(render_process_id, | |
| 390 request_id, | |
| 391 false); | |
| 392 } | |
| 393 | |
| 394 // Notifications sent from the UI thread and run on the file thread. | |
| 395 | |
| 396 // This method will be sent via a user action, or shutdown on the UI thread, | |
| 397 // and run on the file thread. We don't post a message back for cancels, | |
| 398 // but we do forward the cancel to the IO thread. Since this message has been | |
| 399 // sent from the UI thread, the saving job may have already completed and | |
| 400 // won't exist in our map. | |
| 401 void SaveFileManager::CancelSave(int save_id) { | |
| 402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 403 SaveFileMap::iterator it = save_file_map_.find(save_id); | |
| 404 if (it != save_file_map_.end()) { | |
| 405 SaveFile* save_file = it->second; | |
| 406 | |
| 407 // If the data comes from the net IO thread, then forward the cancel | |
| 408 // message to IO thread. If the data comes from other sources, just | |
| 409 // ignore the cancel message. | |
| 410 if (save_file->save_source() == SaveFileCreateInfo::SAVE_FILE_FROM_NET) { | |
| 411 BrowserThread::PostTask( | |
| 412 BrowserThread::IO, FROM_HERE, | |
| 413 NewRunnableMethod( | |
| 414 this, &SaveFileManager::ExecuteCancelSaveRequest, | |
| 415 save_file->render_process_id(), save_file->request_id())); | |
| 416 | |
| 417 // UI thread will notify the render process to stop sending data, | |
| 418 // so in here, we need not to do anything, just close the save file. | |
| 419 save_file->Cancel(); | |
| 420 } else { | |
| 421 // If we did not find SaveFile in map, the saving job should either get | |
| 422 // data from other sources or have finished. | |
| 423 DCHECK(save_file->save_source() != | |
| 424 SaveFileCreateInfo::SAVE_FILE_FROM_NET || | |
| 425 !save_file->in_progress()); | |
| 426 } | |
| 427 // Whatever the save file is renamed or not, just delete it. | |
| 428 save_file_map_.erase(it); | |
| 429 delete save_file; | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 // It is possible that SaveItem which has specified save_id has been canceled | |
| 434 // before this function runs. So if we can not find corresponding SaveFile by | |
| 435 // using specified save_id, just return. | |
| 436 void SaveFileManager::SaveLocalFile(const GURL& original_file_url, | |
| 437 int save_id, | |
| 438 int render_process_id) { | |
| 439 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 440 SaveFile* save_file = LookupSaveFile(save_id); | |
| 441 if (!save_file) | |
| 442 return; | |
| 443 // If it has finished, just return. | |
| 444 if (!save_file->in_progress()) | |
| 445 return; | |
| 446 | |
| 447 // Close the save file before the copy operation. | |
| 448 save_file->Finish(); | |
| 449 save_file->Detach(); | |
| 450 | |
| 451 DCHECK(original_file_url.SchemeIsFile()); | |
| 452 FilePath file_path; | |
| 453 net::FileURLToFilePath(original_file_url, &file_path); | |
| 454 // If we can not get valid file path from original URL, treat it as | |
| 455 // disk error. | |
| 456 if (file_path.empty()) | |
| 457 SaveFinished(save_id, original_file_url, render_process_id, false); | |
| 458 | |
| 459 // Copy the local file to the temporary file. It will be renamed to its | |
| 460 // final name later. | |
| 461 bool success = file_util::CopyFile(file_path, save_file->full_path()); | |
| 462 if (!success) | |
| 463 file_util::Delete(save_file->full_path(), false); | |
| 464 SaveFinished(save_id, original_file_url, render_process_id, success); | |
| 465 } | |
| 466 | |
| 467 void SaveFileManager::OnDeleteDirectoryOrFile(const FilePath& full_path, | |
| 468 bool is_dir) { | |
| 469 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 470 DCHECK(!full_path.empty()); | |
| 471 | |
| 472 file_util::Delete(full_path, is_dir); | |
| 473 } | |
| 474 | |
| 475 // Open a saved page package, show it in a Windows Explorer window. | |
| 476 // We run on this thread to avoid blocking the UI with slow Shell operations. | |
| 477 #if !defined(OS_MACOSX) | |
| 478 void SaveFileManager::OnShowSavedFileInShell(const FilePath full_path) { | |
| 479 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 480 platform_util::ShowItemInFolder(full_path); | |
| 481 } | |
| 482 #endif | |
| 483 | |
| 484 void SaveFileManager::RenameAllFiles( | |
| 485 const FinalNameList& final_names, | |
| 486 const FilePath& resource_dir, | |
| 487 int render_process_id, | |
| 488 int render_view_id, | |
| 489 int save_package_id) { | |
| 490 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 491 | |
| 492 if (!resource_dir.empty() && !file_util::PathExists(resource_dir)) | |
| 493 file_util::CreateDirectory(resource_dir); | |
| 494 | |
| 495 for (FinalNameList::const_iterator i = final_names.begin(); | |
| 496 i != final_names.end(); ++i) { | |
| 497 SaveFileMap::iterator it = save_file_map_.find(i->first); | |
| 498 if (it != save_file_map_.end()) { | |
| 499 SaveFile* save_file = it->second; | |
| 500 DCHECK(!save_file->in_progress()); | |
| 501 save_file->Rename(i->second); | |
| 502 delete save_file; | |
| 503 save_file_map_.erase(it); | |
| 504 } | |
| 505 } | |
| 506 | |
| 507 BrowserThread::PostTask( | |
| 508 BrowserThread::UI, FROM_HERE, | |
| 509 NewRunnableMethod( | |
| 510 this, &SaveFileManager::OnFinishSavePageJob, render_process_id, | |
| 511 render_view_id, save_package_id)); | |
| 512 } | |
| 513 | |
| 514 void SaveFileManager::OnFinishSavePageJob(int render_process_id, | |
| 515 int render_view_id, | |
| 516 int save_package_id) { | |
| 517 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 518 | |
| 519 SavePackage* save_package = | |
| 520 GetSavePackageFromRenderIds(render_process_id, render_view_id); | |
| 521 | |
| 522 if (save_package && save_package->id() == save_package_id) | |
| 523 save_package->Finish(); | |
| 524 } | |
| 525 | |
| 526 void SaveFileManager::RemoveSavedFileFromFileMap( | |
| 527 const SaveIDList& save_ids) { | |
| 528 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 529 | |
| 530 for (SaveIDList::const_iterator i = save_ids.begin(); | |
| 531 i != save_ids.end(); ++i) { | |
| 532 SaveFileMap::iterator it = save_file_map_.find(*i); | |
| 533 if (it != save_file_map_.end()) { | |
| 534 SaveFile* save_file = it->second; | |
| 535 DCHECK(!save_file->in_progress()); | |
| 536 file_util::Delete(save_file->full_path(), false); | |
| 537 delete save_file; | |
| 538 save_file_map_.erase(it); | |
| 539 } | |
| 540 } | |
| 541 } | |
| OLD | NEW |