| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/drive/local_file_reader.h" | 5 #include "chrome/browser/chromeos/drive/local_file_reader.h" |
| 6 | 6 |
| 7 #include <errno.h> | |
| 8 | |
| 9 #include "base/bind.h" | 7 #include "base/bind.h" |
| 10 #include "base/bind_helpers.h" | |
| 11 #include "base/files/file_path.h" | 8 #include "base/files/file_path.h" |
| 12 #include "base/location.h" | |
| 13 #include "base/platform_file.h" | |
| 14 #include "base/sequenced_task_runner.h" | 9 #include "base/sequenced_task_runner.h" |
| 15 #include "base/task_runner_util.h" | |
| 16 #include "net/base/completion_callback.h" | 10 #include "net/base/completion_callback.h" |
| 17 #include "net/base/io_buffer.h" | 11 #include "net/base/io_buffer.h" |
| 18 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
| 19 | 13 |
| 20 namespace drive { | 14 namespace drive { |
| 21 namespace util { | 15 namespace util { |
| 22 | 16 |
| 23 namespace { | |
| 24 | |
| 25 // Opens the file at |file_path| and seeks to the |offset| from begin. | |
| 26 // Returns the net::Error code. If succeeded, |platform_file| is set to point | |
| 27 // the opened file. | |
| 28 // This function should run on the blocking pool. | |
| 29 int OpenAndSeekOnBlockingPool(const base::FilePath& file_path, | |
| 30 int64 offset, | |
| 31 base::PlatformFile* platform_file) { | |
| 32 DCHECK(platform_file); | |
| 33 DCHECK_EQ(base::kInvalidPlatformFileValue, *platform_file); | |
| 34 | |
| 35 // First of all, open the file. | |
| 36 const int open_flags = base::PLATFORM_FILE_OPEN | | |
| 37 base::PLATFORM_FILE_READ | | |
| 38 base::PLATFORM_FILE_ASYNC; | |
| 39 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; | |
| 40 base::PlatformFile file = | |
| 41 base::CreatePlatformFile(file_path, open_flags, NULL, &error); | |
| 42 if (file == base::kInvalidPlatformFileValue) { | |
| 43 DCHECK_NE(base::PLATFORM_FILE_OK, error); | |
| 44 return net::FileErrorToNetError(static_cast<base::File::Error>(error)); | |
| 45 } | |
| 46 | |
| 47 // If succeeded, seek to the |offset| from begin. | |
| 48 int64 position = base::SeekPlatformFile( | |
| 49 file, base::PLATFORM_FILE_FROM_BEGIN, offset); | |
| 50 if (position < 0) { | |
| 51 // If failed, close the file and return an error. | |
| 52 base::ClosePlatformFile(file); | |
| 53 return net::ERR_FAILED; | |
| 54 } | |
| 55 | |
| 56 *platform_file = file; | |
| 57 return net::OK; | |
| 58 } | |
| 59 | |
| 60 // Reads the data from the |platform_file| and copies it to the |buffer| at | |
| 61 // most |buffer_length| size. Returns the number of copied bytes if succeeded, | |
| 62 // or the net::Error code. | |
| 63 // This function should run on the blocking pool. | |
| 64 int ReadOnBlockingPool(base::PlatformFile platform_file, | |
| 65 scoped_refptr<net::IOBuffer> buffer, | |
| 66 int buffer_length) { | |
| 67 DCHECK_NE(base::kInvalidPlatformFileValue, platform_file); | |
| 68 int result = base::ReadPlatformFileCurPosNoBestEffort( | |
| 69 platform_file, buffer->data(), buffer_length); | |
| 70 return result < 0 ? net::MapSystemError(errno) : result; | |
| 71 } | |
| 72 | |
| 73 // Posts a task to close the |platform_file| into |task_runner|. | |
| 74 // Or, if |platform_file| is kInvalidPlatformFileValue, does nothing. | |
| 75 void PostCloseIfNeeded(base::TaskRunner* task_runner, | |
| 76 base::PlatformFile platform_file) { | |
| 77 DCHECK(task_runner); | |
| 78 if (platform_file != base::kInvalidPlatformFileValue) { | |
| 79 task_runner->PostTask( | |
| 80 FROM_HERE, | |
| 81 base::Bind( | |
| 82 base::IgnoreResult(&base::ClosePlatformFile), platform_file)); | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 } // namespace | |
| 87 | |
| 88 class LocalFileReader::ScopedPlatformFile { | |
| 89 public: | |
| 90 explicit ScopedPlatformFile(base::TaskRunner* task_runner) | |
| 91 : task_runner_(task_runner), | |
| 92 platform_file_(base::kInvalidPlatformFileValue) { | |
| 93 DCHECK(task_runner); | |
| 94 } | |
| 95 | |
| 96 ~ScopedPlatformFile() { | |
| 97 PostCloseIfNeeded(task_runner_.get(), platform_file_); | |
| 98 } | |
| 99 | |
| 100 base::PlatformFile* ptr() { return &platform_file_; } | |
| 101 | |
| 102 base::PlatformFile release() { | |
| 103 base::PlatformFile result = platform_file_; | |
| 104 platform_file_ = base::kInvalidPlatformFileValue; | |
| 105 return result; | |
| 106 } | |
| 107 | |
| 108 private: | |
| 109 scoped_refptr<base::TaskRunner> task_runner_; | |
| 110 base::PlatformFile platform_file_; | |
| 111 | |
| 112 DISALLOW_COPY_AND_ASSIGN(ScopedPlatformFile); | |
| 113 }; | |
| 114 | |
| 115 LocalFileReader::LocalFileReader( | 17 LocalFileReader::LocalFileReader( |
| 116 base::SequencedTaskRunner* sequenced_task_runner) | 18 base::SequencedTaskRunner* sequenced_task_runner) |
| 117 : sequenced_task_runner_(sequenced_task_runner), | 19 : file_stream_(NULL, sequenced_task_runner), |
| 118 platform_file_(base::kInvalidPlatformFileValue), | |
| 119 weak_ptr_factory_(this) { | 20 weak_ptr_factory_(this) { |
| 120 DCHECK(sequenced_task_runner_.get()); | |
| 121 } | 21 } |
| 122 | 22 |
| 123 LocalFileReader::~LocalFileReader() { | 23 LocalFileReader::~LocalFileReader() { |
| 124 PostCloseIfNeeded(sequenced_task_runner_.get(), platform_file_); | |
| 125 } | 24 } |
| 126 | 25 |
| 127 void LocalFileReader::Open(const base::FilePath& file_path, | 26 void LocalFileReader::Open(const base::FilePath& file_path, |
| 128 int64 offset, | 27 int64 offset, |
| 129 const net::CompletionCallback& callback) { | 28 const net::CompletionCallback& callback) { |
| 130 DCHECK(!callback.is_null()); | 29 DCHECK(!callback.is_null()); |
| 131 DCHECK_EQ(base::kInvalidPlatformFileValue, platform_file_); | 30 int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | |
| 31 base::PLATFORM_FILE_ASYNC; |
| 132 | 32 |
| 133 ScopedPlatformFile* platform_file = | 33 int rv = file_stream_.Open(file_path, flags, |
| 134 new ScopedPlatformFile(sequenced_task_runner_.get()); | 34 Bind(&LocalFileReader::DidOpen, |
| 135 base::PostTaskAndReplyWithResult( | 35 weak_ptr_factory_.GetWeakPtr(), |
| 136 sequenced_task_runner_.get(), | 36 callback, offset)); |
| 137 FROM_HERE, | 37 DCHECK_EQ(rv, net::ERR_IO_PENDING); |
| 138 base::Bind( | |
| 139 &OpenAndSeekOnBlockingPool, file_path, offset, platform_file->ptr()), | |
| 140 base::Bind(&LocalFileReader::OpenAfterBlockingPoolTask, | |
| 141 weak_ptr_factory_.GetWeakPtr(), | |
| 142 callback, | |
| 143 base::Owned(platform_file))); | |
| 144 } | 38 } |
| 145 | 39 |
| 146 void LocalFileReader::Read(net::IOBuffer* in_buffer, | 40 void LocalFileReader::Read(net::IOBuffer* in_buffer, |
| 147 int buffer_length, | 41 int buffer_length, |
| 148 const net::CompletionCallback& callback) { | 42 const net::CompletionCallback& callback) { |
| 149 DCHECK(!callback.is_null()); | 43 DCHECK(!callback.is_null()); |
| 150 DCHECK_NE(base::kInvalidPlatformFileValue, platform_file_); | 44 DCHECK(file_stream_.IsOpen()); |
| 151 | 45 int rv = file_stream_.Read(in_buffer, buffer_length, callback); |
| 152 scoped_refptr<net::IOBuffer> buffer(in_buffer); | 46 DCHECK_EQ(rv, net::ERR_IO_PENDING); |
| 153 base::PostTaskAndReplyWithResult( | |
| 154 sequenced_task_runner_.get(), | |
| 155 FROM_HERE, | |
| 156 base::Bind(&ReadOnBlockingPool, platform_file_, buffer, buffer_length), | |
| 157 callback); | |
| 158 } | 47 } |
| 159 | 48 |
| 160 void LocalFileReader::OpenAfterBlockingPoolTask( | 49 void LocalFileReader::DidOpen(const net::CompletionCallback& callback, |
| 161 const net::CompletionCallback& callback, | 50 int64 offset, |
| 162 ScopedPlatformFile* platform_file, | 51 int error) { |
| 163 int open_result) { | 52 if (error != net::OK) |
| 164 DCHECK(!callback.is_null()); | 53 return callback.Run(error); |
| 165 DCHECK(platform_file); | |
| 166 DCHECK_EQ(base::kInvalidPlatformFileValue, platform_file_); | |
| 167 | 54 |
| 168 if (open_result == net::OK) { | 55 int rv = file_stream_.Seek(net::FROM_BEGIN, offset, |
| 169 DCHECK_NE(base::kInvalidPlatformFileValue, *platform_file->ptr()); | 56 Bind(&LocalFileReader::DidSeek, |
| 170 platform_file_ = platform_file->release(); | 57 weak_ptr_factory_.GetWeakPtr(), |
| 171 } | 58 callback, offset)); |
| 59 DCHECK_EQ(rv, net::ERR_IO_PENDING); |
| 60 } |
| 172 | 61 |
| 173 callback.Run(open_result); | 62 void LocalFileReader::DidSeek(const net::CompletionCallback& callback, |
| 63 int64 offset, |
| 64 int64 error) { |
| 65 callback.Run(error == offset ? net::OK : net::ERR_FAILED); |
| 174 } | 66 } |
| 175 | 67 |
| 176 } // namespace util | 68 } // namespace util |
| 177 } // namespace drive | 69 } // namespace drive |
| OLD | NEW |