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 LocalFileStreamReader::LocalFileStreamReader( 36 base::TaskRunner* task_runner, 37 const base::FilePath& file_path, 38 int64 initial_offset, 39 const base::Time& expected_modification_time) 40 : task_runner_(task_runner), 41 file_path_(file_path), 42 initial_offset_(initial_offset), 43 expected_modification_time_(expected_modification_time), 44 has_pending_open_(false), 45 weak_factory_(this) {} 46 47 LocalFileStreamReader::~LocalFileStreamReader() { 48 } 49 50 int LocalFileStreamReader::Read(net::IOBuffer* buf, int buf_len, 51 const net::CompletionCallback& callback) { 52 DCHECK(!has_pending_open_); 53 if (stream_impl_) 54 return stream_impl_->Read(buf, buf_len, callback); 55 return Open(base::Bind(&LocalFileStreamReader::DidOpenForRead, 56 weak_factory_.GetWeakPtr(), 57 make_scoped_refptr(buf), buf_len, callback)); 58 } 59 60 int64 LocalFileStreamReader::GetLength( 61 const net::Int64CompletionCallback& callback) { 62 const bool posted = base::FileUtilProxy::GetFileInfo( 63 task_runner_.get(), 64 file_path_, 65 base::Bind(&LocalFileStreamReader::DidGetFileInfoForGetLength, 66 weak_factory_.GetWeakPtr(), 67 callback)); 68 DCHECK(posted); 69 return net::ERR_IO_PENDING; 70 } 71 72 int LocalFileStreamReader::Open(const net::CompletionCallback& callback) { 73 DCHECK(!has_pending_open_); 74 DCHECK(!stream_impl_.get()); 75 has_pending_open_ = true; 76 77 // Call GetLength first to make it perform last-modified-time verification, 78 // and then call DidVerifyForOpen for do the rest. 79 return GetLength(base::Bind(&LocalFileStreamReader::DidVerifyForOpen, 80 weak_factory_.GetWeakPtr(), callback)); 81 } 82 83 void LocalFileStreamReader::DidVerifyForOpen( 84 const net::CompletionCallback& callback, 85 int64 get_length_result) { 86 if (get_length_result < 0) { 87 callback.Run(static_cast<int>(get_length_result)); 88 return; 89 } 90 91 stream_impl_.reset(new net::FileStream(NULL, task_runner_)); 92 const int result = stream_impl_->Open( 93 file_path_, kOpenFlagsForRead, 94 base::Bind(&LocalFileStreamReader::DidOpenFileStream, 95 weak_factory_.GetWeakPtr(), 96 callback)); 97 if (result != net::ERR_IO_PENDING) 98 callback.Run(result); 99 } 100 101 void LocalFileStreamReader::DidOpenFileStream( 102 const net::CompletionCallback& callback, 103 int result) { 104 if (result != net::OK) { 105 callback.Run(result); 106 return; 107 } 108 result = stream_impl_->Seek( 109 net::FROM_BEGIN, initial_offset_, 110 base::Bind(&LocalFileStreamReader::DidSeekFileStream, 111 weak_factory_.GetWeakPtr(), 112 callback)); 113 if (result != net::ERR_IO_PENDING) { 114 callback.Run(result); 115 } 116 } 117 118 void LocalFileStreamReader::DidSeekFileStream( 119 const net::CompletionCallback& callback, 120 int64 seek_result) { 121 if (seek_result < 0) { 122 callback.Run(static_cast<int>(seek_result)); 123 return; 124 } 125 if (seek_result != initial_offset_) { 126 callback.Run(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); 127 return; 128 } 129 callback.Run(net::OK); 130 } 131 132 void LocalFileStreamReader::DidOpenForRead( 133 net::IOBuffer* buf, 134 int buf_len, 135 const net::CompletionCallback& callback, 136 int open_result) { 137 DCHECK(has_pending_open_); 138 has_pending_open_ = false; 139 if (open_result != net::OK) { 140 stream_impl_.reset(); 141 callback.Run(open_result); 142 return; 143 } 144 DCHECK(stream_impl_.get()); 145 const int read_result = stream_impl_->Read(buf, buf_len, callback); 146 if (read_result != net::ERR_IO_PENDING) 147 callback.Run(read_result); 148 } 149 150 void LocalFileStreamReader::DidGetFileInfoForGetLength( 151 const net::Int64CompletionCallback& callback, 152 base::PlatformFileError error, 153 const base::PlatformFileInfo& file_info) { 154 if (file_info.is_directory) { 155 callback.Run(net::ERR_FILE_NOT_FOUND); 156 return; 157 } 158 if (error != base::PLATFORM_FILE_OK) { 159 callback.Run(net::PlatformFileErrorToNetError(error)); 160 return; 161 } 162 if (!VerifySnapshotTime(expected_modification_time_, file_info)) { 163 callback.Run(net::ERR_UPLOAD_FILE_CHANGED); 164 return; 165 } 166 callback.Run(file_info.size); 167 } 168 169 } // namespace webkit_blob 170