1 // Copyright 2014 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.
5 #include "chrome/browser/chromeos/drive/fileapi/webkit_file_stream_writer_impl.h"
8 #include "base/callback_helpers.h"
9 #include "chrome/browser/chromeos/drive/fileapi/fileapi_worker.h"
10 #include "components/drive/file_system_core_util.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "google_apis/drive/task_util.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/net_errors.h"
15 #include "storage/browser/fileapi/file_stream_writer.h"
17 using content::BrowserThread
;
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_CURRENTLY_ON(BrowserThread::IO
);
30 BrowserThread::PostTask(
34 &fileapi_internal::RunFileSystemCallback
,
36 base::Bind(&fileapi_internal::CreateWritableSnapshotFile
,
37 drive_path
, google_apis::CreateRelayCallback(callback
)),
38 google_apis::CreateRelayCallback(base::Bind(
39 callback
, base::File::FILE_ERROR_FAILED
, base::FilePath(),
45 WebkitFileStreamWriterImpl::WebkitFileStreamWriterImpl(
46 const FileSystemGetter
& file_system_getter
,
47 base::TaskRunner
* file_task_runner
,
48 const base::FilePath
& file_path
,
50 : file_system_getter_(file_system_getter
),
51 file_task_runner_(file_task_runner
),
52 file_path_(file_path
),
54 weak_ptr_factory_(this) {
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
,
65 close_callback_on_ui_thread_
);
69 int WebkitFileStreamWriterImpl::Write(net::IOBuffer
* buf
,
71 const net::CompletionCallback
& callback
) {
72 DCHECK(pending_write_callback_
.is_null());
73 DCHECK(pending_cancel_callback_
.is_null());
74 DCHECK(!callback
.is_null());
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
);
80 // The local file is not yet ready. Create the writable snapshot.
81 if (file_path_
.empty())
82 return net::ERR_FILE_NOT_FOUND
;
84 pending_write_callback_
= callback
;
85 CreateWritableSnapshotFile(
86 file_system_getter_
, file_path_
,
88 &WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile
,
89 weak_ptr_factory_
.GetWeakPtr(), make_scoped_refptr(buf
), buf_len
));
90 return net::ERR_IO_PENDING
;
93 int WebkitFileStreamWriterImpl::Cancel(
94 const net::CompletionCallback
& callback
) {
95 DCHECK(pending_cancel_callback_
.is_null());
96 DCHECK(!callback
.is_null());
98 // If LocalFileWriter is already created, just delegate the cancel to it.
99 if (local_file_writer_
)
100 return local_file_writer_
->Cancel(callback
);
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
;
111 // Write() is not called yet.
112 return net::ERR_UNEXPECTED
;
115 int WebkitFileStreamWriterImpl::Flush(const net::CompletionCallback
& callback
) {
116 DCHECK(pending_cancel_callback_
.is_null());
117 DCHECK(!callback
.is_null());
119 // If LocalFileWriter is already created, just delegate to it.
120 if (local_file_writer_
)
121 return local_file_writer_
->Flush(callback
);
123 // There shouldn't be in-flight Write operation.
124 DCHECK(pending_write_callback_
.is_null());
126 // Here is the case Flush() is called before any Write() invocation.
128 // Synchronization to the remote server is not done until the file is closed.
132 void WebkitFileStreamWriterImpl::WriteAfterCreateWritableSnapshotFile(
135 base::File::Error open_result
,
136 const base::FilePath
& local_path
,
137 const base::Closure
& close_callback_on_ui_thread
) {
138 DCHECK(!local_file_writer_
);
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::File::FILE_OK
) {
145 // Here the file is internally created. To revert the operation, close
147 DCHECK(!close_callback_on_ui_thread
.is_null());
148 BrowserThread::PostTask(BrowserThread::UI
,
150 close_callback_on_ui_thread
);
153 base::ResetAndReturn(&pending_cancel_callback_
).Run(net::OK
);
157 DCHECK(!pending_write_callback_
.is_null());
159 const net::CompletionCallback callback
=
160 base::ResetAndReturn(&pending_write_callback_
);
161 if (open_result
!= base::File::FILE_OK
) {
162 DCHECK(close_callback_on_ui_thread
.is_null());
164 net::FileErrorToNetError(open_result
));
168 // Keep |close_callback| to close the file when the stream is destructed.
169 DCHECK(!close_callback_on_ui_thread
.is_null());
170 close_callback_on_ui_thread_
= close_callback_on_ui_thread
;
171 local_file_writer_
.reset(storage::FileStreamWriter::CreateForLocalFile(
172 file_task_runner_
.get(),
175 storage::FileStreamWriter::OPEN_EXISTING_FILE
));
176 int result
= local_file_writer_
->Write(buf
, buf_len
, callback
);
177 if (result
!= net::ERR_IO_PENDING
)
178 callback
.Run(result
);
181 } // namespace internal