| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 "base/files/file_proxy.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/bind_helpers.h" | |
| 9 #include "base/files/file.h" | |
| 10 #include "base/files/file_util.h" | |
| 11 #include "base/location.h" | |
| 12 #include "base/task_runner.h" | |
| 13 #include "base/task_runner_util.h" | |
| 14 | |
| 15 namespace { | |
| 16 | |
| 17 void FileDeleter(base::File file) { | |
| 18 } | |
| 19 | |
| 20 } // namespace | |
| 21 | |
| 22 namespace base { | |
| 23 | |
| 24 class FileHelper { | |
| 25 public: | |
| 26 FileHelper(FileProxy* proxy, File file) | |
| 27 : file_(file.Pass()), | |
| 28 error_(File::FILE_ERROR_FAILED), | |
| 29 task_runner_(proxy->task_runner()), | |
| 30 proxy_(AsWeakPtr(proxy)) { | |
| 31 } | |
| 32 | |
| 33 void PassFile() { | |
| 34 if (proxy_) | |
| 35 proxy_->SetFile(file_.Pass()); | |
| 36 else if (file_.IsValid()) | |
| 37 task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_))); | |
| 38 } | |
| 39 | |
| 40 protected: | |
| 41 File file_; | |
| 42 File::Error error_; | |
| 43 | |
| 44 private: | |
| 45 scoped_refptr<TaskRunner> task_runner_; | |
| 46 WeakPtr<FileProxy> proxy_; | |
| 47 DISALLOW_COPY_AND_ASSIGN(FileHelper); | |
| 48 }; | |
| 49 | |
| 50 namespace { | |
| 51 | |
| 52 class GenericFileHelper : public FileHelper { | |
| 53 public: | |
| 54 GenericFileHelper(FileProxy* proxy, File file) | |
| 55 : FileHelper(proxy, file.Pass()) { | |
| 56 } | |
| 57 | |
| 58 void Close() { | |
| 59 file_.Close(); | |
| 60 error_ = File::FILE_OK; | |
| 61 } | |
| 62 | |
| 63 void SetTimes(Time last_access_time, Time last_modified_time) { | |
| 64 bool rv = file_.SetTimes(last_access_time, last_modified_time); | |
| 65 error_ = rv ? File::FILE_OK : File::FILE_ERROR_FAILED; | |
| 66 } | |
| 67 | |
| 68 void SetLength(int64 length) { | |
| 69 if (file_.SetLength(length)) | |
| 70 error_ = File::FILE_OK; | |
| 71 } | |
| 72 | |
| 73 void Flush() { | |
| 74 if (file_.Flush()) | |
| 75 error_ = File::FILE_OK; | |
| 76 } | |
| 77 | |
| 78 void Reply(const FileProxy::StatusCallback& callback) { | |
| 79 PassFile(); | |
| 80 if (!callback.is_null()) | |
| 81 callback.Run(error_); | |
| 82 } | |
| 83 | |
| 84 private: | |
| 85 DISALLOW_COPY_AND_ASSIGN(GenericFileHelper); | |
| 86 }; | |
| 87 | |
| 88 class CreateOrOpenHelper : public FileHelper { | |
| 89 public: | |
| 90 CreateOrOpenHelper(FileProxy* proxy, File file) | |
| 91 : FileHelper(proxy, file.Pass()) { | |
| 92 } | |
| 93 | |
| 94 void RunWork(const FilePath& file_path, int file_flags) { | |
| 95 file_.Initialize(file_path, file_flags); | |
| 96 error_ = file_.IsValid() ? File::FILE_OK : file_.error_details(); | |
| 97 } | |
| 98 | |
| 99 void Reply(const FileProxy::StatusCallback& callback) { | |
| 100 DCHECK(!callback.is_null()); | |
| 101 PassFile(); | |
| 102 callback.Run(error_); | |
| 103 } | |
| 104 | |
| 105 private: | |
| 106 DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper); | |
| 107 }; | |
| 108 | |
| 109 class CreateTemporaryHelper : public FileHelper { | |
| 110 public: | |
| 111 CreateTemporaryHelper(FileProxy* proxy, File file) | |
| 112 : FileHelper(proxy, file.Pass()) { | |
| 113 } | |
| 114 | |
| 115 void RunWork(uint32 additional_file_flags) { | |
| 116 // TODO(darin): file_util should have a variant of CreateTemporaryFile | |
| 117 // that returns a FilePath and a File. | |
| 118 if (!CreateTemporaryFile(&file_path_)) { | |
| 119 // TODO(davidben): base::CreateTemporaryFile should preserve the error | |
| 120 // code. | |
| 121 error_ = File::FILE_ERROR_FAILED; | |
| 122 return; | |
| 123 } | |
| 124 | |
| 125 uint32 file_flags = File::FLAG_WRITE | | |
| 126 File::FLAG_TEMPORARY | | |
| 127 File::FLAG_CREATE_ALWAYS | | |
| 128 additional_file_flags; | |
| 129 | |
| 130 file_.Initialize(file_path_, file_flags); | |
| 131 if (file_.IsValid()) { | |
| 132 error_ = File::FILE_OK; | |
| 133 } else { | |
| 134 error_ = file_.error_details(); | |
| 135 DeleteFile(file_path_, false); | |
| 136 file_path_.clear(); | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 void Reply(const FileProxy::CreateTemporaryCallback& callback) { | |
| 141 DCHECK(!callback.is_null()); | |
| 142 PassFile(); | |
| 143 callback.Run(error_, file_path_); | |
| 144 } | |
| 145 | |
| 146 private: | |
| 147 FilePath file_path_; | |
| 148 DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper); | |
| 149 }; | |
| 150 | |
| 151 class GetInfoHelper : public FileHelper { | |
| 152 public: | |
| 153 GetInfoHelper(FileProxy* proxy, File file) | |
| 154 : FileHelper(proxy, file.Pass()) { | |
| 155 } | |
| 156 | |
| 157 void RunWork() { | |
| 158 if (file_.GetInfo(&file_info_)) | |
| 159 error_ = File::FILE_OK; | |
| 160 } | |
| 161 | |
| 162 void Reply(const FileProxy::GetFileInfoCallback& callback) { | |
| 163 PassFile(); | |
| 164 DCHECK(!callback.is_null()); | |
| 165 callback.Run(error_, file_info_); | |
| 166 } | |
| 167 | |
| 168 private: | |
| 169 File::Info file_info_; | |
| 170 DISALLOW_COPY_AND_ASSIGN(GetInfoHelper); | |
| 171 }; | |
| 172 | |
| 173 class ReadHelper : public FileHelper { | |
| 174 public: | |
| 175 ReadHelper(FileProxy* proxy, File file, int bytes_to_read) | |
| 176 : FileHelper(proxy, file.Pass()), | |
| 177 buffer_(new char[bytes_to_read]), | |
| 178 bytes_to_read_(bytes_to_read), | |
| 179 bytes_read_(0) { | |
| 180 } | |
| 181 | |
| 182 void RunWork(int64 offset) { | |
| 183 bytes_read_ = file_.Read(offset, buffer_.get(), bytes_to_read_); | |
| 184 error_ = (bytes_read_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK; | |
| 185 } | |
| 186 | |
| 187 void Reply(const FileProxy::ReadCallback& callback) { | |
| 188 PassFile(); | |
| 189 DCHECK(!callback.is_null()); | |
| 190 callback.Run(error_, buffer_.get(), bytes_read_); | |
| 191 } | |
| 192 | |
| 193 private: | |
| 194 scoped_ptr<char[]> buffer_; | |
| 195 int bytes_to_read_; | |
| 196 int bytes_read_; | |
| 197 DISALLOW_COPY_AND_ASSIGN(ReadHelper); | |
| 198 }; | |
| 199 | |
| 200 class WriteHelper : public FileHelper { | |
| 201 public: | |
| 202 WriteHelper(FileProxy* proxy, | |
| 203 File file, | |
| 204 const char* buffer, int bytes_to_write) | |
| 205 : FileHelper(proxy, file.Pass()), | |
| 206 buffer_(new char[bytes_to_write]), | |
| 207 bytes_to_write_(bytes_to_write), | |
| 208 bytes_written_(0) { | |
| 209 memcpy(buffer_.get(), buffer, bytes_to_write); | |
| 210 } | |
| 211 | |
| 212 void RunWork(int64 offset) { | |
| 213 bytes_written_ = file_.Write(offset, buffer_.get(), bytes_to_write_); | |
| 214 error_ = (bytes_written_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK; | |
| 215 } | |
| 216 | |
| 217 void Reply(const FileProxy::WriteCallback& callback) { | |
| 218 PassFile(); | |
| 219 if (!callback.is_null()) | |
| 220 callback.Run(error_, bytes_written_); | |
| 221 } | |
| 222 | |
| 223 private: | |
| 224 scoped_ptr<char[]> buffer_; | |
| 225 int bytes_to_write_; | |
| 226 int bytes_written_; | |
| 227 DISALLOW_COPY_AND_ASSIGN(WriteHelper); | |
| 228 }; | |
| 229 | |
| 230 } // namespace | |
| 231 | |
| 232 FileProxy::FileProxy(TaskRunner* task_runner) : task_runner_(task_runner) { | |
| 233 } | |
| 234 | |
| 235 FileProxy::~FileProxy() { | |
| 236 if (file_.IsValid()) | |
| 237 task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_))); | |
| 238 } | |
| 239 | |
| 240 bool FileProxy::CreateOrOpen(const FilePath& file_path, | |
| 241 uint32 file_flags, | |
| 242 const StatusCallback& callback) { | |
| 243 DCHECK(!file_.IsValid()); | |
| 244 CreateOrOpenHelper* helper = new CreateOrOpenHelper(this, File()); | |
| 245 return task_runner_->PostTaskAndReply( | |
| 246 FROM_HERE, | |
| 247 Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), file_path, | |
| 248 file_flags), | |
| 249 Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback)); | |
| 250 } | |
| 251 | |
| 252 bool FileProxy::CreateTemporary(uint32 additional_file_flags, | |
| 253 const CreateTemporaryCallback& callback) { | |
| 254 DCHECK(!file_.IsValid()); | |
| 255 CreateTemporaryHelper* helper = new CreateTemporaryHelper(this, File()); | |
| 256 return task_runner_->PostTaskAndReply( | |
| 257 FROM_HERE, | |
| 258 Bind(&CreateTemporaryHelper::RunWork, Unretained(helper), | |
| 259 additional_file_flags), | |
| 260 Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback)); | |
| 261 } | |
| 262 | |
| 263 bool FileProxy::IsValid() const { | |
| 264 return file_.IsValid(); | |
| 265 } | |
| 266 | |
| 267 void FileProxy::SetFile(File file) { | |
| 268 DCHECK(!file_.IsValid()); | |
| 269 file_ = file.Pass(); | |
| 270 } | |
| 271 | |
| 272 File FileProxy::TakeFile() { | |
| 273 return file_.Pass(); | |
| 274 } | |
| 275 | |
| 276 PlatformFile FileProxy::GetPlatformFile() const { | |
| 277 return file_.GetPlatformFile(); | |
| 278 } | |
| 279 | |
| 280 bool FileProxy::Close(const StatusCallback& callback) { | |
| 281 DCHECK(file_.IsValid()); | |
| 282 GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass()); | |
| 283 return task_runner_->PostTaskAndReply( | |
| 284 FROM_HERE, | |
| 285 Bind(&GenericFileHelper::Close, Unretained(helper)), | |
| 286 Bind(&GenericFileHelper::Reply, Owned(helper), callback)); | |
| 287 } | |
| 288 | |
| 289 bool FileProxy::GetInfo(const GetFileInfoCallback& callback) { | |
| 290 DCHECK(file_.IsValid()); | |
| 291 GetInfoHelper* helper = new GetInfoHelper(this, file_.Pass()); | |
| 292 return task_runner_->PostTaskAndReply( | |
| 293 FROM_HERE, | |
| 294 Bind(&GetInfoHelper::RunWork, Unretained(helper)), | |
| 295 Bind(&GetInfoHelper::Reply, Owned(helper), callback)); | |
| 296 } | |
| 297 | |
| 298 bool FileProxy::Read(int64 offset, | |
| 299 int bytes_to_read, | |
| 300 const ReadCallback& callback) { | |
| 301 DCHECK(file_.IsValid()); | |
| 302 if (bytes_to_read < 0) | |
| 303 return false; | |
| 304 | |
| 305 ReadHelper* helper = new ReadHelper(this, file_.Pass(), bytes_to_read); | |
| 306 return task_runner_->PostTaskAndReply( | |
| 307 FROM_HERE, | |
| 308 Bind(&ReadHelper::RunWork, Unretained(helper), offset), | |
| 309 Bind(&ReadHelper::Reply, Owned(helper), callback)); | |
| 310 } | |
| 311 | |
| 312 bool FileProxy::Write(int64 offset, | |
| 313 const char* buffer, | |
| 314 int bytes_to_write, | |
| 315 const WriteCallback& callback) { | |
| 316 DCHECK(file_.IsValid()); | |
| 317 if (bytes_to_write <= 0 || buffer == NULL) | |
| 318 return false; | |
| 319 | |
| 320 WriteHelper* helper = | |
| 321 new WriteHelper(this, file_.Pass(), buffer, bytes_to_write); | |
| 322 return task_runner_->PostTaskAndReply( | |
| 323 FROM_HERE, | |
| 324 Bind(&WriteHelper::RunWork, Unretained(helper), offset), | |
| 325 Bind(&WriteHelper::Reply, Owned(helper), callback)); | |
| 326 } | |
| 327 | |
| 328 bool FileProxy::SetTimes(Time last_access_time, | |
| 329 Time last_modified_time, | |
| 330 const StatusCallback& callback) { | |
| 331 DCHECK(file_.IsValid()); | |
| 332 GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass()); | |
| 333 return task_runner_->PostTaskAndReply( | |
| 334 FROM_HERE, | |
| 335 Bind(&GenericFileHelper::SetTimes, Unretained(helper), last_access_time, | |
| 336 last_modified_time), | |
| 337 Bind(&GenericFileHelper::Reply, Owned(helper), callback)); | |
| 338 } | |
| 339 | |
| 340 bool FileProxy::SetLength(int64 length, const StatusCallback& callback) { | |
| 341 DCHECK(file_.IsValid()); | |
| 342 GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass()); | |
| 343 return task_runner_->PostTaskAndReply( | |
| 344 FROM_HERE, | |
| 345 Bind(&GenericFileHelper::SetLength, Unretained(helper), length), | |
| 346 Bind(&GenericFileHelper::Reply, Owned(helper), callback)); | |
| 347 } | |
| 348 | |
| 349 bool FileProxy::Flush(const StatusCallback& callback) { | |
| 350 DCHECK(file_.IsValid()); | |
| 351 GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass()); | |
| 352 return task_runner_->PostTaskAndReply( | |
| 353 FROM_HERE, | |
| 354 Bind(&GenericFileHelper::Flush, Unretained(helper)), | |
| 355 Bind(&GenericFileHelper::Reply, Owned(helper), callback)); | |
| 356 } | |
| 357 | |
| 358 } // namespace base | |
| OLD | NEW |