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