Chromium Code Reviews| Index: webkit/fileapi/file_system_file_util.cc |
| diff --git a/webkit/fileapi/file_system_file_util.cc b/webkit/fileapi/file_system_file_util.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..79531681a6b1b475b041cc9b40695e48cba43425 |
| --- /dev/null |
| +++ b/webkit/fileapi/file_system_file_util.cc |
| @@ -0,0 +1,253 @@ |
| +// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "webkit/fileapi/file_system_file_util.h" |
| + |
| +#include "base/file_util_proxy.h" |
| +#include "webkit/fileapi/file_system_file_util_proxy.h" |
| + |
| +// This also removes the destination directory if it's non-empty and all other |
| +// checks are passed (so that the copy/move correctly overwrites the |
| +// destination). |
| +// TODO(ericu): This isn't exactly what we want for FileSystem, but we can make |
| +// it fit with minimal changes. The call to Delete will have to be virtualized |
| +// somehow. Not sure about the other file_util calls; it will depend on whether |
| +// or not we obfuscate before calling in [if needed]. |
|
ericu
2011/03/03 01:05:11
This comment is somewhat obsolete. We will need t
Dai Mikurube (google.com)
2011/03/03 20:24:52
Agreed. I've rewritten the TODO. Could you check w
ericu
2011/03/03 21:27:48
Yes, that looks good. Thanks.
|
| +static base::PlatformFileError PerformCommonCheckAndPreparationForMoveAndCopy( |
| + const FilePath& src_file_path, |
| + const FilePath& dest_file_path) { |
| + // Exits earlier if the source path does not exist. |
| + if (!file_util::PathExists(src_file_path)) |
| + return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| + |
| + // The parent of the |dest_file_path| does not exist. |
| + if (!file_util::DirectoryExists(dest_file_path.DirName())) |
| + return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| + |
| + // It is an error to try to copy/move an entry into its child. |
| + if (src_file_path.IsParent(dest_file_path)) |
| + return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; |
| + |
| + // Now it is ok to return if the |dest_file_path| does not exist. |
| + if (!file_util::PathExists(dest_file_path)) |
| + return base::PLATFORM_FILE_OK; |
| + |
| + // |src_file_path| exists and is a directory. |
| + // |dest_file_path| exists and is a file. |
| + bool src_is_directory = file_util::DirectoryExists(src_file_path); |
| + bool dest_is_directory = file_util::DirectoryExists(dest_file_path); |
| + if (src_is_directory && !dest_is_directory) |
| + return base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY; |
| + |
| + // |src_file_path| exists and is a file. |
| + // |dest_file_path| exists and is a directory. |
| + if (!src_is_directory && dest_is_directory) |
| + return base::PLATFORM_FILE_ERROR_NOT_A_FILE; |
| + |
| + // It is an error to copy/move an entry into the same path. |
| + if (src_file_path.value() == dest_file_path.value()) |
| + return base::PLATFORM_FILE_ERROR_EXISTS; |
| + |
| + if (dest_is_directory) { |
| + // It is an error to copy/move an entry to a non-empty directory. |
| + // Otherwise the copy/move attempt must overwrite the destination, but |
| + // the file_util's Copy or Move method doesn't perform overwrite |
| + // on all platforms, so we delete the destination directory here. |
| + // TODO(kinuko): may be better to change the file_util::{Copy,Move}. |
| + if (!file_util::Delete(dest_file_path, false /* recursive */)) { |
| + if (!file_util::IsDirectoryEmpty(dest_file_path)) |
| + return base::PLATFORM_FILE_ERROR_NOT_EMPTY; |
| + return base::PLATFORM_FILE_ERROR_FAILED; |
| + } |
| + } |
| + return base::PLATFORM_FILE_OK; |
| +} |
| + |
| +namespace fileapi { |
| + |
| +FileSystemFileUtil* FileSystemFileUtil::GetInstance() { |
| + return Singleton<FileSystemFileUtil>::get(); |
| +} |
| + |
| + |
| +PlatformFileError FileSystemFileUtil::CreateOrOpen( |
| + FileSystemOperationContext* unused, |
| + const FilePath& file_path, int file_flags, |
| + PlatformFile* file_handle, bool* created) { |
| + if (!file_util::DirectoryExists(file_path.DirName())) { |
| + // If its parent does not exist, should return NOT_FOUND error. |
| + return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| + } |
| + PlatformFileError error_code = base::PLATFORM_FILE_OK; |
| + *file_handle = base::CreatePlatformFile(file_path, file_flags, |
| + created, &error_code); |
| + return error_code; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::Close( |
| + FileSystemOperationContext* unused, |
| + PlatformFile file_handle) { |
| + if (!base::ClosePlatformFile(file_handle)) |
| + return base::PLATFORM_FILE_ERROR_FAILED; |
| + return base::PLATFORM_FILE_OK; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::EnsureFileExists( |
| + FileSystemOperationContext* unused, |
| + const FilePath& file_path, |
| + bool* created) { |
| + if (!file_util::DirectoryExists(file_path.DirName())) |
| + // If its parent does not exist, should return NOT_FOUND error. |
| + return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| + PlatformFileError error_code = base::PLATFORM_FILE_OK; |
| + // Tries to create the |file_path| exclusively. This should fail |
| + // with base::PLATFORM_FILE_ERROR_EXISTS if the path already exists. |
| + PlatformFile handle = base::CreatePlatformFile( |
| + file_path, |
| + base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_READ, |
| + created, &error_code); |
| + if (error_code == base::PLATFORM_FILE_ERROR_EXISTS) { |
| + // Make sure created_ is false. |
| + *created = false; |
| + error_code = base::PLATFORM_FILE_OK; |
| + } |
| + if (handle != base::kInvalidPlatformFileValue) |
| + base::ClosePlatformFile(handle); |
| + return error_code; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::GetFileInfo( |
| + FileSystemOperationContext* unused, |
| + const FilePath& file_path, |
| + base::PlatformFileInfo* file_info) { |
| + if (!file_util::PathExists(file_path)) |
| + return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| + if (!file_util::GetFileInfo(file_path, file_info)) |
| + return base::PLATFORM_FILE_ERROR_FAILED; |
| + return base::PLATFORM_FILE_OK; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::ReadDirectory( |
| + FileSystemOperationContext* unused, |
| + const FilePath& file_path, |
| + std::vector<base::FileUtilProxy::Entry>* entries) { |
|
ericu
2011/03/03 01:05:11
In this method I mixed FileUtilProxy::Entry and Fi
Dai Mikurube (google.com)
2011/03/03 20:24:52
Agreed. Actually, I did the same and found that in
|
| + // TODO(kkanetkar): Implement directory read in multiple chunks. |
| + if (!file_util::DirectoryExists(file_path)) |
| + return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| + |
| + file_util::FileEnumerator file_enum( |
| + file_path, false, static_cast<file_util::FileEnumerator::FILE_TYPE>( |
| + file_util::FileEnumerator::FILES | |
| + file_util::FileEnumerator::DIRECTORIES)); |
| + FilePath current; |
| + while (!(current = file_enum.Next()).empty()) { |
| + fileapi::FileSystemFileUtilProxy::Entry entry; |
| + file_util::FileEnumerator::FindInfo info; |
| + file_enum.GetFindInfo(&info); |
| + entry.is_directory = file_enum.IsDirectory(info); |
| + // This will just give the entry's name instead of entire path |
| + // if we use current.value(). |
| + entry.name = file_util::FileEnumerator::GetFilename(info).value(); |
| + entries->push_back(entry); |
| + } |
| + return base::PLATFORM_FILE_OK; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::CreateDirectory( |
| + FileSystemOperationContext* unused, |
| + const FilePath& file_path, |
| + bool exclusive) { |
| + bool path_exists = file_util::PathExists(file_path); |
| + if (!file_util::PathExists(file_path.DirName())) |
| + return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| + // If parent dir of file doesn't exist. |
| + if (exclusive && path_exists) |
| + return base::PLATFORM_FILE_ERROR_EXISTS; |
| + // If file exists at the path. |
| + if (path_exists && !file_util::DirectoryExists(file_path)) |
| + return base::PLATFORM_FILE_ERROR_EXISTS; |
| + if (!file_util::CreateDirectory(file_path)) |
| + return base::PLATFORM_FILE_ERROR_FAILED; |
| + return base::PLATFORM_FILE_OK; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::Copy( |
| + FileSystemOperationContext* unused, |
| + const FilePath& src_file_path, |
| + const FilePath& dest_file_path) { |
| + PlatformFileError error_code; |
| + error_code = |
| + PerformCommonCheckAndPreparationForMoveAndCopy( |
| + src_file_path, dest_file_path); |
| + if (error_code != base::PLATFORM_FILE_OK) |
| + return error_code; |
| + if (!file_util::CopyDirectory(src_file_path, dest_file_path, |
| + true /* recursive */)) |
| + return base::PLATFORM_FILE_ERROR_FAILED; |
| + return base::PLATFORM_FILE_OK; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::Move( |
| + FileSystemOperationContext* unused, |
| + const FilePath& src_file_path, |
| + const FilePath& dest_file_path) { |
| + PlatformFileError error_code; |
| + error_code = |
| + PerformCommonCheckAndPreparationForMoveAndCopy( |
| + src_file_path, dest_file_path); |
| + if (error_code != base::PLATFORM_FILE_OK) |
| + return error_code; |
| + if (!file_util::Move(src_file_path, dest_file_path)) |
| + return base::PLATFORM_FILE_ERROR_FAILED; |
| + return base::PLATFORM_FILE_OK; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::Delete( |
| + FileSystemOperationContext* unused, |
| + const FilePath& file_path, |
| + bool recursive) { |
| + if (!file_util::PathExists(file_path)) { |
| + return base::PLATFORM_FILE_ERROR_NOT_FOUND; |
| + } |
| + if (!file_util::Delete(file_path, recursive)) { |
| + if (!recursive && !file_util::IsDirectoryEmpty(file_path)) { |
| + return base::PLATFORM_FILE_ERROR_NOT_EMPTY; |
| + } |
| + return base::PLATFORM_FILE_ERROR_FAILED; |
| + } |
| + return base::PLATFORM_FILE_OK; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::Touch( |
| + FileSystemOperationContext* unused, |
| + const FilePath& file_path, |
| + const base::Time& last_access_time, |
| + const base::Time& last_modified_time) { |
| + if (!file_util::TouchFile( |
| + file_path, last_access_time, last_modified_time)) |
| + return base::PLATFORM_FILE_ERROR_FAILED; |
| + return base::PLATFORM_FILE_OK; |
| +} |
| + |
| +PlatformFileError FileSystemFileUtil::Truncate( |
| + FileSystemOperationContext* unused, |
| + const FilePath& file_path, |
| + int64 length) { |
| + PlatformFileError error_code(base::PLATFORM_FILE_ERROR_FAILED); |
| + PlatformFile file = |
| + base::CreatePlatformFile( |
| + file_path, |
| + base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE, |
| + NULL, |
| + &error_code); |
| + if (error_code != base::PLATFORM_FILE_OK) { |
| + return error_code; |
| + } |
| + if (!base::TruncatePlatformFile(file, length)) |
| + error_code = base::PLATFORM_FILE_ERROR_FAILED; |
| + base::ClosePlatformFile(file); |
| + return error_code; |
| +} |
| + |
| +} // namespace fileapi |