diff options
author | ericu@chromium.org <ericu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-04 02:29:17 +0000 |
---|---|---|
committer | ericu@chromium.org <ericu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-04 02:29:17 +0000 |
commit | 456b545268b62b89f93b67d5fcae4851cd64144e (patch) | |
tree | 1db82c014a4636c62af766e2dec8604fff42a3d3 /webkit/fileapi | |
parent | 5e2a9aaf31d13e5a76b64480fce107d5ad38b4c5 (diff) | |
download | chromium_src-456b545268b62b89f93b67d5fcae4851cd64144e.zip chromium_src-456b545268b62b89f93b67d5fcae4851cd64144e.tar.gz chromium_src-456b545268b62b89f93b67d5fcae4851cd64144e.tar.bz2 |
A database to hold mappings from origin identifiers to unique directory names.
BUG=NONE
TEST=included
Review URL: http://codereview.chromium.org/6903118
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@84029 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/fileapi')
-rw-r--r-- | webkit/fileapi/file_system_origin_database.cc | 190 | ||||
-rw-r--r-- | webkit/fileapi/file_system_origin_database.h | 55 | ||||
-rw-r--r-- | webkit/fileapi/file_system_origin_database_unittest.cc | 166 | ||||
-rw-r--r-- | webkit/fileapi/webkit_fileapi.gypi | 5 |
4 files changed, 415 insertions, 1 deletions
diff --git a/webkit/fileapi/file_system_origin_database.cc b/webkit/fileapi/file_system_origin_database.cc new file mode 100644 index 0000000..a559c1b --- /dev/null +++ b/webkit/fileapi/file_system_origin_database.cc @@ -0,0 +1,190 @@ +// 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_origin_database.h" + +#include "base/logging.h" +#include "base/string_number_conversions.h" +#include "base/string_util.h" +#include "base/sys_string_conversions.h" +#include "third_party/leveldb/include/leveldb/iterator.h" +#include "third_party/leveldb/include/leveldb/write_batch.h" + +namespace { + +const char kOriginKeyPrefix[] = "ORIGIN:"; +const char kLastPathKey[] = "LAST_PATH"; + +std::string OriginToOriginKey(const std::string& origin) { + std::string key(kOriginKeyPrefix); + return key + origin; +} + +const char* LastPathKey() { + return kLastPathKey; +} + +} + +namespace fileapi { + +FileSystemOriginDatabase::FileSystemOriginDatabase(const FilePath& path) { +#if defined(OS_POSIX) + path_ = path.value(); +#elif defined(OS_WIN) + path_ = base::SysWideToUTF8(path.value()); +#endif +} + +FileSystemOriginDatabase::~FileSystemOriginDatabase() { +} + +bool FileSystemOriginDatabase::Init() { + if (db_.get()) + return true; + + leveldb::Options options; + options.create_if_missing = true; + leveldb::DB* db; + leveldb::Status status = leveldb::DB::Open(options, path_, &db); + if (status.ok()) { + db_.reset(db); + return true; + } + HandleError(status); + return false; +} + +void FileSystemOriginDatabase::HandleError(leveldb::Status status) { + db_.reset(); + LOG(ERROR) << "FileSystemOriginDatabase failed with error: " << + status.ToString(); +} + +bool FileSystemOriginDatabase::HasOriginPath(const std::string& origin) { + if (!Init()) + return false; + if (origin.empty()) + return false; + std::string path; + leveldb::Status status = + db_->Get(leveldb::ReadOptions(), OriginToOriginKey(origin), &path); + if (status.ok()) + return true; + if (status.IsNotFound()) + return false; + HandleError(status); + return false; +} + +bool FileSystemOriginDatabase::GetPathForOrigin( + const std::string& origin, FilePath* directory) { + if (!Init()) + return false; + DCHECK(directory); + if (origin.empty()) + return false; + std::string path_string; + std::string origin_key = OriginToOriginKey(origin); + leveldb::Status status = + db_->Get(leveldb::ReadOptions(), origin_key, &path_string); + if (status.IsNotFound()) { + int last_path_number; + if (!GetLastPathNumber(&last_path_number)) + return false; + path_string = base::IntToString(last_path_number + 1); + // store both back as a single transaction + leveldb::WriteBatch batch; + batch.Put(LastPathKey(), path_string); + batch.Put(origin_key, path_string); + status = db_->Write(leveldb::WriteOptions(), &batch); + if (!status.ok()) { + HandleError(status); + return false; + } + } + if (status.ok()) { +#if defined(OS_POSIX) + *directory = FilePath(path_string); +#elif defined(OS_WIN) + *directory = FilePath(base::SysUTF8ToWide(path_string)); +#endif + return true; + } + HandleError(status); + return false; +} + +bool FileSystemOriginDatabase::RemovePathForOrigin(const std::string& origin) { + if (!Init()) + return false; + leveldb::Status status = + db_->Delete(leveldb::WriteOptions(), OriginToOriginKey(origin)); + if (status.ok() || status.IsNotFound()) + return true; + HandleError(status); + return false; +} + +bool FileSystemOriginDatabase::ListAllOrigins( + std::vector<OriginRecord>* origins) { + if (!Init()) + return false; + DCHECK(origins); + scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); + std::string origin_key_prefix = OriginToOriginKey(""); + iter->Seek(origin_key_prefix); + origins->clear(); + while(iter->Valid() && + StartsWithASCII(iter->key().ToString(), origin_key_prefix, true)) { + std::string origin = + iter->key().ToString().substr(origin_key_prefix.length()); +#if defined(OS_POSIX) + FilePath path = FilePath(iter->value().ToString()); +#elif defined(OS_WIN) + FilePath path = FilePath(base::SysUTF8ToWide(iter->value().ToString())); +#endif + origins->push_back(OriginRecord(origin, path)); + iter->Next(); + } + return true; +} + +void FileSystemOriginDatabase::DropDatabase() { + db_.reset(); +} + +bool FileSystemOriginDatabase::GetLastPathNumber(int* number) { + if (!Init()) + return false; + DCHECK(number); + std::string number_string; + leveldb::Status status = + db_->Get(leveldb::ReadOptions(), LastPathKey(), &number_string); + if (status.ok()) + return base::StringToInt(number_string, number); + if (!status.IsNotFound()) { + HandleError(status); + return false; + } + // Verify that this is a totally new database, and initialize it. + scoped_ptr<leveldb::Iterator> iter(db_->NewIterator(leveldb::ReadOptions())); + iter->SeekToFirst(); + if (iter->Valid()) { // DB was not empty, but had no last path number! + LOG(ERROR) << "File system origin database is corrupt!"; + return false; + } + // This is always the first write into the database. If we ever add a + // version number, they should go in in a single transaction. + status = + db_->Put(leveldb::WriteOptions(), LastPathKey(), std::string("-1")); + if (!status.ok()) { + HandleError(status); + return false; + } + *number = -1; + return true; +} + +} // namespace fileapi diff --git a/webkit/fileapi/file_system_origin_database.h b/webkit/fileapi/file_system_origin_database.h new file mode 100644 index 0000000..1a28082 --- /dev/null +++ b/webkit/fileapi/file_system_origin_database.h @@ -0,0 +1,55 @@ +// 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. + +#ifndef WEBKIT_FILEAPI_FILE_SYSTEM_ORIGIN_DATABASE_H_ +#define WEBKIT_FILEAPI_FILE_SYSTEM_ORIGIN_DATABASE_H_ + +#include <string> +#include <utility> +#include <vector> + +#include "base/file_path.h" +#include "base/scoped_ptr.h" +#include "third_party/leveldb/include/leveldb/db.h" + +namespace fileapi { + +// All methods of this class other than the constructor may be used only from +// the browser's FILE thread. The constructor may be used on any thread. +class FileSystemOriginDatabase { + public: + typedef std::pair<std::string, FilePath> OriginRecord; + + // Only one instance of FileSystemOriginDatabase should exist for a given path + // at a given time. + FileSystemOriginDatabase(const FilePath& path); + ~FileSystemOriginDatabase(); + + bool HasOriginPath(const std::string& origin); + + // This will produce a unique path and add it to its database, if it's not + // already present. + bool GetPathForOrigin(const std::string& origin, FilePath* directory); + + // Also returns success if the origin is not found. + bool RemovePathForOrigin(const std::string& origin); + + bool ListAllOrigins(std::vector<OriginRecord>* origins); + + // This will release all database resources in use; call it to save memory. + void DropDatabase(); + + private: + bool Init(); + void HandleError(leveldb::Status status); + bool GetLastPathNumber(int* number); + + std::string path_; + scoped_ptr<leveldb::DB> db_; + DISALLOW_COPY_AND_ASSIGN(FileSystemOriginDatabase); +}; + +} // namespace fileapi + +#endif // WEBKIT_FILEAPI_FILE_SYSTEM_ORIGIN_DATABASE_H_ diff --git a/webkit/fileapi/file_system_origin_database_unittest.cc b/webkit/fileapi/file_system_origin_database_unittest.cc new file mode 100644 index 0000000..c7c4f71 --- /dev/null +++ b/webkit/fileapi/file_system_origin_database_unittest.cc @@ -0,0 +1,166 @@ +// 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 "testing/gtest/include/gtest/gtest.h" + +#include <string> + +#include "base/file_util.h" +#include "base/memory/scoped_temp_dir.h" +#include "webkit/fileapi/file_system_origin_database.h" + +namespace fileapi { + +TEST(FileSystemOriginDatabaseTest, BasicTest) { + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + const FilePath kDBFile = dir.path().AppendASCII("fsod.db"); + EXPECT_FALSE(file_util::PathExists(kDBFile)); + + FileSystemOriginDatabase database(kDBFile); + std::string origin("origin"); + + EXPECT_FALSE(database.HasOriginPath(origin)); + // Double-check to make sure that had no side effects. + EXPECT_FALSE(database.HasOriginPath(origin)); + + FilePath path0; + FilePath path1; + + // Empty strings aren't valid origins. + EXPECT_FALSE(database.GetPathForOrigin(std::string(), &path0)); + + EXPECT_TRUE(database.GetPathForOrigin(origin, &path0)); + EXPECT_TRUE(database.HasOriginPath(origin)); + EXPECT_TRUE(database.GetPathForOrigin(origin, &path1)); + EXPECT_FALSE(path0.empty()); + EXPECT_FALSE(path1.empty()); + EXPECT_EQ(path0, path1); + + EXPECT_TRUE(file_util::PathExists(kDBFile)); +} + +TEST(FileSystemOriginDatabaseTest, TwoPathTest) { + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + const FilePath kDBFile = dir.path().AppendASCII("fsod.db"); + EXPECT_FALSE(file_util::PathExists(kDBFile)); + + FileSystemOriginDatabase database(kDBFile); + std::string origin0("origin0"); + std::string origin1("origin1"); + + EXPECT_FALSE(database.HasOriginPath(origin0)); + EXPECT_FALSE(database.HasOriginPath(origin1)); + + FilePath path0; + FilePath path1; + EXPECT_TRUE(database.GetPathForOrigin(origin0, &path0)); + EXPECT_TRUE(database.HasOriginPath(origin0)); + EXPECT_FALSE(database.HasOriginPath(origin1)); + EXPECT_TRUE(database.GetPathForOrigin(origin1, &path1)); + EXPECT_TRUE(database.HasOriginPath(origin1)); + EXPECT_FALSE(path0.empty()); + EXPECT_FALSE(path1.empty()); + EXPECT_NE(path0, path1); + + EXPECT_TRUE(file_util::PathExists(kDBFile)); +} + +TEST(FileSystemOriginDatabaseTest, DropDatabaseTest) { + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + const FilePath kDBFile = dir.path().AppendASCII("fsod.db"); + EXPECT_FALSE(file_util::PathExists(kDBFile)); + + FileSystemOriginDatabase database(kDBFile); + std::string origin("origin"); + + EXPECT_FALSE(database.HasOriginPath(origin)); + + FilePath path0; + EXPECT_TRUE(database.GetPathForOrigin(origin, &path0)); + EXPECT_TRUE(database.HasOriginPath(origin)); + EXPECT_FALSE(path0.empty()); + + EXPECT_TRUE(file_util::PathExists(kDBFile)); + + database.DropDatabase(); + + FilePath path1; + EXPECT_TRUE(database.HasOriginPath(origin)); + EXPECT_TRUE(database.GetPathForOrigin(origin, &path1)); + EXPECT_FALSE(path1.empty()); + EXPECT_EQ(path0, path1); +} + +TEST(FileSystemOriginDatabaseTest, DeleteOriginTest) { + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + const FilePath kDBFile = dir.path().AppendASCII("fsod.db"); + EXPECT_FALSE(file_util::PathExists(kDBFile)); + + FileSystemOriginDatabase database(kDBFile); + std::string origin("origin"); + + EXPECT_FALSE(database.HasOriginPath(origin)); + EXPECT_TRUE(database.RemovePathForOrigin(origin)); + + FilePath path0; + EXPECT_TRUE(database.GetPathForOrigin(origin, &path0)); + EXPECT_TRUE(database.HasOriginPath(origin)); + EXPECT_FALSE(path0.empty()); + + EXPECT_TRUE(database.RemovePathForOrigin(origin)); + EXPECT_FALSE(database.HasOriginPath(origin)); + + FilePath path1; + EXPECT_TRUE(database.GetPathForOrigin(origin, &path1)); + EXPECT_FALSE(path1.empty()); + EXPECT_NE(path0, path1); +} + +TEST(FileSystemOriginDatabaseTest, ListOriginsTest) { + ScopedTempDir dir; + ASSERT_TRUE(dir.CreateUniqueTempDir()); + const FilePath kDBFile = dir.path().AppendASCII("fsod.db"); + EXPECT_FALSE(file_util::PathExists(kDBFile)); + + std::vector<FileSystemOriginDatabase::OriginRecord> origins; + + FileSystemOriginDatabase database(kDBFile); + EXPECT_TRUE(database.ListAllOrigins(&origins)); + EXPECT_TRUE(origins.empty()); + origins.clear(); + + std::string origin0("origin0"); + std::string origin1("origin1"); + + EXPECT_FALSE(database.HasOriginPath(origin0)); + EXPECT_FALSE(database.HasOriginPath(origin1)); + + FilePath path0; + FilePath path1; + EXPECT_TRUE(database.GetPathForOrigin(origin0, &path0)); + EXPECT_TRUE(database.ListAllOrigins(&origins)); + EXPECT_EQ(origins.size(), 1UL); + EXPECT_EQ(origins[0].first, origin0); + EXPECT_EQ(origins[0].second, path0); + origins.clear(); + EXPECT_TRUE(database.GetPathForOrigin(origin1, &path1)); + EXPECT_TRUE(database.ListAllOrigins(&origins)); + EXPECT_EQ(origins.size(), 2UL); + if (origins[0].first == origin0) { + EXPECT_EQ(origins[0].second, path0); + EXPECT_EQ(origins[1].first, origin1); + EXPECT_EQ(origins[1].second, path1); + } else { + EXPECT_EQ(origins[0].first, origin1); + EXPECT_EQ(origins[0].second, path1); + EXPECT_EQ(origins[1].first, origin0); + EXPECT_EQ(origins[1].second, path0); + } +} + +} // namespace fileapi diff --git a/webkit/fileapi/webkit_fileapi.gypi b/webkit/fileapi/webkit_fileapi.gypi index 258db99..cda2ec0 100644 --- a/webkit/fileapi/webkit_fileapi.gypi +++ b/webkit/fileapi/webkit_fileapi.gypi @@ -1,4 +1,4 @@ -# Copyright (c) 2010 The Chromium Authors. All rights reserved. +# 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. @@ -12,6 +12,7 @@ '<(DEPTH)/app/app.gyp:app_base', '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/net/net.gyp:net', + '<(DEPTH)/third_party/leveldb/leveldb.gyp:leveldb', ], 'sources': [ 'file_system_callback_dispatcher.cc', @@ -29,6 +30,8 @@ 'file_system_operation.h', 'file_system_operation_context.cc', 'file_system_operation_context.h', + 'file_system_origin_database.cc', + 'file_system_origin_database.h', 'file_system_path_manager.cc', 'file_system_path_manager.h', 'file_system_types.h', |