summaryrefslogtreecommitdiffstats
path: root/webkit/fileapi
diff options
context:
space:
mode:
authorericu@chromium.org <ericu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-04 02:29:17 +0000
committerericu@chromium.org <ericu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-04 02:29:17 +0000
commit456b545268b62b89f93b67d5fcae4851cd64144e (patch)
tree1db82c014a4636c62af766e2dec8604fff42a3d3 /webkit/fileapi
parent5e2a9aaf31d13e5a76b64480fce107d5ad38b4c5 (diff)
downloadchromium_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.cc190
-rw-r--r--webkit/fileapi/file_system_origin_database.h55
-rw-r--r--webkit/fileapi/file_system_origin_database_unittest.cc166
-rw-r--r--webkit/fileapi/webkit_fileapi.gypi5
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',