blob: 3a51b603dfa0ee0f11273317bf7cab71cb917fcb [file] [log] [blame]
finnur@chromium.org899d4e02011-03-15 18:56:27 +09001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
dumi@chromium.orgc980e402010-08-21 07:42:50 +09002// 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/file_util_proxy.h"
6
dumi@chromium.orgc980e402010-08-21 07:42:50 +09007#include "base/message_loop_proxy.h"
8
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +09009// TODO(jianli): Move the code from anonymous namespace to base namespace so
10// that all of the base:: prefixes would be unnecessary.
dumi@chromium.orgc980e402010-08-21 07:42:50 +090011namespace {
12
kinuko@chromium.org1a078042010-10-07 17:35:09 +090013namespace {
14
15// Performs common checks for move and copy.
16// This also removes the destination directory if it's non-empty and all other
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +090017// checks are passed (so that the copy/move correctly overwrites the
18// destination).
kinuko@chromium.org1a078042010-10-07 17:35:09 +090019static base::PlatformFileError PerformCommonCheckAndPreparationForMoveAndCopy(
20 const FilePath& src_file_path,
21 const FilePath& dest_file_path) {
22 // Exits earlier if the source path does not exist.
23 if (!file_util::PathExists(src_file_path))
24 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
25
26 // The parent of the |dest_file_path| does not exist.
27 if (!file_util::DirectoryExists(dest_file_path.DirName()))
28 return base::PLATFORM_FILE_ERROR_NOT_FOUND;
29
30 // It is an error to try to copy/move an entry into its child.
31 if (src_file_path.IsParent(dest_file_path))
32 return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
33
34 // Now it is ok to return if the |dest_file_path| does not exist.
35 if (!file_util::PathExists(dest_file_path))
36 return base::PLATFORM_FILE_OK;
37
38 // |src_file_path| exists and is a directory.
39 // |dest_file_path| exists and is a file.
40 bool src_is_directory = file_util::DirectoryExists(src_file_path);
41 bool dest_is_directory = file_util::DirectoryExists(dest_file_path);
42 if (src_is_directory && !dest_is_directory)
43 return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
44
45 // |src_file_path| exists and is a file.
46 // |dest_file_path| exists and is a directory.
47 if (!src_is_directory && dest_is_directory)
48 return base::PLATFORM_FILE_ERROR_NOT_A_FILE;
49
50 // It is an error to copy/move an entry into the same path.
51 if (src_file_path.value() == dest_file_path.value())
52 return base::PLATFORM_FILE_ERROR_EXISTS;
53
54 if (dest_is_directory) {
55 // It is an error to copy/move an entry to a non-empty directory.
56 // Otherwise the copy/move attempt must overwrite the destination, but
57 // the file_util's Copy or Move method doesn't perform overwrite
58 // on all platforms, so we delete the destination directory here.
59 // TODO(kinuko): may be better to change the file_util::{Copy,Move}.
60 if (!file_util::Delete(dest_file_path, false /* recursive */)) {
61 if (!file_util::IsDirectoryEmpty(dest_file_path))
62 return base::PLATFORM_FILE_ERROR_NOT_EMPTY;
63 return base::PLATFORM_FILE_ERROR_FAILED;
64 }
65 }
66 return base::PLATFORM_FILE_OK;
67}
68
kkanetkar@chromium.org48710682010-11-03 05:36:52 +090069} // anonymous namespace
kinuko@chromium.org1a078042010-10-07 17:35:09 +090070
dumi@chromium.orgc980e402010-08-21 07:42:50 +090071class MessageLoopRelay
72 : public base::RefCountedThreadSafe<MessageLoopRelay> {
73 public:
74 MessageLoopRelay()
75 : origin_message_loop_proxy_(
nduca@chromium.orgba048612011-08-16 05:33:46 +090076 base::MessageLoopProxy::current()),
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +090077 error_code_(base::PLATFORM_FILE_OK) {
dumi@chromium.orgc980e402010-08-21 07:42:50 +090078 }
79
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +090080 bool Start(scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
dumi@chromium.orgc980e402010-08-21 07:42:50 +090081 const tracked_objects::Location& from_here) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +090082 return message_loop_proxy->PostTask(
dumi@chromium.orgc980e402010-08-21 07:42:50 +090083 from_here,
84 NewRunnableMethod(this, &MessageLoopRelay::ProcessOnTargetThread));
85 }
86
87 protected:
88 friend class base::RefCountedThreadSafe<MessageLoopRelay>;
89 virtual ~MessageLoopRelay() {}
90
91 // Called to perform work on the FILE thread.
92 virtual void RunWork() = 0;
93
94 // Called to notify the callback on the origin thread.
95 virtual void RunCallback() = 0;
96
dumi@chromium.org50f197d2010-09-01 04:30:27 +090097 void set_error_code(base::PlatformFileError error_code) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +090098 error_code_ = error_code;
99 }
100
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900101 base::PlatformFileError error_code() const {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900102 return error_code_;
103 }
104
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900105 private:
106 void ProcessOnTargetThread() {
107 RunWork();
108 origin_message_loop_proxy_->PostTask(
109 FROM_HERE,
110 NewRunnableMethod(this, &MessageLoopRelay::RunCallback));
111 }
112
113 scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_;
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900114 base::PlatformFileError error_code_;
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900115};
116
117class RelayCreateOrOpen : public MessageLoopRelay {
118 public:
119 RelayCreateOrOpen(
120 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
121 const FilePath& file_path,
122 int file_flags,
jhawkins@chromium.org3a6573d2011-10-18 03:40:30 +0900123 const base::FileUtilProxy::CreateOrOpenCallback& callback)
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900124 : message_loop_proxy_(message_loop_proxy),
125 file_path_(file_path),
126 file_flags_(file_flags),
127 callback_(callback),
128 file_handle_(base::kInvalidPlatformFileValue),
129 created_(false) {
jhawkins@chromium.org3a6573d2011-10-18 03:40:30 +0900130 DCHECK_EQ(false, callback.is_null());
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900131 }
132
133 protected:
134 virtual ~RelayCreateOrOpen() {
135 if (file_handle_ != base::kInvalidPlatformFileValue)
136 base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
137 }
138
139 virtual void RunWork() {
kinuko@chromium.orgaf334b22010-10-12 11:17:14 +0900140 if (!file_util::DirectoryExists(file_path_.DirName())) {
141 // If its parent does not exist, should return NOT_FOUND error.
142 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
143 return;
144 }
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900145 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
146 file_handle_ = base::CreatePlatformFile(file_path_, file_flags_,
147 &created_, &error_code);
148 set_error_code(error_code);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900149 }
150
151 virtual void RunCallback() {
jhawkins@chromium.org3a6573d2011-10-18 03:40:30 +0900152 callback_.Run(error_code(), base::PassPlatformFile(&file_handle_),
153 created_);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900154 }
155
156 private:
157 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
158 FilePath file_path_;
159 int file_flags_;
jhawkins@chromium.org3a6573d2011-10-18 03:40:30 +0900160 base::FileUtilProxy::CreateOrOpenCallback callback_;
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900161 base::PlatformFile file_handle_;
162 bool created_;
163};
164
165class RelayCreateTemporary : public MessageLoopRelay {
166 public:
167 RelayCreateTemporary(
168 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
noelutz@google.comf56dab22011-06-14 05:29:50 +0900169 int additional_file_flags,
jhawkins@chromium.orgd90c4f52011-10-18 04:29:29 +0900170 const base::FileUtilProxy::CreateTemporaryCallback& callback)
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900171 : message_loop_proxy_(message_loop_proxy),
noelutz@google.comf56dab22011-06-14 05:29:50 +0900172 additional_file_flags_(additional_file_flags),
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900173 callback_(callback),
174 file_handle_(base::kInvalidPlatformFileValue) {
jhawkins@chromium.orgd90c4f52011-10-18 04:29:29 +0900175 DCHECK_EQ(false, callback.is_null());
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900176 }
177
178 protected:
179 virtual ~RelayCreateTemporary() {
180 if (file_handle_ != base::kInvalidPlatformFileValue)
181 base::FileUtilProxy::Close(message_loop_proxy_, file_handle_, NULL);
182 }
183
184 virtual void RunWork() {
185 // TODO(darin): file_util should have a variant of CreateTemporaryFile
186 // that returns a FilePath and a PlatformFile.
187 file_util::CreateTemporaryFile(&file_path_);
188
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900189 int file_flags =
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900190 base::PLATFORM_FILE_WRITE |
noelutz@google.comf56dab22011-06-14 05:29:50 +0900191 base::PLATFORM_FILE_TEMPORARY |
192 base::PLATFORM_FILE_CREATE_ALWAYS |
193 additional_file_flags_;
194
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900195 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
196 file_handle_ = base::CreatePlatformFile(file_path_, file_flags,
197 NULL, &error_code);
198 set_error_code(error_code);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900199 }
200
201 virtual void RunCallback() {
jhawkins@chromium.orgd90c4f52011-10-18 04:29:29 +0900202 callback_.Run(error_code(), base::PassPlatformFile(&file_handle_),
203 file_path_);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900204 }
205
206 private:
207 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
noelutz@google.comf56dab22011-06-14 05:29:50 +0900208 int additional_file_flags_;
jhawkins@chromium.orgd90c4f52011-10-18 04:29:29 +0900209 base::FileUtilProxy::CreateTemporaryCallback callback_;
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900210 base::PlatformFile file_handle_;
211 FilePath file_path_;
212};
213
214class RelayWithStatusCallback : public MessageLoopRelay {
215 public:
216 explicit RelayWithStatusCallback(
217 base::FileUtilProxy::StatusCallback* callback)
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900218 : callback_(callback) {
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900219 // It is OK for callback to be NULL.
220 }
221
222 protected:
223 virtual void RunCallback() {
224 // The caller may not have been interested in the result.
225 if (callback_) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900226 callback_->Run(error_code());
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900227 delete callback_;
228 }
229 }
230
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900231 private:
232 base::FileUtilProxy::StatusCallback* callback_;
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900233};
234
235class RelayClose : public RelayWithStatusCallback {
236 public:
237 RelayClose(base::PlatformFile file_handle,
238 base::FileUtilProxy::StatusCallback* callback)
239 : RelayWithStatusCallback(callback),
240 file_handle_(file_handle) {
241 }
242
243 protected:
244 virtual void RunWork() {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900245 if (!base::ClosePlatformFile(file_handle_))
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900246 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900247 }
248
249 private:
250 base::PlatformFile file_handle_;
251};
252
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900253class RelayEnsureFileExists : public MessageLoopRelay {
254 public:
255 RelayEnsureFileExists(
256 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
257 const FilePath& file_path,
jhawkins@chromium.org70bffc12011-10-18 04:39:59 +0900258 const base::FileUtilProxy::EnsureFileExistsCallback& callback)
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900259 : message_loop_proxy_(message_loop_proxy),
260 file_path_(file_path),
261 callback_(callback),
262 created_(false) {
jhawkins@chromium.org70bffc12011-10-18 04:39:59 +0900263 DCHECK_EQ(false, callback.is_null());
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900264 }
265
266 protected:
267 virtual void RunWork() {
268 if (!file_util::DirectoryExists(file_path_.DirName())) {
269 // If its parent does not exist, should return NOT_FOUND error.
270 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
271 return;
272 }
273 base::PlatformFileError error_code = base::PLATFORM_FILE_OK;
274 // Tries to create the |file_path_| exclusively. This should fail
275 // with PLATFORM_FILE_ERROR_EXISTS if the path already exists.
276 base::PlatformFile handle = base::CreatePlatformFile(
277 file_path_,
278 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ,
279 &created_, &error_code);
280 if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) {
281 // Make sure created_ is false.
282 created_ = false;
283 error_code = base::PLATFORM_FILE_OK;
284 }
285 if (handle != base::kInvalidPlatformFileValue)
286 base::ClosePlatformFile(handle);
287 set_error_code(error_code);
288 }
289
290 virtual void RunCallback() {
jhawkins@chromium.org70bffc12011-10-18 04:39:59 +0900291 callback_.Run(error_code(), created_);
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900292 }
293
294 private:
295 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
296 FilePath file_path_;
jhawkins@chromium.org70bffc12011-10-18 04:39:59 +0900297 base::FileUtilProxy::EnsureFileExistsCallback callback_;
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900298 bool created_;
299};
300
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900301class RelayDelete : public RelayWithStatusCallback {
302 public:
303 RelayDelete(const FilePath& file_path,
304 bool recursive,
305 base::FileUtilProxy::StatusCallback* callback)
306 : RelayWithStatusCallback(callback),
307 file_path_(file_path),
308 recursive_(recursive) {
309 }
310
311 protected:
312 virtual void RunWork() {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900313 if (!file_util::PathExists(file_path_)) {
314 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
315 return;
316 }
317 if (!file_util::Delete(file_path_, recursive_)) {
318 if (!recursive_ && !file_util::IsDirectoryEmpty(file_path_)) {
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900319 set_error_code(base::PLATFORM_FILE_ERROR_NOT_EMPTY);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900320 return;
321 }
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900322 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900323 }
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900324 }
325
326 private:
327 FilePath file_path_;
328 bool recursive_;
329};
330
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900331class RelayCopy : public RelayWithStatusCallback {
332 public:
333 RelayCopy(const FilePath& src_file_path,
334 const FilePath& dest_file_path,
335 base::FileUtilProxy::StatusCallback* callback)
336 : RelayWithStatusCallback(callback),
337 src_file_path_(src_file_path),
338 dest_file_path_(dest_file_path) {
339 }
340
341 protected:
342 virtual void RunWork() {
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900343 set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy(
344 src_file_path_, dest_file_path_));
345 if (error_code() != base::PLATFORM_FILE_OK)
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900346 return;
kinuko@chromium.org31583c32010-10-07 06:44:35 +0900347 if (!file_util::CopyDirectory(src_file_path_, dest_file_path_,
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900348 true /* recursive */))
kinuko@chromium.org31583c32010-10-07 06:44:35 +0900349 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900350 }
351
352 private:
353 FilePath src_file_path_;
354 FilePath dest_file_path_;
355};
356
357class RelayMove : public RelayWithStatusCallback {
358 public:
359 RelayMove(const FilePath& src_file_path,
360 const FilePath& dest_file_path,
361 base::FileUtilProxy::StatusCallback* callback)
362 : RelayWithStatusCallback(callback),
363 src_file_path_(src_file_path),
364 dest_file_path_(dest_file_path) {
365 }
366
367 protected:
368 virtual void RunWork() {
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900369 set_error_code(PerformCommonCheckAndPreparationForMoveAndCopy(
370 src_file_path_, dest_file_path_));
371 if (error_code() != base::PLATFORM_FILE_OK)
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900372 return;
kinuko@chromium.org1a078042010-10-07 17:35:09 +0900373 if (!file_util::Move(src_file_path_, dest_file_path_))
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900374 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900375 }
376
377 private:
378 FilePath src_file_path_;
379 FilePath dest_file_path_;
380};
381
382class RelayCreateDirectory : public RelayWithStatusCallback {
383 public:
384 RelayCreateDirectory(
385 const FilePath& file_path,
386 bool exclusive,
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900387 bool recursive,
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900388 base::FileUtilProxy::StatusCallback* callback)
389 : RelayWithStatusCallback(callback),
390 file_path_(file_path),
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900391 exclusive_(exclusive),
392 recursive_(recursive) {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900393 }
394
395 protected:
396 virtual void RunWork() {
397 bool path_exists = file_util::PathExists(file_path_);
398 // If parent dir of file doesn't exist.
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900399 if (!recursive_ && !file_util::PathExists(file_path_.DirName())) {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900400 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
401 return;
402 }
403 if (exclusive_ && path_exists) {
404 set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
405 return;
406 }
407 // If file exists at the path.
408 if (path_exists && !file_util::DirectoryExists(file_path_)) {
409 set_error_code(base::PLATFORM_FILE_ERROR_EXISTS);
410 return;
411 }
412 if (!file_util::CreateDirectory(file_path_))
413 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
414 }
415
416 private:
417 FilePath file_path_;
418 bool exclusive_;
kinuko@chromium.orgc483d792010-09-08 09:50:41 +0900419 bool recursive_;
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900420};
421
422class RelayReadDirectory : public MessageLoopRelay {
423 public:
424 RelayReadDirectory(const FilePath& file_path,
425 base::FileUtilProxy::ReadDirectoryCallback* callback)
426 : callback_(callback), file_path_(file_path) {
427 DCHECK(callback);
428 }
429
430 protected:
431 virtual void RunWork() {
432 // TODO(kkanetkar): Implement directory read in multiple chunks.
433 if (!file_util::DirectoryExists(file_path_)) {
434 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
435 return;
436 }
437
438 file_util::FileEnumerator file_enum(
tfarina@chromium.orga3a4db72011-08-15 22:09:27 +0900439 file_path_, false, static_cast<file_util::FileEnumerator::FileType>(
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900440 file_util::FileEnumerator::FILES |
441 file_util::FileEnumerator::DIRECTORIES));
442 FilePath current;
443 while (!(current = file_enum.Next()).empty()) {
kkanetkar@chromium.org48710682010-11-03 05:36:52 +0900444 base::FileUtilProxy::Entry entry;
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900445 file_util::FileEnumerator::FindInfo info;
446 file_enum.GetFindInfo(&info);
kinuko@chromium.org83604d12010-09-03 07:28:49 +0900447 entry.is_directory = file_enum.IsDirectory(info);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900448 // This will just give the entry's name instead of entire path
449 // if we use current.value().
450 entry.name = file_util::FileEnumerator::GetFilename(info).value();
tzik@chromium.org09987c32011-07-19 14:03:03 +0900451 entry.size = file_util::FileEnumerator::GetFilesize(info);
452 entry.last_modified_time =
453 file_util::FileEnumerator::GetLastModifiedTime(info);
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900454 entries_.push_back(entry);
455 }
456 }
457
458 virtual void RunCallback() {
459 callback_->Run(error_code(), entries_);
460 delete callback_;
461 }
462
463 private:
464 base::FileUtilProxy::ReadDirectoryCallback* callback_;
465 FilePath file_path_;
kkanetkar@chromium.org48710682010-11-03 05:36:52 +0900466 std::vector<base::FileUtilProxy::Entry> entries_;
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900467};
468
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900469class RelayGetFileInfo : public MessageLoopRelay {
470 public:
471 RelayGetFileInfo(const FilePath& file_path,
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900472 const base::FileUtilProxy::GetFileInfoCallback& callback)
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900473 : callback_(callback),
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900474 file_path_(file_path) {
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900475 DCHECK_EQ(false, callback.is_null());
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900476 }
477
478 protected:
479 virtual void RunWork() {
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900480 if (!file_util::PathExists(file_path_)) {
481 set_error_code(base::PLATFORM_FILE_ERROR_NOT_FOUND);
482 return;
483 }
dumi@chromium.org50f197d2010-09-01 04:30:27 +0900484 if (!file_util::GetFileInfo(file_path_, &file_info_))
485 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900486 }
487
488 virtual void RunCallback() {
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900489 callback_.Run(error_code(), file_info_);
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900490 }
491
492 private:
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900493 base::FileUtilProxy::GetFileInfoCallback callback_;
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900494 FilePath file_path_;
dumi@chromium.org97ae2612010-09-03 11:28:37 +0900495 base::PlatformFileInfo file_info_;
jianli@chromium.org9ed1f9d2010-08-31 11:42:36 +0900496};
497
dumi@chromium.org23915982010-09-10 12:01:14 +0900498class RelayGetFileInfoFromPlatformFile : public MessageLoopRelay {
499 public:
500 RelayGetFileInfoFromPlatformFile(
501 base::PlatformFile file,
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900502 const base::FileUtilProxy::GetFileInfoCallback& callback)
dumi@chromium.org23915982010-09-10 12:01:14 +0900503 : callback_(callback),
504 file_(file) {
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900505 DCHECK_EQ(false, callback.is_null());
dumi@chromium.org23915982010-09-10 12:01:14 +0900506 }
507
508 protected:
509 virtual void RunWork() {
510 if (!base::GetPlatformFileInfo(file_, &file_info_))
511 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
512 }
513
514 virtual void RunCallback() {
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900515 callback_.Run(error_code(), file_info_);
dumi@chromium.org23915982010-09-10 12:01:14 +0900516 }
517
518 private:
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900519 base::FileUtilProxy::GetFileInfoCallback callback_;
dumi@chromium.org23915982010-09-10 12:01:14 +0900520 base::PlatformFile file_;
521 base::PlatformFileInfo file_info_;
522};
523
524class RelayRead : public MessageLoopRelay {
525 public:
526 RelayRead(base::PlatformFile file,
527 int64 offset,
dumi@chromium.org23915982010-09-10 12:01:14 +0900528 int bytes_to_read,
darin@chromium.org44a99732011-02-04 09:39:34 +0900529 base::FileUtilProxy::ReadCallback* callback)
dumi@chromium.org23915982010-09-10 12:01:14 +0900530 : file_(file),
531 offset_(offset),
darin@chromium.org44a99732011-02-04 09:39:34 +0900532 buffer_(new char[bytes_to_read]),
dumi@chromium.org23915982010-09-10 12:01:14 +0900533 bytes_to_read_(bytes_to_read),
534 callback_(callback),
535 bytes_read_(0) {
536 }
537
538 protected:
539 virtual void RunWork() {
darin@chromium.org44a99732011-02-04 09:39:34 +0900540 bytes_read_ = base::ReadPlatformFile(file_, offset_, buffer_.get(),
dumi@chromium.org23915982010-09-10 12:01:14 +0900541 bytes_to_read_);
542 if (bytes_read_ < 0)
543 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
544 }
545
546 virtual void RunCallback() {
547 if (callback_) {
darin@chromium.org44a99732011-02-04 09:39:34 +0900548 callback_->Run(error_code(), buffer_.get(), bytes_read_);
dumi@chromium.org23915982010-09-10 12:01:14 +0900549 delete callback_;
550 }
551 }
552
553 private:
554 base::PlatformFile file_;
555 int64 offset_;
darin@chromium.org44a99732011-02-04 09:39:34 +0900556 scoped_array<char> buffer_;
dumi@chromium.org23915982010-09-10 12:01:14 +0900557 int bytes_to_read_;
darin@chromium.org44a99732011-02-04 09:39:34 +0900558 base::FileUtilProxy::ReadCallback* callback_;
dumi@chromium.org23915982010-09-10 12:01:14 +0900559 int bytes_read_;
560};
561
562class RelayWrite : public MessageLoopRelay {
563 public:
564 RelayWrite(base::PlatformFile file,
ericu@google.com6a652222010-10-05 11:26:47 +0900565 int64 offset,
dumi@chromium.org23915982010-09-10 12:01:14 +0900566 const char* buffer,
567 int bytes_to_write,
darin@chromium.org44a99732011-02-04 09:39:34 +0900568 base::FileUtilProxy::WriteCallback* callback)
dumi@chromium.org23915982010-09-10 12:01:14 +0900569 : file_(file),
570 offset_(offset),
darin@chromium.org44a99732011-02-04 09:39:34 +0900571 buffer_(new char[bytes_to_write]),
dumi@chromium.org23915982010-09-10 12:01:14 +0900572 bytes_to_write_(bytes_to_write),
finnur@chromium.org899d4e02011-03-15 18:56:27 +0900573 callback_(callback),
574 bytes_written_(0) {
darin@chromium.org44a99732011-02-04 09:39:34 +0900575 memcpy(buffer_.get(), buffer, bytes_to_write);
dumi@chromium.org23915982010-09-10 12:01:14 +0900576 }
577
578 protected:
579 virtual void RunWork() {
darin@chromium.org44a99732011-02-04 09:39:34 +0900580 bytes_written_ = base::WritePlatformFile(file_, offset_, buffer_.get(),
dumi@chromium.org23915982010-09-10 12:01:14 +0900581 bytes_to_write_);
582 if (bytes_written_ < 0)
583 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
584 }
585
586 virtual void RunCallback() {
587 if (callback_) {
588 callback_->Run(error_code(), bytes_written_);
589 delete callback_;
590 }
591 }
592
593 private:
594 base::PlatformFile file_;
595 int64 offset_;
darin@chromium.org44a99732011-02-04 09:39:34 +0900596 scoped_array<char> buffer_;
dumi@chromium.org23915982010-09-10 12:01:14 +0900597 int bytes_to_write_;
darin@chromium.org44a99732011-02-04 09:39:34 +0900598 base::FileUtilProxy::WriteCallback* callback_;
dumi@chromium.org23915982010-09-10 12:01:14 +0900599 int bytes_written_;
600};
601
602class RelayTouch : public RelayWithStatusCallback {
603 public:
604 RelayTouch(base::PlatformFile file,
605 const base::Time& last_access_time,
606 const base::Time& last_modified_time,
607 base::FileUtilProxy::StatusCallback* callback)
608 : RelayWithStatusCallback(callback),
609 file_(file),
610 last_access_time_(last_access_time),
611 last_modified_time_(last_modified_time) {
612 }
613
614 protected:
615 virtual void RunWork() {
616 if (!base::TouchPlatformFile(file_, last_access_time_, last_modified_time_))
617 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
618 }
619
620 private:
621 base::PlatformFile file_;
622 base::Time last_access_time_;
623 base::Time last_modified_time_;
624};
625
dumi@chromium.org12c2e2b2010-09-24 10:09:32 +0900626class RelayTouchFilePath : public RelayWithStatusCallback {
627 public:
628 RelayTouchFilePath(const FilePath& file_path,
629 const base::Time& last_access_time,
630 const base::Time& last_modified_time,
631 base::FileUtilProxy::StatusCallback* callback)
632 : RelayWithStatusCallback(callback),
evan@chromium.orgd719ede2010-09-25 05:07:41 +0900633 file_path_(file_path),
dumi@chromium.org12c2e2b2010-09-24 10:09:32 +0900634 last_access_time_(last_access_time),
635 last_modified_time_(last_modified_time) {
636 }
637
638 protected:
639 virtual void RunWork() {
640 if (!file_util::TouchFile(
641 file_path_, last_access_time_, last_modified_time_))
642 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
643 }
644
645 private:
646 FilePath file_path_;
647 base::Time last_access_time_;
648 base::Time last_modified_time_;
649};
650
ericu@google.com6a652222010-10-05 11:26:47 +0900651class RelayTruncatePlatformFile : public RelayWithStatusCallback {
dumi@chromium.org23915982010-09-10 12:01:14 +0900652 public:
ericu@google.com6a652222010-10-05 11:26:47 +0900653 RelayTruncatePlatformFile(base::PlatformFile file,
654 int64 length,
655 base::FileUtilProxy::StatusCallback* callback)
dumi@chromium.org23915982010-09-10 12:01:14 +0900656 : RelayWithStatusCallback(callback),
657 file_(file),
658 length_(length) {
659 }
660
661 protected:
662 virtual void RunWork() {
663 if (!base::TruncatePlatformFile(file_, length_))
664 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
665 }
666
667 private:
668 base::PlatformFile file_;
669 int64 length_;
670};
671
ericu@google.com6a652222010-10-05 11:26:47 +0900672class RelayTruncate : public RelayWithStatusCallback {
673 public:
674 RelayTruncate(const FilePath& path,
675 int64 length,
676 base::FileUtilProxy::StatusCallback* callback)
677 : RelayWithStatusCallback(callback),
678 path_(path),
679 length_(length) {
680 }
681
682 protected:
683 virtual void RunWork() {
684 base::PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED);
685 base::PlatformFile file =
686 base::CreatePlatformFile(
687 path_,
688 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE,
689 NULL,
690 &error_code);
691 if (error_code != base::PLATFORM_FILE_OK) {
692 set_error_code(error_code);
693 return;
694 }
695 if (!base::TruncatePlatformFile(file, length_))
696 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
697 base::ClosePlatformFile(file);
698 }
699
700 private:
701 FilePath path_;
702 int64 length_;
703};
704
dumi@chromium.org23915982010-09-10 12:01:14 +0900705class RelayFlush : public RelayWithStatusCallback {
706 public:
707 RelayFlush(base::PlatformFile file,
708 base::FileUtilProxy::StatusCallback* callback)
709 : RelayWithStatusCallback(callback),
710 file_(file) {
711 }
712
713 protected:
714 virtual void RunWork() {
715 if (!base::FlushPlatformFile(file_))
716 set_error_code(base::PLATFORM_FILE_ERROR_FAILED);
717 }
718
719 private:
720 base::PlatformFile file_;
721};
722
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900723bool Start(const tracked_objects::Location& from_here,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900724 scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
725 scoped_refptr<MessageLoopRelay> relay) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900726 return relay->Start(message_loop_proxy, from_here);
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900727}
728
729} // namespace
730
731namespace base {
732
733// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900734bool FileUtilProxy::CreateOrOpen(
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900735 scoped_refptr<MessageLoopProxy> message_loop_proxy,
736 const FilePath& file_path, int file_flags,
jhawkins@chromium.org3a6573d2011-10-18 03:40:30 +0900737 const CreateOrOpenCallback& callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900738 return Start(FROM_HERE, message_loop_proxy, new RelayCreateOrOpen(
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900739 message_loop_proxy, file_path, file_flags, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900740}
741
742// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900743bool FileUtilProxy::CreateTemporary(
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900744 scoped_refptr<MessageLoopProxy> message_loop_proxy,
noelutz@google.comf56dab22011-06-14 05:29:50 +0900745 int additional_file_flags,
jhawkins@chromium.orgd90c4f52011-10-18 04:29:29 +0900746 const CreateTemporaryCallback& callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900747 return Start(FROM_HERE, message_loop_proxy,
noelutz@google.comf56dab22011-06-14 05:29:50 +0900748 new RelayCreateTemporary(message_loop_proxy,
749 additional_file_flags,
750 callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900751}
752
753// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900754bool FileUtilProxy::Close(scoped_refptr<MessageLoopProxy> message_loop_proxy,
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900755 base::PlatformFile file_handle,
756 StatusCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900757 return Start(FROM_HERE, message_loop_proxy,
758 new RelayClose(file_handle, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900759}
760
761// static
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900762bool FileUtilProxy::EnsureFileExists(
763 scoped_refptr<MessageLoopProxy> message_loop_proxy,
764 const FilePath& file_path,
jhawkins@chromium.org70bffc12011-10-18 04:39:59 +0900765 const EnsureFileExistsCallback& callback) {
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900766 return Start(FROM_HERE, message_loop_proxy, new RelayEnsureFileExists(
767 message_loop_proxy, file_path, callback));
768}
769
erg@google.com37c078e2011-01-11 09:50:59 +0900770// Retrieves the information about a file. It is invalid to pass NULL for the
771// callback.
772bool FileUtilProxy::GetFileInfo(
773 scoped_refptr<MessageLoopProxy> message_loop_proxy,
774 const FilePath& file_path,
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900775 const GetFileInfoCallback& callback) {
erg@google.com37c078e2011-01-11 09:50:59 +0900776 return Start(FROM_HERE, message_loop_proxy, new RelayGetFileInfo(
777 file_path, callback));
778}
779
kinuko@chromium.org850eb6d2010-10-15 09:37:34 +0900780// static
erg@google.com37c078e2011-01-11 09:50:59 +0900781bool FileUtilProxy::GetFileInfoFromPlatformFile(
782 scoped_refptr<MessageLoopProxy> message_loop_proxy,
783 PlatformFile file,
jhawkins@chromium.org56771f02011-10-18 05:12:05 +0900784 const GetFileInfoCallback& callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900785 return Start(FROM_HERE, message_loop_proxy,
erg@google.com37c078e2011-01-11 09:50:59 +0900786 new RelayGetFileInfoFromPlatformFile(file, callback));
787}
788
789// static
790bool FileUtilProxy::ReadDirectory(
791 scoped_refptr<MessageLoopProxy> message_loop_proxy,
792 const FilePath& file_path,
793 ReadDirectoryCallback* callback) {
794 return Start(FROM_HERE, message_loop_proxy, new RelayReadDirectory(
795 file_path, callback));
796}
797
798// static
799bool FileUtilProxy::CreateDirectory(
800 scoped_refptr<MessageLoopProxy> message_loop_proxy,
801 const FilePath& file_path,
802 bool exclusive,
803 bool recursive,
804 StatusCallback* callback) {
805 return Start(FROM_HERE, message_loop_proxy, new RelayCreateDirectory(
806 file_path, exclusive, recursive, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900807}
808
809// static
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900810bool FileUtilProxy::Copy(scoped_refptr<MessageLoopProxy> message_loop_proxy,
811 const FilePath& src_file_path,
812 const FilePath& dest_file_path,
813 StatusCallback* callback) {
814 return Start(FROM_HERE, message_loop_proxy,
815 new RelayCopy(src_file_path, dest_file_path, callback));
816}
817
818// static
819bool FileUtilProxy::Move(scoped_refptr<MessageLoopProxy> message_loop_proxy,
820 const FilePath& src_file_path,
821 const FilePath& dest_file_path,
822 StatusCallback* callback) {
823 return Start(FROM_HERE, message_loop_proxy,
824 new RelayMove(src_file_path, dest_file_path, callback));
825}
826
827// static
erg@google.com37c078e2011-01-11 09:50:59 +0900828bool FileUtilProxy::Delete(scoped_refptr<MessageLoopProxy> message_loop_proxy,
829 const FilePath& file_path,
830 bool recursive,
831 StatusCallback* callback) {
832 return Start(FROM_HERE, message_loop_proxy,
833 new RelayDelete(file_path, recursive, callback));
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900834}
835
836// static
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900837bool FileUtilProxy::RecursiveDelete(
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900838 scoped_refptr<MessageLoopProxy> message_loop_proxy,
839 const FilePath& file_path,
840 StatusCallback* callback) {
dumi@chromium.org6dedd6d2010-08-25 05:26:23 +0900841 return Start(FROM_HERE, message_loop_proxy,
842 new RelayDelete(file_path, true, callback));
dumi@chromium.orgc980e402010-08-21 07:42:50 +0900843}
844
dumi@chromium.org23915982010-09-10 12:01:14 +0900845// static
dumi@chromium.org23915982010-09-10 12:01:14 +0900846bool FileUtilProxy::Read(
847 scoped_refptr<MessageLoopProxy> message_loop_proxy,
848 PlatformFile file,
849 int64 offset,
dumi@chromium.org23915982010-09-10 12:01:14 +0900850 int bytes_to_read,
darin@chromium.org44a99732011-02-04 09:39:34 +0900851 ReadCallback* callback) {
kinuko@chromium.org6e168d32011-08-19 19:14:27 +0900852 if (bytes_to_read < 0) {
853 delete callback;
sanga@chromium.orgf5cff132011-08-18 01:16:27 +0900854 return false;
kinuko@chromium.org6e168d32011-08-19 19:14:27 +0900855 }
dumi@chromium.org23915982010-09-10 12:01:14 +0900856 return Start(FROM_HERE, message_loop_proxy,
darin@chromium.org44a99732011-02-04 09:39:34 +0900857 new RelayRead(file, offset, bytes_to_read, callback));
dumi@chromium.org23915982010-09-10 12:01:14 +0900858}
859
860// static
861bool FileUtilProxy::Write(
862 scoped_refptr<MessageLoopProxy> message_loop_proxy,
863 PlatformFile file,
864 int64 offset,
865 const char* buffer,
866 int bytes_to_write,
darin@chromium.org44a99732011-02-04 09:39:34 +0900867 WriteCallback* callback) {
kinuko@chromium.org6e168d32011-08-19 19:14:27 +0900868 if (bytes_to_write <= 0) {
869 delete callback;
sanga@chromium.org21d251f2011-08-18 01:45:48 +0900870 return false;
kinuko@chromium.org6e168d32011-08-19 19:14:27 +0900871 }
dumi@chromium.org23915982010-09-10 12:01:14 +0900872 return Start(FROM_HERE, message_loop_proxy,
873 new RelayWrite(file, offset, buffer, bytes_to_write, callback));
874}
875
876// static
877bool FileUtilProxy::Touch(
878 scoped_refptr<MessageLoopProxy> message_loop_proxy,
879 PlatformFile file,
880 const base::Time& last_access_time,
881 const base::Time& last_modified_time,
882 StatusCallback* callback) {
883 return Start(FROM_HERE, message_loop_proxy,
884 new RelayTouch(file, last_access_time, last_modified_time,
885 callback));
886}
887
888// static
dumi@chromium.org12c2e2b2010-09-24 10:09:32 +0900889bool FileUtilProxy::Touch(
890 scoped_refptr<MessageLoopProxy> message_loop_proxy,
891 const FilePath& file_path,
892 const base::Time& last_access_time,
893 const base::Time& last_modified_time,
894 StatusCallback* callback) {
895 return Start(FROM_HERE, message_loop_proxy,
896 new RelayTouchFilePath(file_path, last_access_time,
897 last_modified_time, callback));
898}
899
900// static
dumi@chromium.org23915982010-09-10 12:01:14 +0900901bool FileUtilProxy::Truncate(
902 scoped_refptr<MessageLoopProxy> message_loop_proxy,
903 PlatformFile file,
ericu@google.com6a652222010-10-05 11:26:47 +0900904 int64 length,
dumi@chromium.org23915982010-09-10 12:01:14 +0900905 StatusCallback* callback) {
906 return Start(FROM_HERE, message_loop_proxy,
ericu@google.com6a652222010-10-05 11:26:47 +0900907 new RelayTruncatePlatformFile(file, length, callback));
908}
909
910// static
911bool FileUtilProxy::Truncate(
912 scoped_refptr<MessageLoopProxy> message_loop_proxy,
913 const FilePath& path,
914 int64 length,
915 StatusCallback* callback) {
916 return Start(FROM_HERE, message_loop_proxy,
917 new RelayTruncate(path, length, callback));
dumi@chromium.org23915982010-09-10 12:01:14 +0900918}
919
920// static
921bool FileUtilProxy::Flush(
922 scoped_refptr<MessageLoopProxy> message_loop_proxy,
923 PlatformFile file,
924 StatusCallback* callback) {
925 return Start(FROM_HERE, message_loop_proxy, new RelayFlush(file, callback));
926}
927
kkanetkar@chromium.org3a3bdea2010-09-02 12:43:36 +0900928} // namespace base