- add sources.
[platform/framework/web/crosswalk.git] / src / webkit / browser / blob / local_file_stream_reader.cc
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/blob/local_file_stream_reader.h"
6
7 #include "base/file_util.h"
8 #include "base/files/file_util_proxy.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/platform_file.h"
12 #include "base/task_runner.h"
13 #include "net/base/file_stream.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/net_errors.h"
16
17 namespace webkit_blob {
18
19 namespace {
20
21 const int kOpenFlagsForRead = base::PLATFORM_FILE_OPEN |
22                               base::PLATFORM_FILE_READ |
23                               base::PLATFORM_FILE_ASYNC;
24
25 // Verify if the underlying file has not been modified.
26 bool VerifySnapshotTime(const base::Time& expected_modification_time,
27                         const base::PlatformFileInfo& file_info) {
28   return expected_modification_time.is_null() ||
29          expected_modification_time.ToTimeT() ==
30              file_info.last_modified.ToTimeT();
31 }
32
33 }  // namespace
34
35 FileStreamReader* FileStreamReader::CreateForLocalFile(
36     base::TaskRunner* task_runner,
37     const base::FilePath& file_path,
38     int64 initial_offset,
39     const base::Time& expected_modification_time) {
40   return new LocalFileStreamReader(task_runner, file_path, initial_offset,
41                                    expected_modification_time);
42 }
43
44 LocalFileStreamReader::~LocalFileStreamReader() {
45 }
46
47 int LocalFileStreamReader::Read(net::IOBuffer* buf, int buf_len,
48                           const net::CompletionCallback& callback) {
49   DCHECK(!has_pending_open_);
50   if (stream_impl_)
51     return stream_impl_->Read(buf, buf_len, callback);
52   return Open(base::Bind(&LocalFileStreamReader::DidOpenForRead,
53                          weak_factory_.GetWeakPtr(),
54                          make_scoped_refptr(buf), buf_len, callback));
55 }
56
57 int64 LocalFileStreamReader::GetLength(
58     const net::Int64CompletionCallback& callback) {
59   const bool posted = base::FileUtilProxy::GetFileInfo(
60       task_runner_.get(),
61       file_path_,
62       base::Bind(&LocalFileStreamReader::DidGetFileInfoForGetLength,
63                  weak_factory_.GetWeakPtr(),
64                  callback));
65   DCHECK(posted);
66   return net::ERR_IO_PENDING;
67 }
68
69 LocalFileStreamReader::LocalFileStreamReader(
70     base::TaskRunner* task_runner,
71     const base::FilePath& file_path,
72     int64 initial_offset,
73     const base::Time& expected_modification_time)
74     : task_runner_(task_runner),
75       file_path_(file_path),
76       initial_offset_(initial_offset),
77       expected_modification_time_(expected_modification_time),
78       has_pending_open_(false),
79       weak_factory_(this) {}
80
81 int LocalFileStreamReader::Open(const net::CompletionCallback& callback) {
82   DCHECK(!has_pending_open_);
83   DCHECK(!stream_impl_.get());
84   has_pending_open_ = true;
85
86   // Call GetLength first to make it perform last-modified-time verification,
87   // and then call DidVerifyForOpen for do the rest.
88   return GetLength(base::Bind(&LocalFileStreamReader::DidVerifyForOpen,
89                               weak_factory_.GetWeakPtr(), callback));
90 }
91
92 void LocalFileStreamReader::DidVerifyForOpen(
93     const net::CompletionCallback& callback,
94     int64 get_length_result) {
95   if (get_length_result < 0) {
96     callback.Run(static_cast<int>(get_length_result));
97     return;
98   }
99
100   stream_impl_.reset(new net::FileStream(NULL, task_runner_));
101   const int result = stream_impl_->Open(
102       file_path_, kOpenFlagsForRead,
103       base::Bind(&LocalFileStreamReader::DidOpenFileStream,
104                  weak_factory_.GetWeakPtr(),
105                  callback));
106   if (result != net::ERR_IO_PENDING)
107     callback.Run(result);
108 }
109
110 void LocalFileStreamReader::DidOpenFileStream(
111     const net::CompletionCallback& callback,
112     int result) {
113   if (result != net::OK) {
114     callback.Run(result);
115     return;
116   }
117   result = stream_impl_->Seek(
118       net::FROM_BEGIN, initial_offset_,
119       base::Bind(&LocalFileStreamReader::DidSeekFileStream,
120                  weak_factory_.GetWeakPtr(),
121                  callback));
122   if (result != net::ERR_IO_PENDING) {
123     callback.Run(result);
124   }
125 }
126
127 void LocalFileStreamReader::DidSeekFileStream(
128     const net::CompletionCallback& callback,
129     int64 seek_result) {
130   if (seek_result < 0) {
131     callback.Run(static_cast<int>(seek_result));
132     return;
133   }
134   if (seek_result != initial_offset_) {
135     callback.Run(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
136     return;
137   }
138   callback.Run(net::OK);
139 }
140
141 void LocalFileStreamReader::DidOpenForRead(
142     net::IOBuffer* buf,
143     int buf_len,
144     const net::CompletionCallback& callback,
145     int open_result) {
146   DCHECK(has_pending_open_);
147   has_pending_open_ = false;
148   if (open_result != net::OK) {
149     stream_impl_.reset();
150     callback.Run(open_result);
151     return;
152   }
153   DCHECK(stream_impl_.get());
154   const int read_result = stream_impl_->Read(buf, buf_len, callback);
155   if (read_result != net::ERR_IO_PENDING)
156     callback.Run(read_result);
157 }
158
159 void LocalFileStreamReader::DidGetFileInfoForGetLength(
160     const net::Int64CompletionCallback& callback,
161     base::PlatformFileError error,
162     const base::PlatformFileInfo& file_info) {
163   if (file_info.is_directory) {
164     callback.Run(net::ERR_FILE_NOT_FOUND);
165     return;
166   }
167   if (error != base::PLATFORM_FILE_OK) {
168     callback.Run(net::PlatformFileErrorToNetError(error));
169     return;
170   }
171   if (!VerifySnapshotTime(expected_modification_time_, file_info)) {
172     callback.Run(net::ERR_UPLOAD_FILE_CHANGED);
173     return;
174   }
175   callback.Run(file_info.size);
176 }
177
178 }  // namespace webkit_blob