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