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