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/webkit_file_stream_writer_impl.h" 6 7 #include "base/bind.h" 8 #include "base/callback_helpers.h" 9 #include "chrome/browser/chromeos/drive/file_system_util.h" 10 #include "chrome/browser/chromeos/drive/fileapi_worker.h" 11 #include "chrome/browser/google_apis/task_util.h" 12 #include "content/public/browser/browser_thread.h" 13 #include "net/base/io_buffer.h" 14 #include "net/base/net_errors.h" 15 #include "webkit/browser/fileapi/local_file_stream_writer.h" 16 17 using content::BrowserThread; 18 19 namespace drive { 20 namespace internal { 21 namespace { 22 23 // Creates a writable snapshot file of the |drive_path|. 24 void CreateWritableSnapshotFile( 25 const WebkitFileStreamWriterImpl::FileSystemGetter& file_system_getter, 26 const base::FilePath& drive_path, 27 const fileapi_internal::CreateWritableSnapshotFileCallback& callback) { 28 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 29 30 BrowserThread::PostTask( 31 BrowserThread::UI, 32 FROM_HERE, 33 base::Bind( 34 &fileapi_internal::RunFileSystemCallback, 35 file_system_getter, 36 base::Bind(&fileapi_internal::CreateWritableSnapshotFile, 37 drive_path, google_apis::CreateRelayCallback(callback)), 38 google_apis::CreateRelayCallback(base::Bind( 39 callback, base::PLATFORM_FILE_ERROR_FAILED, base::FilePath(), 40 base::Closure())))); 41 } 42 43 } // namespace 44 45 WebkitFileStreamWriterImpl::WebkitFileStreamWriterImpl( 46 const FileSystemGetter& file_system_getter, 47 base::TaskRunner* file_task_runner, 48 const base::FilePath& file_path, 49 int64 offset) 50 : file_system_getter_(file_system_getter), 51 file_task_runner_(file_task_runner), 52 file_path_(file_path), 53 offset_(offset), 54 weak_ptr_factory_(this) { 55 } 56 57 WebkitFileStreamWriterImpl::~WebkitFileStreamWriterImpl() { 58 if (local_file_writer_) { 59 // If the file is opened, close it at destructor. 60 // It is necessary to close the local file in advance. 61 local_file_writer_.reset(); 62 DCHECK(!close_callback_on_ui_thread_.is_null()); 63 BrowserThread::PostTask(BrowserThread::UI, 64 FROM_HERE, 65 close_callback_on_ui_thread_); 66 } 67 } 68 69 int WebkitFileStreamWriterImpl::Write(net::IOBuffer* buf, 70 int buf_len, 71 const net::CompletionCallback& callback) { 72 DCHECK(pending_write_callback_.is_null()); 73 DCHECK(pending_cancel_callback_.is_null()); 74 DCHECK(!callback.is_null()); 75 76 // If the local file is already available, just delegate to it. 77 if (local_file_writer_) 78 return local_file_writer_->Write(buf, buf_len, callback); 79 80 // The local file is not yet ready. Create the writable snapshot. 81 if (file_path_.empty()) 82 return net::ERR_FILE_NOT_FOUND; 83 84 pending_write_callback_ = callback; 85 CreateWritableSnapshotFile( 86 file_system_getter_, file_path_, 87 base::Bind( 88 &WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile, 89 weak_ptr_factory_.GetWeakPtr(), make_scoped_refptr(buf), buf_len)); 90 return net::ERR_IO_PENDING; 91 } 92 93 int WebkitFileStreamWriterImpl::Cancel( 94 const net::CompletionCallback& callback) { 95 DCHECK(pending_cancel_callback_.is_null()); 96 DCHECK(!callback.is_null()); 97 98 // If LocalFileWriter is already created, just delegate the cancel to it. 99 if (local_file_writer_) 100 return local_file_writer_->Cancel(callback); 101 102 // If file open operation is in-flight, wait for its completion and cancel 103 // further write operation in WriteAfterCreateWritableSnapshotFile. 104 if (!pending_write_callback_.is_null()) { 105 // Dismiss pending write callback immediately. 106 pending_write_callback_.Reset(); 107 pending_cancel_callback_ = callback; 108 return net::ERR_IO_PENDING; 109 } 110 111 // Write() is not called yet. 112 return net::ERR_UNEXPECTED; 113 } 114 115 int WebkitFileStreamWriterImpl::Flush(const net::CompletionCallback& callback) { 116 DCHECK(pending_cancel_callback_.is_null()); 117 DCHECK(!callback.is_null()); 118 119 // If LocalFileWriter is already created, just delegate to it. 120 if (local_file_writer_) 121 return local_file_writer_->Flush(callback); 122 123 // There shouldn't be in-flight Write operation. 124 DCHECK(pending_write_callback_.is_null()); 125 126 // Here is the case Flush() is called before any Write() invocation. 127 // Do nothing. 128 // Synchronization to the remote server is not done until the file is closed. 129 return net::OK; 130 } 131 132 void WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile( 133 net::IOBuffer* buf, 134 int buf_len, 135 base::PlatformFileError open_result, 136 const base::FilePath& local_path, 137 const base::Closure& close_callback_on_ui_thread) { 138 DCHECK(!local_file_writer_); 139 140 if (!pending_cancel_callback_.is_null()) { 141 DCHECK(pending_write_callback_.is_null()); 142 // Cancel() is called during the creation of the snapshot file. 143 // Don't write to the file. 144 if (open_result == base::PLATFORM_FILE_OK) { 145 // Here the file is internally created. To revert the operation, close 146 // the file. 147 DCHECK(!close_callback_on_ui_thread.is_null()); 148 BrowserThread::PostTask(BrowserThread::UI, 149 FROM_HERE, 150 close_callback_on_ui_thread); 151 } 152 153 base::ResetAndReturn(&pending_cancel_callback_).Run(net::OK); 154 return; 155 } 156 157 DCHECK(!pending_write_callback_.is_null()); 158 159 const net::CompletionCallback callback = 160 base::ResetAndReturn(&pending_write_callback_); 161 if (open_result != base::PLATFORM_FILE_OK) { 162 DCHECK(close_callback_on_ui_thread.is_null()); 163 callback.Run(net::PlatformFileErrorToNetError(open_result)); 164 return; 165 } 166 167 // Keep |close_callback| to close the file when the stream is destructed. 168 DCHECK(!close_callback_on_ui_thread.is_null()); 169 close_callback_on_ui_thread_ = close_callback_on_ui_thread; 170 local_file_writer_.reset(new fileapi::LocalFileStreamWriter( 171 file_task_runner_.get(), local_path, offset_)); 172 int result = local_file_writer_->Write(buf, buf_len, callback); 173 if (result != net::ERR_IO_PENDING) 174 callback.Run(result); 175 } 176 177 } // namespace internal 178 } // namespace drive 179