1 // Copyright 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 "chrome/browser/chromeos/drive/file_system/truncate_operation.h" 6 7 #include "base/bind.h" 8 #include "base/files/file_path.h" 9 #include "base/files/scoped_platform_file_closer.h" 10 #include "base/logging.h" 11 #include "base/message_loop/message_loop_proxy.h" 12 #include "base/platform_file.h" 13 #include "base/sequenced_task_runner.h" 14 #include "base/task_runner_util.h" 15 #include "chrome/browser/chromeos/drive/drive.pb.h" 16 #include "chrome/browser/chromeos/drive/file_cache.h" 17 #include "chrome/browser/chromeos/drive/file_errors.h" 18 #include "chrome/browser/chromeos/drive/file_system/download_operation.h" 19 #include "chrome/browser/chromeos/drive/file_system/operation_observer.h" 20 #include "content/public/browser/browser_thread.h" 21 22 using content::BrowserThread; 23 24 namespace drive { 25 namespace file_system { 26 namespace { 27 28 // Truncates the local file at |local_cache_path| to the |length| bytes, 29 // then marks the resource is dirty on |cache|. 30 FileError TruncateOnBlockingPool(internal::FileCache* cache, 31 const std::string& resource_id, 32 const base::FilePath& local_cache_path, 33 int64 length) { 34 DCHECK(cache); 35 36 FileError error = cache->MarkDirty(resource_id); 37 if (error != FILE_ERROR_OK) 38 return error; 39 40 base::PlatformFileError result = base::PLATFORM_FILE_ERROR_FAILED; 41 base::PlatformFile file = base::CreatePlatformFile( 42 local_cache_path, 43 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, 44 NULL, 45 &result); 46 if (result != base::PLATFORM_FILE_OK) 47 return FILE_ERROR_FAILED; 48 49 DCHECK_NE(base::kInvalidPlatformFileValue, file); 50 base::ScopedPlatformFileCloser file_closer(&file); 51 52 if (!base::TruncatePlatformFile(file, length)) 53 return FILE_ERROR_FAILED; 54 55 return FILE_ERROR_OK; 56 } 57 58 } // namespace 59 60 TruncateOperation::TruncateOperation( 61 base::SequencedTaskRunner* blocking_task_runner, 62 OperationObserver* observer, 63 JobScheduler* scheduler, 64 internal::ResourceMetadata* metadata, 65 internal::FileCache* cache, 66 const base::FilePath& temporary_file_directory) 67 : blocking_task_runner_(blocking_task_runner), 68 observer_(observer), 69 cache_(cache), 70 download_operation_(new DownloadOperation(blocking_task_runner, 71 observer, 72 scheduler, 73 metadata, 74 cache, 75 temporary_file_directory)), 76 weak_ptr_factory_(this) { 77 } 78 79 TruncateOperation::~TruncateOperation() { 80 } 81 82 void TruncateOperation::Truncate(const base::FilePath& file_path, 83 int64 length, 84 const FileOperationCallback& callback) { 85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 86 87 if (length < 0) { 88 base::MessageLoopProxy::current()->PostTask( 89 FROM_HERE, 90 base::Bind(callback, FILE_ERROR_INVALID_OPERATION)); 91 return; 92 } 93 94 // TODO(kinaba): http://crbug.com/132780. 95 // Optimize the cases for small |length|, at least for |length| == 0. 96 download_operation_->EnsureFileDownloadedByPath( 97 file_path, 98 ClientContext(USER_INITIATED), 99 GetFileContentInitializedCallback(), 100 google_apis::GetContentCallback(), 101 base::Bind(&TruncateOperation::TruncateAfterEnsureFileDownloadedByPath, 102 weak_ptr_factory_.GetWeakPtr(), file_path, length, callback)); 103 } 104 105 void TruncateOperation::TruncateAfterEnsureFileDownloadedByPath( 106 const base::FilePath& file_path, 107 int64 length, 108 const FileOperationCallback& callback, 109 FileError error, 110 const base::FilePath& local_file_path, 111 scoped_ptr<ResourceEntry> entry) { 112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 113 DCHECK(!callback.is_null()); 114 115 if (error != FILE_ERROR_OK) { 116 callback.Run(error); 117 return; 118 } 119 DCHECK(entry); 120 DCHECK(entry->has_file_specific_info()); 121 122 if (entry->file_specific_info().is_hosted_document()) { 123 callback.Run(FILE_ERROR_INVALID_OPERATION); 124 return; 125 } 126 127 base::PostTaskAndReplyWithResult( 128 blocking_task_runner_.get(), 129 FROM_HERE, 130 base::Bind(&TruncateOnBlockingPool, 131 base::Unretained(cache_), 132 entry->resource_id(), 133 local_file_path, length), 134 base::Bind( 135 &TruncateOperation::TruncateAfterTruncateOnBlockingPool, 136 weak_ptr_factory_.GetWeakPtr(), entry->resource_id(), callback)); 137 } 138 139 void TruncateOperation::TruncateAfterTruncateOnBlockingPool( 140 const std::string& resource_id, 141 const FileOperationCallback& callback, 142 FileError error) { 143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 144 DCHECK(!callback.is_null()); 145 146 observer_->OnCacheFileUploadNeededByOperation(resource_id); 147 148 callback.Run(error); 149 } 150 151 } // namespace file_system 152 } // namespace drive 153