• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "webkit/browser/fileapi/local_file_stream_writer.h"
6 
7 #include "base/callback.h"
8 #include "base/message_loop/message_loop.h"
9 #include "net/base/file_stream.h"
10 #include "net/base/io_buffer.h"
11 #include "net/base/net_errors.h"
12 
13 namespace fileapi {
14 
15 namespace {
16 
17 const int kOpenFlagsForWrite = base::PLATFORM_FILE_OPEN |
18                                base::PLATFORM_FILE_WRITE |
19                                base::PLATFORM_FILE_ASYNC;
20 
21 }  // namespace
22 
CreateForLocalFile(base::TaskRunner * task_runner,const base::FilePath & file_path,int64 initial_offset)23 FileStreamWriter* FileStreamWriter::CreateForLocalFile(
24     base::TaskRunner* task_runner,
25     const base::FilePath& file_path,
26     int64 initial_offset) {
27   return new LocalFileStreamWriter(task_runner, file_path, initial_offset);
28 }
29 
~LocalFileStreamWriter()30 LocalFileStreamWriter::~LocalFileStreamWriter() {
31   // Invalidate weak pointers so that we won't receive any callbacks from
32   // in-flight stream operations, which might be triggered during the file close
33   // in the FileStream destructor.
34   weak_factory_.InvalidateWeakPtrs();
35 
36   // FileStream's destructor closes the file safely, since we opened the file
37   // by its Open() method.
38 }
39 
Write(net::IOBuffer * buf,int buf_len,const net::CompletionCallback & callback)40 int LocalFileStreamWriter::Write(net::IOBuffer* buf, int buf_len,
41                                  const net::CompletionCallback& callback) {
42   DCHECK(!has_pending_operation_);
43   DCHECK(cancel_callback_.is_null());
44 
45   has_pending_operation_ = true;
46   if (stream_impl_) {
47     int result = InitiateWrite(buf, buf_len, callback);
48     if (result != net::ERR_IO_PENDING)
49       has_pending_operation_ = false;
50     return result;
51   }
52   return InitiateOpen(callback,
53                       base::Bind(&LocalFileStreamWriter::ReadyToWrite,
54                                  weak_factory_.GetWeakPtr(),
55                                  make_scoped_refptr(buf), buf_len, callback));
56 }
57 
Cancel(const net::CompletionCallback & callback)58 int LocalFileStreamWriter::Cancel(const net::CompletionCallback& callback) {
59   if (!has_pending_operation_)
60     return net::ERR_UNEXPECTED;
61 
62   DCHECK(!callback.is_null());
63   cancel_callback_ = callback;
64   return net::ERR_IO_PENDING;
65 }
66 
Flush(const net::CompletionCallback & callback)67 int LocalFileStreamWriter::Flush(const net::CompletionCallback& callback) {
68   DCHECK(!has_pending_operation_);
69   DCHECK(cancel_callback_.is_null());
70 
71   // Write() is not called yet, so there's nothing to flush.
72   if (!stream_impl_)
73     return net::OK;
74 
75   has_pending_operation_ = true;
76   int result = InitiateFlush(callback);
77   if (result != net::ERR_IO_PENDING)
78     has_pending_operation_ = false;
79   return result;
80 }
81 
LocalFileStreamWriter(base::TaskRunner * task_runner,const base::FilePath & file_path,int64 initial_offset)82 LocalFileStreamWriter::LocalFileStreamWriter(base::TaskRunner* task_runner,
83                                              const base::FilePath& file_path,
84                                              int64 initial_offset)
85     : file_path_(file_path),
86       initial_offset_(initial_offset),
87       task_runner_(task_runner),
88       has_pending_operation_(false),
89       weak_factory_(this) {}
90 
InitiateOpen(const net::CompletionCallback & error_callback,const base::Closure & main_operation)91 int LocalFileStreamWriter::InitiateOpen(
92     const net::CompletionCallback& error_callback,
93     const base::Closure& main_operation) {
94   DCHECK(has_pending_operation_);
95   DCHECK(!stream_impl_.get());
96 
97   stream_impl_.reset(new net::FileStream(NULL, task_runner_));
98 
99   return stream_impl_->Open(file_path_,
100                             kOpenFlagsForWrite,
101                             base::Bind(&LocalFileStreamWriter::DidOpen,
102                                        weak_factory_.GetWeakPtr(),
103                                        error_callback,
104                                        main_operation));
105 }
106 
DidOpen(const net::CompletionCallback & error_callback,const base::Closure & main_operation,int result)107 void LocalFileStreamWriter::DidOpen(
108     const net::CompletionCallback& error_callback,
109     const base::Closure& main_operation,
110     int result) {
111   DCHECK(has_pending_operation_);
112   DCHECK(stream_impl_.get());
113 
114   if (CancelIfRequested())
115     return;
116 
117   if (result != net::OK) {
118     has_pending_operation_ = false;
119     stream_impl_.reset(NULL);
120     error_callback.Run(result);
121     return;
122   }
123 
124   InitiateSeek(error_callback, main_operation);
125 }
126 
InitiateSeek(const net::CompletionCallback & error_callback,const base::Closure & main_operation)127 void LocalFileStreamWriter::InitiateSeek(
128     const net::CompletionCallback& error_callback,
129     const base::Closure& main_operation) {
130   DCHECK(has_pending_operation_);
131   DCHECK(stream_impl_.get());
132 
133   if (initial_offset_ == 0) {
134     // No need to seek.
135     main_operation.Run();
136     return;
137   }
138 
139   int result = stream_impl_->Seek(net::FROM_BEGIN, initial_offset_,
140                                   base::Bind(&LocalFileStreamWriter::DidSeek,
141                                              weak_factory_.GetWeakPtr(),
142                                              error_callback,
143                                              main_operation));
144   if (result != net::ERR_IO_PENDING) {
145     has_pending_operation_ = false;
146     error_callback.Run(result);
147   }
148 }
149 
DidSeek(const net::CompletionCallback & error_callback,const base::Closure & main_operation,int64 result)150 void LocalFileStreamWriter::DidSeek(
151     const net::CompletionCallback& error_callback,
152     const base::Closure& main_operation,
153     int64 result) {
154   DCHECK(has_pending_operation_);
155 
156   if (CancelIfRequested())
157     return;
158 
159   if (result != initial_offset_) {
160     // TODO(kinaba) add a more specific error code.
161     result = net::ERR_FAILED;
162   }
163 
164   if (result < 0) {
165     has_pending_operation_ = false;
166     error_callback.Run(static_cast<int>(result));
167     return;
168   }
169 
170   main_operation.Run();
171 }
172 
ReadyToWrite(net::IOBuffer * buf,int buf_len,const net::CompletionCallback & callback)173 void LocalFileStreamWriter::ReadyToWrite(
174     net::IOBuffer* buf, int buf_len,
175     const net::CompletionCallback& callback) {
176   DCHECK(has_pending_operation_);
177 
178   int result = InitiateWrite(buf, buf_len, callback);
179   if (result != net::ERR_IO_PENDING) {
180     has_pending_operation_ = false;
181     callback.Run(result);
182   }
183 }
184 
InitiateWrite(net::IOBuffer * buf,int buf_len,const net::CompletionCallback & callback)185 int LocalFileStreamWriter::InitiateWrite(
186     net::IOBuffer* buf, int buf_len,
187     const net::CompletionCallback& callback) {
188   DCHECK(has_pending_operation_);
189   DCHECK(stream_impl_.get());
190 
191   return stream_impl_->Write(buf, buf_len,
192                              base::Bind(&LocalFileStreamWriter::DidWrite,
193                                         weak_factory_.GetWeakPtr(),
194                                         callback));
195 }
196 
DidWrite(const net::CompletionCallback & callback,int result)197 void LocalFileStreamWriter::DidWrite(const net::CompletionCallback& callback,
198                                      int result) {
199   DCHECK(has_pending_operation_);
200 
201   if (CancelIfRequested())
202     return;
203   has_pending_operation_ = false;
204   callback.Run(result);
205 }
206 
InitiateFlush(const net::CompletionCallback & callback)207 int LocalFileStreamWriter::InitiateFlush(
208     const net::CompletionCallback& callback) {
209   DCHECK(has_pending_operation_);
210   DCHECK(stream_impl_.get());
211 
212   return stream_impl_->Flush(base::Bind(&LocalFileStreamWriter::DidFlush,
213                                         weak_factory_.GetWeakPtr(),
214                                         callback));
215 }
216 
DidFlush(const net::CompletionCallback & callback,int result)217 void LocalFileStreamWriter::DidFlush(const net::CompletionCallback& callback,
218                                      int result) {
219   DCHECK(has_pending_operation_);
220 
221   if (CancelIfRequested())
222     return;
223   has_pending_operation_ = false;
224   callback.Run(result);
225 }
226 
CancelIfRequested()227 bool LocalFileStreamWriter::CancelIfRequested() {
228   DCHECK(has_pending_operation_);
229 
230   if (cancel_callback_.is_null())
231     return false;
232 
233   net::CompletionCallback pending_cancel = cancel_callback_;
234   has_pending_operation_ = false;
235   cancel_callback_.Reset();
236   pending_cancel.Run(net::OK);
237   return true;
238 }
239 
240 }  // namespace fileapi
241