diff options
author | ericu@chromium.org <ericu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-20 21:02:35 +0000 |
---|---|---|
committer | ericu@chromium.org <ericu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-20 21:02:35 +0000 |
commit | 6b931158eff95b7969107824049fcf786325f0a7 (patch) | |
tree | 3a49d28cc7f222b4221f93218d221302eb3e64d2 | |
parent | 798dce5e549ff3a9f71f6903eb65f773782310d5 (diff) | |
download | chromium_src-6b931158eff95b7969107824049fcf786325f0a7.zip chromium_src-6b931158eff95b7969107824049fcf786325f0a7.tar.gz chromium_src-6b931158eff95b7969107824049fcf786325f0a7.tar.bz2 |
Code to migrate a single directory from the old sandbox to the new.
Also cleans up the new directory path format just a bit, and makes the database store relative paths instead of absolute ones, so that if the user moves her profile path, things don't break.
BUG=none
TEST=unit test
Review URL: http://codereview.chromium.org/7042029
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@86145 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | webkit/fileapi/file_system_directory_database.cc | 16 | ||||
-rw-r--r-- | webkit/fileapi/file_system_directory_database.h | 2 | ||||
-rw-r--r-- | webkit/fileapi/file_system_origin_database.cc | 4 | ||||
-rw-r--r-- | webkit/fileapi/obfuscated_file_system_file_util.cc | 208 | ||||
-rw-r--r-- | webkit/fileapi/obfuscated_file_system_file_util.h | 44 | ||||
-rw-r--r-- | webkit/fileapi/obfuscated_file_system_file_util_unittest.cc | 98 |
6 files changed, 329 insertions, 43 deletions
diff --git a/webkit/fileapi/file_system_directory_database.cc b/webkit/fileapi/file_system_directory_database.cc index c21ba49..2ff4758 100644 --- a/webkit/fileapi/file_system_directory_database.cc +++ b/webkit/fileapi/file_system_directory_database.cc @@ -389,6 +389,22 @@ bool FileSystemDirectoryDatabase::GetNextInteger(int64* next) { return GetNextInteger(next); } +// static +bool FileSystemDirectoryDatabase::DestroyDatabase(const FilePath& path) { + std::string name; +#if defined(OS_POSIX) + name = path.value(); +#elif defined(OS_WIN) + name = base::SysWideToUTF8(path.value()); +#endif + leveldb::Status status = leveldb::DestroyDB(name, leveldb::Options()); + if (status.ok()) + return true; + LOG(WARNING) << "Failed to destroy a database with status " << + status.ToString(); + return false; +} + bool FileSystemDirectoryDatabase::Init() { if (db_.get()) return true; diff --git a/webkit/fileapi/file_system_directory_database.h b/webkit/fileapi/file_system_directory_database.h index 22f1212..0c36463 100644 --- a/webkit/fileapi/file_system_directory_database.h +++ b/webkit/fileapi/file_system_directory_database.h @@ -80,6 +80,8 @@ class FileSystemDirectoryDatabase { // creation/destruction of FileSystemDirectoryDatabase objects. bool GetNextInteger(int64* next); + static bool DestroyDatabase(const FilePath& path); + private: bool Init(); bool StoreDefaultValues(); diff --git a/webkit/fileapi/file_system_origin_database.cc b/webkit/fileapi/file_system_origin_database.cc index a559c1b..f028cdc 100644 --- a/webkit/fileapi/file_system_origin_database.cc +++ b/webkit/fileapi/file_system_origin_database.cc @@ -4,8 +4,10 @@ #include "webkit/fileapi/file_system_origin_database.h" +#include "base/format_macros.h" #include "base/logging.h" #include "base/string_number_conversions.h" +#include "base/stringprintf.h" #include "base/string_util.h" #include "base/sys_string_conversions.h" #include "third_party/leveldb/include/leveldb/iterator.h" @@ -93,7 +95,7 @@ bool FileSystemOriginDatabase::GetPathForOrigin( int last_path_number; if (!GetLastPathNumber(&last_path_number)) return false; - path_string = base::IntToString(last_path_number + 1); + path_string = StringPrintf("%03u", last_path_number + 1); // store both back as a single transaction leveldb::WriteBatch batch; batch.Put(LastPathKey(), path_string); diff --git a/webkit/fileapi/obfuscated_file_system_file_util.cc b/webkit/fileapi/obfuscated_file_system_file_util.cc index d91f0b4..1e7c16e 100644 --- a/webkit/fileapi/obfuscated_file_system_file_util.cc +++ b/webkit/fileapi/obfuscated_file_system_file_util.cc @@ -7,9 +7,11 @@ #include <queue> #include "base/file_util.h" +#include "base/format_macros.h" #include "base/logging.h" #include "base/message_loop.h" #include "base/string_number_conversions.h" +#include "base/stringprintf.h" #include "base/sys_string_conversions.h" #include "base/stl_util-inl.h" #include "googleurl/src/gurl.h" @@ -32,14 +34,17 @@ const char kDirectoryDatabaseName[] = "Paths"; void InitFileInfo( fileapi::FileSystemDirectoryDatabase::FileInfo* file_info, fileapi::FileSystemDirectoryDatabase::FileId parent_id, - const FilePath::StringType& file_name, - const FilePath& data_path) { + const FilePath::StringType& file_name) { DCHECK(file_info); file_info->parent_id = parent_id; - file_info->data_path = data_path; file_info->name = file_name; } +const FilePath::CharType kLegacyDataDirectory[] = FILE_PATH_LITERAL("Legacy"); + +const FilePath::CharType kTemporaryDirectoryName[] = FILE_PATH_LITERAL("t"); +const FilePath::CharType kPersistentDirectoryName[] = FILE_PATH_LITERAL("p"); + } // namespace namespace fileapi { @@ -77,11 +82,10 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CreateOrOpen( if (!db->GetFileWithPath(virtual_path.DirName(), &parent_id)) return base::PLATFORM_FILE_ERROR_NOT_FOUND; FileInfo file_info; - InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value(), - FilePath()); + InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value()); PlatformFileError error = CreateFile( - context, context->src_origin_url(), context->src_type(), &file_info, - file_flags, file_handle); + context, context->src_origin_url(), context->src_type(), FilePath(), + &file_info, file_flags, file_handle); if (created && base::PLATFORM_FILE_OK == error) *created = true; return error; @@ -96,8 +100,10 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CreateOrOpen( } if (file_info.is_directory()) return base::PLATFORM_FILE_ERROR_NOT_A_FILE; + FilePath data_path = DataPathToLocalPath(context->src_origin_url(), + context->src_type(), file_info.data_path); return FileSystemFileUtil::GetInstance()->CreateOrOpen( - context, file_info.data_path, file_flags, file_handle, created); + context, data_path, file_flags, file_handle, created); } PlatformFileError ObfuscatedFileSystemFileUtil::EnsureFileExists( @@ -126,10 +132,9 @@ PlatformFileError ObfuscatedFileSystemFileUtil::EnsureFileExists( return base::PLATFORM_FILE_ERROR_NOT_FOUND; FileInfo file_info; - InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value(), - FilePath()); - PlatformFileError error = CreateFile(context, - context->src_origin_url(), context->src_type(), &file_info, 0, NULL); + InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value()); + PlatformFileError error = CreateFile(context, context->src_origin_url(), + context->src_type(), FilePath(), &file_info, 0, NULL); if (created && base::PLATFORM_FILE_OK == error) *created = true; return error; @@ -176,8 +181,10 @@ PlatformFileError ObfuscatedFileSystemFileUtil::GetFileInfo( } if (local_info.data_path.empty()) return base::PLATFORM_FILE_ERROR_INVALID_OPERATION; + FilePath data_path = DataPathToLocalPath(context->src_origin_url(), + context->src_type(), local_info.data_path); return FileSystemFileUtil::GetInstance()->GetFileInfo( - context, local_info.data_path, file_info, platform_file_path); + context, data_path, file_info, platform_file_path); } PlatformFileError ObfuscatedFileSystemFileUtil::ReadDirectory( @@ -318,9 +325,13 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CopyOrMoveFile( * Just update metadata */ if (copy) { + FilePath src_data_path = DataPathToLocalPath(context->src_origin_url(), + context->src_type(), src_file_info.data_path); if (overwrite) { + FilePath dest_data_path = DataPathToLocalPath(context->src_origin_url(), + context->src_type(), dest_file_info.data_path); return FileSystemFileUtil::GetInstance()->CopyOrMoveFile(context, - src_file_info.data_path, dest_file_info.data_path, copy); + src_data_path, dest_data_path, copy); } else { FileId dest_parent_id; if (!db->GetFileWithPath(dest_file_path.DirName(), &dest_parent_id)) { @@ -328,17 +339,20 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CopyOrMoveFile( return base::PLATFORM_FILE_ERROR_NOT_FOUND; } InitFileInfo(&dest_file_info, dest_parent_id, - dest_file_path.BaseName().value(), src_file_info.data_path); + dest_file_path.BaseName().value()); return CreateFile(context, context->dest_origin_url(), - context->dest_type(), &dest_file_info, 0, NULL); + context->dest_type(), src_data_path, &dest_file_info, 0, + NULL); } } else { // It's a move. if (overwrite) { if (!db->OverwritingMoveFile(src_file_id, dest_file_id)) return base::PLATFORM_FILE_ERROR_FAILED; + FilePath dest_data_path = DataPathToLocalPath(context->src_origin_url(), + context->src_type(), dest_file_info.data_path); if (base::PLATFORM_FILE_OK != FileSystemFileUtil::GetInstance()->DeleteFile( - context, dest_file_info.data_path)) + context, dest_data_path)) LOG(WARNING) << "Leaked a backing file."; return base::PLATFORM_FILE_OK; } else { @@ -377,9 +391,10 @@ PlatformFileError ObfuscatedFileSystemFileUtil::DeleteFile( NOTREACHED(); return base::PLATFORM_FILE_ERROR_FAILED; } + FilePath data_path = DataPathToLocalPath(context->src_origin_url(), + context->src_type(), file_info.data_path); if (base::PLATFORM_FILE_OK != - FileSystemFileUtil::GetInstance()->DeleteFile( - context, file_info.data_path)) + FileSystemFileUtil::GetInstance()->DeleteFile(context, data_path)) LOG(WARNING) << "Leaked a backing file."; return base::PLATFORM_FILE_OK; } @@ -426,24 +441,27 @@ PlatformFileError ObfuscatedFileSystemFileUtil::Touch( return base::PLATFORM_FILE_ERROR_FAILED; return base::PLATFORM_FILE_OK; } + FilePath data_path = DataPathToLocalPath(context->src_origin_url(), + context->src_type(), file_info.data_path); return FileSystemFileUtil::GetInstance()->Touch( - context, file_info.data_path, last_access_time, last_modified_time); + context, data_path, last_access_time, last_modified_time); } FileId parent_id; if (!db->GetFileWithPath(virtual_path.DirName(), &parent_id)) return base::PLATFORM_FILE_ERROR_NOT_FOUND; FileInfo file_info; - InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value(), - FilePath()); + InitFileInfo(&file_info, parent_id, virtual_path.BaseName().value()); // In the event of a sporadic underlying failure, we might create a new file, // but fail to update its mtime + atime. - PlatformFileError error = CreateFile(context, - context->src_origin_url(), context->src_type(), &file_info, 0, NULL); + PlatformFileError error = CreateFile(context, context->src_origin_url(), + context->src_type(), FilePath(), &file_info, 0, NULL); if (base::PLATFORM_FILE_OK != error) return error; - return FileSystemFileUtil::GetInstance()->Touch(context, file_info.data_path, + FilePath data_path = DataPathToLocalPath(context->src_origin_url(), + context->src_type(), file_info.data_path); + return FileSystemFileUtil::GetInstance()->Touch(context, data_path, last_access_time, last_modified_time); } @@ -598,7 +616,7 @@ ObfuscatedFileSystemFileUtil::CreateFileEnumerator( PlatformFileError ObfuscatedFileSystemFileUtil::CreateFile( FileSystemOperationContext* context, - const GURL& origin_url, FileSystemType type, + const GURL& origin_url, FileSystemType type, const FilePath& source_path, FileInfo* file_info, int file_flags, PlatformFile* handle) { if (handle) *handle = base::kInvalidPlatformFileValue; @@ -612,19 +630,23 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CreateFile( GetDirectoryForOriginAndType(origin_url, type, false); if (path.empty()) return base::PLATFORM_FILE_ERROR_FAILED; - path = path.AppendASCII(base::Int64ToString(directory_number)); + + path = path.AppendASCII(StringPrintf("%02" PRIu64, directory_number)); PlatformFileError error; error = FileSystemFileUtil::GetInstance()->CreateDirectory( context, path, false /* exclusive */, false /* recursive */); if (base::PLATFORM_FILE_OK != error) return error; - path = path.AppendASCII(base::Int64ToString(number)); + path = path.AppendASCII(StringPrintf("%08" PRIu64, number)); + FilePath data_path = LocalPathToDataPath(origin_url, type, path); + if (data_path.empty()) + return base::PLATFORM_FILE_ERROR_FAILED; bool created = false; - if (!file_info->data_path.empty()) { + if (!source_path.empty()) { DCHECK(!file_flags); DCHECK(!handle); error = FileSystemFileUtil::GetInstance()->CopyOrMoveFile( - context, file_info->data_path, path, true /* copy */); + context, source_path, path, true /* copy */); created = true; } else { if (handle) { @@ -648,7 +670,7 @@ PlatformFileError ObfuscatedFileSystemFileUtil::CreateFile( } return base::PLATFORM_FILE_ERROR_FAILED; } - file_info->data_path = path; + file_info->data_path = data_path; FileId file_id; if (!db->AddFileInfo(*file_info, &file_id)) { if (handle) @@ -675,7 +697,7 @@ FilePath ObfuscatedFileSystemFileUtil::GetLocalPath( NOTREACHED(); return FilePath(); // Directories have no local path. } - return file_info.data_path; + return DataPathToLocalPath(origin_url, type, file_info.data_path); } FilePath ObfuscatedFileSystemFileUtil::GetDirectoryForOriginAndType( @@ -683,13 +705,12 @@ FilePath ObfuscatedFileSystemFileUtil::GetDirectoryForOriginAndType( FilePath origin_dir = GetDirectoryForOrigin(origin, create); if (origin_dir.empty()) return FilePath(); - std::string type_string = - FileSystemPathManager::GetFileSystemTypeString(type); + FilePath::StringType type_string = GetDirectoryNameForType(type); if (type_string.empty()) { LOG(WARNING) << "Unknown filesystem type requested:" << type; return FilePath(); } - return origin_dir.AppendASCII(type_string); + return origin_dir.Append(type_string); } FilePath ObfuscatedFileSystemFileUtil::GetDirectoryForOrigin( @@ -717,6 +738,99 @@ FilePath ObfuscatedFileSystemFileUtil::GetDirectoryForOrigin( return file_system_directory_.Append(directory_name); } +bool ObfuscatedFileSystemFileUtil::MigrateFromOldSandbox( + const GURL& origin_url, FileSystemType type, const FilePath& src_root) { + if (!DestroyDirectoryDatabase(origin_url, type)) + return false; + FilePath dest_root = GetDirectoryForOriginAndType(origin_url, type, true); + if (dest_root.empty()) + return false; + FileSystemDirectoryDatabase* db = GetDirectoryDatabase(origin_url, type); + if (!db) + return false; + + file_util::FileEnumerator file_enum(src_root, true, + static_cast<file_util::FileEnumerator::FILE_TYPE>( + file_util::FileEnumerator::FILES | + file_util::FileEnumerator::DIRECTORIES)); + FilePath src_full_path; + size_t root_path_length = src_root.value().length() + 1; // +1 for the slash + while (!(src_full_path = file_enum.Next()).empty()) { + file_util::FileEnumerator::FindInfo info; + file_enum.GetFindInfo(&info); + FilePath relative_virtual_path = + FilePath(src_full_path.value().substr(root_path_length)); + if (relative_virtual_path.empty()) { + LOG(WARNING) << "Failed to convert path to relative: " << + src_full_path.value(); + return false; + } + FileId file_id; + if (db->GetFileWithPath(relative_virtual_path, &file_id)) { + NOTREACHED(); // File already exists. + return false; + } + if (!db->GetFileWithPath(relative_virtual_path.DirName(), &file_id)) { + NOTREACHED(); // Parent doesn't exist. + return false; + } + + FileInfo file_info; + file_info.name = src_full_path.BaseName().value(); + if (file_util::FileEnumerator::IsDirectory(info)) { +#if defined(OS_WIN) + file_info.modification_time = + base::Time::FromFileTime(info.ftLastWriteTime); +#elif defined(OS_POSIX) + file_info.modification_time = base::Time::FromTimeT(info.stat.st_mtime); +#endif + } else { + file_info.data_path = + FilePath(kLegacyDataDirectory).Append(relative_virtual_path); + } + file_info.parent_id = file_id; + if (!db->AddFileInfo(file_info, &file_id)) { + NOTREACHED(); + return false; + } + } + // TODO(ericu): Should we adjust the mtime of the root directory to match as + // well? + FilePath legacy_dest_dir = dest_root.Append(kLegacyDataDirectory); + return file_util::Move(src_root, legacy_dest_dir); +} + +FilePath::StringType ObfuscatedFileSystemFileUtil::GetDirectoryNameForType( + FileSystemType type) const { + switch (type) { + case kFileSystemTypeTemporary: + return kTemporaryDirectoryName; + case kFileSystemTypePersistent: + return kPersistentDirectoryName; + case kFileSystemTypeUnknown: + default: + return FilePath::StringType(); + } +} + +FilePath ObfuscatedFileSystemFileUtil::DataPathToLocalPath( + const GURL& origin, FileSystemType type, const FilePath& data_path) { + FilePath root = GetDirectoryForOriginAndType(origin, type, false); + if (root.empty()) + return root; + return root.Append(data_path); +} + +FilePath ObfuscatedFileSystemFileUtil::LocalPathToDataPath( + const GURL& origin, FileSystemType type, const FilePath& local_path) { + FilePath root = GetDirectoryForOriginAndType(origin, type, false); + if (root.empty()) + return root; + // This removes the root, including the trailing slash, leaving a relative + // path. + return FilePath(local_path.value().substr(root.value().length() + 1)); +} + // TODO: How to do the whole validation-without-creation thing? We may not have // quota even to create the database. Ah, in that case don't even get here? // Still doesn't answer the quota issue, though. @@ -767,4 +881,28 @@ void ObfuscatedFileSystemFileUtil::DropDatabases() { directories_.clear(); } +bool ObfuscatedFileSystemFileUtil::DestroyDirectoryDatabase( + const GURL& origin, FileSystemType type) { + std::string type_string = + FileSystemPathManager::GetFileSystemTypeString(type); + if (type_string.empty()) { + LOG(WARNING) << "Unknown filesystem type requested:" << type; + return true; + } + // TODO(ericu): This should probably be using GetOriginIdentifierFromURL from + // sandbox_mount_point_provider.cc, instead of just using origin.spec(). + std::string key = origin.spec() + type_string; + DirectoryMap::iterator iter = directories_.find(key); + if (iter != directories_.end()) + directories_.erase(iter); + + FilePath path = GetDirectoryForOriginAndType(origin, type, false); + if (path.empty()) + return true; + if (!file_util::DirectoryExists(path)) + return true; + path = path.AppendASCII(kDirectoryDatabaseName); + return FileSystemDirectoryDatabase::DestroyDatabase(path); +} + } // namespace fileapi diff --git a/webkit/fileapi/obfuscated_file_system_file_util.h b/webkit/fileapi/obfuscated_file_system_file_util.h index c6a4498..65e4e5f 100644 --- a/webkit/fileapi/obfuscated_file_system_file_util.h +++ b/webkit/fileapi/obfuscated_file_system_file_util.h @@ -41,6 +41,9 @@ class FileSystemOperationContext; // SandboxMountPointProvider [and the task it uses to drop the reference] and // SandboxMountPointProvider::GetFileSystemRootPathTask. Without that last one, // we wouldn't need ref counting. +// +// TODO(ericu): We don't ever update directory mtimes; which operations should +// do that? class ObfuscatedFileSystemFileUtil : public FileSystemFileUtil, public base::RefCountedThreadSafe<ObfuscatedFileSystemFileUtil> { public: @@ -131,6 +134,21 @@ class ObfuscatedFileSystemFileUtil : public FileSystemFileUtil, // about migration; TODO(ericu): implement migration and fix these comments. FilePath GetDirectoryForOrigin(const GURL& origin, bool create); + // This will migrate a filesystem from the old passthrough sandbox into the + // new obfuscated one. It won't obfuscate the old filenames [it will maintain + // the old structure, but move it to a new root], but any new files created + // will go into the new standard locations. This will be completely + // transparent to the user. This migration is atomic in that it won't alter + // the source data until it's done, and that will be with a single directory + // move [the directory with the unguessable name will move into the new + // filesystem storage directory]. However, if this fails partway through, it + // might leave a seemingly-valid database for this origin. When it starts up, + // it will clear any such database, just in case. + bool MigrateFromOldSandbox( + const GURL& origin, FileSystemType type, const FilePath& root); + + FilePath::StringType GetDirectoryNameForType(FileSystemType type) const; + protected: virtual AbstractFileEnumerator* CreateFileEnumerator( FileSystemOperationContext* context, @@ -142,29 +160,41 @@ class ObfuscatedFileSystemFileUtil : public FileSystemFileUtil, // Creates a new file, both the underlying backing file and the entry in the // database. file_info is an in-out parameter. Supply the name and - // parent_id; supply data_path if you want it to be used as a source from - // which to COPY data--otherwise leave it empty. On success, data_path will - // always be set to the full path of a NEW backing file, and handle, if - // supplied, will hold open PlatformFile for the backing file, which the - // caller is responsible for closing. + // parent_id; data_path is ignored. On success, data_path will + // always be set to the relative path [from the root of the type-specific + // filesystem directory] of a NEW backing file, and handle, if supplied, will + // hold open PlatformFile for the backing file, which the caller is + // responsible for closing. If you supply a path in source_path, it will be + // used as a source from which to COPY data. // Caveat: do not supply handle if you're also supplying a data path. It was // easier not to support this, and no code has needed it so far, so it will // DCHECK and handle will hold base::kInvalidPlatformFileValue. base::PlatformFileError CreateFile( FileSystemOperationContext* context, const GURL& origin_url, FileSystemType type, - FileInfo* file_info, + const FilePath& source_path, FileInfo* file_info, int file_flags, base::PlatformFile* handle); // Given the filesystem's root URL and a virtual path, produces a real, full - // local path to the underlying data file. + // local path to the underlying data file. This does a database lookup, and + // verifies that the file exists. FilePath GetLocalPath( const GURL& origin_url, FileSystemType type, const FilePath& virtual_path); + // This converts from a relative path [as is stored in the FileInfo.data_path + // field] to an absolute local path that can be given to the operating system. + // It does no checks as to whether the file actually exists; it's pure path + // manipulation. + FilePath DataPathToLocalPath( + const GURL& origin, FileSystemType type, const FilePath& data_path); + // This does the reverse of DataPathToLocalPath. + FilePath LocalPathToDataPath( + const GURL& origin, FileSystemType type, const FilePath& local_path); FileSystemDirectoryDatabase* GetDirectoryDatabase( const GURL& origin_url, FileSystemType type); void MarkUsed(); void DropDatabases(); + bool DestroyDirectoryDatabase(const GURL& origin, FileSystemType type); typedef std::map<std::string, FileSystemDirectoryDatabase*> DirectoryMap; DirectoryMap directories_; diff --git a/webkit/fileapi/obfuscated_file_system_file_util_unittest.cc b/webkit/fileapi/obfuscated_file_system_file_util_unittest.cc index 47db73b..549a542 100644 --- a/webkit/fileapi/obfuscated_file_system_file_util_unittest.cc +++ b/webkit/fileapi/obfuscated_file_system_file_util_unittest.cc @@ -66,6 +66,33 @@ const CopyMoveTestCaseRecord kCopyMoveTestCases[] = { {false, "dir0/file0", "dir1/file1", true}, }; +struct MigrationTestCaseRecord { + bool is_directory; + const FilePath::CharType path[64]; + int64 data_file_size; +}; + +const MigrationTestCaseRecord kMigrationTestCases[] = { + {true, FILE_PATH_LITERAL("dir a"), 0}, + {true, FILE_PATH_LITERAL("dir a/dir a"), 0}, + {true, FILE_PATH_LITERAL("dir a/dir d"), 0}, + {true, FILE_PATH_LITERAL("dir a/dir d/dir e"), 0}, + {true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir f"), 0}, + {true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g"), 0}, + {true, FILE_PATH_LITERAL("dir a/dir d/dir e/dir h"), 0}, + {true, FILE_PATH_LITERAL("dir b"), 0}, + {true, FILE_PATH_LITERAL("dir b/dir a"), 0}, + {true, FILE_PATH_LITERAL("dir c"), 0}, + {false, FILE_PATH_LITERAL("file 0"), 38}, + {false, FILE_PATH_LITERAL("file 2"), 60}, + {false, FILE_PATH_LITERAL("file 3"), 0}, + {false, FILE_PATH_LITERAL("dir a/file 0"), 39}, + {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 0"), 40}, + {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 1"), 41}, + {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 2"), 42}, + {false, FILE_PATH_LITERAL("dir a/dir d/dir e/dir g/file 3"), 50}, +}; + } // namespace (anonymous) // TODO(ericu): The vast majority of this and the other FSFU subclass tests @@ -100,6 +127,10 @@ class ObfuscatedFileSystemFileUtilTest : public testing::Test { return obfuscated_file_system_file_util_.get(); } + const FilePath& test_directory() const { + return data_dir_.path(); + } + int64 GetSize(const FilePath& path) { int64 size; EXPECT_TRUE(file_util::GetFileSize(path, &size)); @@ -753,3 +784,70 @@ TEST_F(ObfuscatedFileSystemFileUtilTest, TestEnumerator) { context.reset(NewContext()); EXPECT_FALSE(ofsfu()->DirectoryExists(context.get(), dest_path)); } + +TEST_F(ObfuscatedFileSystemFileUtilTest, TestMigration) { + ScopedTempDir source_dir; + ASSERT_TRUE(source_dir.CreateUniqueTempDir()); + FilePath root_path = source_dir.path().AppendASCII("chrome-pLmnMWXE7NzTFRsn"); + ASSERT_TRUE(file_util::CreateDirectory(root_path)); + + for (size_t i = 0; i < arraysize(kMigrationTestCases); ++i) { + SCOPED_TRACE(testing::Message() << "Creating kMigrationTestPath " << i); + const MigrationTestCaseRecord& test_case = kMigrationTestCases[i]; + FilePath local_src_path = root_path.Append(test_case.path); + if (test_case.is_directory) { + ASSERT_TRUE( + file_util::CreateDirectory(local_src_path)); + } else { + base::PlatformFileError error_code; + bool created = false; + int file_flags = base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE; + base::PlatformFile file_handle = + base::CreatePlatformFile( + local_src_path, file_flags, &created, &error_code); + EXPECT_TRUE(created); + ASSERT_EQ(base::PLATFORM_FILE_OK, error_code); + ASSERT_TRUE( + base::TruncatePlatformFile(file_handle, test_case.data_file_size)); + EXPECT_TRUE(base::ClosePlatformFile(file_handle)); + } + } + + const GURL origin_url("http://example.com"); + fileapi::FileSystemType type = kFileSystemTypeTemporary; + EXPECT_TRUE(ofsfu()->MigrateFromOldSandbox(origin_url, type, root_path)); + + FilePath new_root = + test_directory().AppendASCII("000").Append( + ofsfu()->GetDirectoryNameForType(type)).AppendASCII("Legacy"); + for (size_t i = 0; i < arraysize(kMigrationTestCases); ++i) { + SCOPED_TRACE(testing::Message() << "Validating kMigrationTestPath " << i); + const MigrationTestCaseRecord& test_case = kMigrationTestCases[i]; + FilePath local_data_path = new_root.Append(test_case.path); +#if defined(OS_WIN) + local_data_path = local_data_path.NormalizeWindowsPathSeparators(); +#endif + scoped_ptr<FileSystemOperationContext> context(NewContext()); + base::PlatformFileInfo ofsfu_file_info; + FilePath data_path; + SCOPED_TRACE(testing::Message() << "Path is " << test_case.path); + EXPECT_EQ(base::PLATFORM_FILE_OK, + ofsfu()->GetFileInfo(context.get(), FilePath(test_case.path), + &ofsfu_file_info, &data_path)); + if (test_case.is_directory) { + EXPECT_TRUE(ofsfu_file_info.is_directory); + } else { + base::PlatformFileInfo platform_file_info; + SCOPED_TRACE(testing::Message() << "local_data_path is " << + local_data_path.value()); + SCOPED_TRACE(testing::Message() << "data_path is " << data_path.value()); + ASSERT_TRUE(file_util::GetFileInfo(local_data_path, &platform_file_info)); + EXPECT_EQ(test_case.data_file_size, platform_file_info.size); + EXPECT_FALSE(platform_file_info.is_directory); + scoped_ptr<FileSystemOperationContext> context(NewContext()); + EXPECT_EQ(local_data_path, data_path); + EXPECT_EQ(platform_file_info.size, ofsfu_file_info.size); + EXPECT_FALSE(ofsfu_file_info.is_directory); + } + } +} |