Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Unified Diff: webkit/fileapi/obfuscated_name_map.cc

Issue 6286038: Add initial code to do filename munging in the FileSystem.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webkit/fileapi/obfuscated_name_map.cc
===================================================================
--- webkit/fileapi/obfuscated_name_map.cc (revision 0)
+++ webkit/fileapi/obfuscated_name_map.cc (revision 0)
@@ -0,0 +1,309 @@
+// 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/obfuscated_name_map.h"
+
+#if defined(OS_WIN)
+#include <errno.h>
+#endif
+
+#include "base/file_util.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "base/sys_string_conversions.h"
+
+namespace fileapi {
+
+ObfuscatedNameMap::ObfuscatedNameMap()
+ : directory_(),
+ map_valid_(false),
+ map_next_valid_(false) {
+}
+
+void ObfuscatedNameMap::Init(const FilePath& directory) {
+ Rollback();
+ map_valid_ = false;
+ map_.clear();
+ map_next_valid_ = false;
+ map_next_.clear();
+ directory_ = directory;
+}
+
+PlatformFileError ObfuscatedNameMap::ClearNameFromObfuscatedName(
+ StringType obfuscated_name,
+ StringType* clear_name) {
+ CHECK(clear_name);
+ PlatformFileError error = LoadFromFileIfNeeded();
+ if (base::PLATFORM_FILE_OK != error)
+ return error;
+ MapType::iterator found = map_.find(obfuscated_name);
+ if (found == map_.end())
+ return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ *clear_name = found->second;
+ return base::PLATFORM_FILE_OK;
+}
+
+StringType ObfuscatedNameMap::ObfuscatedNameFromClearName(
+ StringType clear_name) {
+ // FIXME: This is a hack to get around the fact that PRIxS produces an 8-bit
+ // string on all platforms, and the macro that would fix that gets evaluated
+ // *before* PRIxS does, so it can't be used.
+ FilePath temp;
+ return base::StringPrintf(
+ temp.AppendASCII("%08" PRIxS).BaseName().value().c_str(),
+ hash(FilePath(clear_name)));
+}
+
+PlatformFileError ObfuscatedNameMap::PrepareAdd(
+ const StringType& clear_name, const StringType& obfuscated_name) {
+ PlatformFileError error = InitMapNext();
+ if (base::PLATFORM_FILE_OK != error)
+ return error;
+#ifndef NDEBUG
+ StringType test_name(ObfuscatedNameFromClearName(clear_name));
+ CHECK(test_name == obfuscated_name);
+#endif
+ if (map_next_.find(obfuscated_name) != map_next_.end())
+ return base::PLATFORM_FILE_ERROR_EXISTS;
+ map_next_[obfuscated_name] = clear_name;
+ return WriteToNextFile();
+}
+
+PlatformFileError ObfuscatedNameMap::PrepareDelete(
+ const StringType& clear_name, const StringType& obfuscated_name) {
+ PlatformFileError error = InitMapNext();
+ if (base::PLATFORM_FILE_OK != error)
+ return error;
+#ifndef NDEBUG
+ StringType test_name(ObfuscatedNameFromClearName(clear_name));
+ CHECK(test_name == obfuscated_name);
+#endif
+
+ MapType::iterator found = map_next_.find(obfuscated_name);
+ if (found == map_next_.end())
+ return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ map_next_.erase(found);
+ return WriteToNextFile();
+}
+
+PlatformFileError ObfuscatedNameMap::PrepareMove(
+ const StringType& old_clear_name,
+ const StringType& old_obfuscated_name,
+ const StringType& new_clear_name,
+ const StringType& new_obfuscated_name) {
+ PlatformFileError error = InitMapNext();
+ if (base::PLATFORM_FILE_OK != error)
+ return error;
+#ifndef NDEBUG
+ StringType test_name(ObfuscatedNameFromClearName(old_clear_name));
+ CHECK(test_name == old_obfuscated_name);
+ test_name = ObfuscatedNameFromClearName(new_clear_name);
+ CHECK(test_name == new_obfuscated_name);
+#endif
+ if (map_next_.find(new_obfuscated_name) != map_next_.end())
+ return base::PLATFORM_FILE_ERROR_EXISTS;
+ MapType::iterator old_found = map_next_.find(old_obfuscated_name);
+ if (old_found == map_next_.end())
+ return base::PLATFORM_FILE_ERROR_NOT_FOUND;
+ map_next_.erase(old_found);
+ map_next_[new_obfuscated_name] = new_clear_name;
+ return WriteToNextFile();
+}
+
+PlatformFileError ObfuscatedNameMap::Commit() {
+ CHECK(map_next_valid_);
+ if (file_util::Move(GetDictionaryNextLocation(), GetDictionaryLocation())) {
+ map_.swap(map_next_);
+ map_valid_ = map_next_valid_;
+ map_next_valid_ = false;
+ map_next_.clear();
+ return base::PLATFORM_FILE_OK;
+ } else {
+ return base::PLATFORM_FILE_ERROR_FAILED;
+ }
+}
+
+void ObfuscatedNameMap::Rollback() {
+ if (map_next_valid_) {
+ map_next_valid_ = false;
+ map_next_.clear();
+ // The file may or may not exist; we delete it and ignore errors.
+ file_util::Delete(GetDictionaryNextLocation(), false);
+ }
+}
+
+size_t ObfuscatedNameMap::hash(const FilePath& f) {
+ // TODO(ericu): This is temporary--find a real SHA1 implementation or the
+ // like somewhere in our existing codebase.
+#if defined(COMPILER_GCC)
+ struct __gnu__cxx::hash<FilePath> gcc_hash;
Dai Mikurube (google.com) 2011/02/22 02:57:35 s/__gnu__cxx/__gnu_cxx/
+ return gcc_hash(f);
+#elif defined(COMPILER_MSVC)
+ return stdext::hash_value(f);
+#else
+#error // Must define hashing function
+#endif
+}
+
+FilePath ObfuscatedNameMap::GetDictionaryLocation() {
+ return directory_.Append(StringType(DICTIONARY_NAME));
+}
+
+FilePath ObfuscatedNameMap::GetDictionaryNextLocation() {
+ return directory_.Append(StringType(DICTIONARY_NEXT_NAME));
+}
+
+PlatformFileError ObfuscatedNameMap::LoadFromFileIfNeeded() {
+ if (map_valid_)
+ return base::PLATFORM_FILE_OK;
+
+ PlatformFileError error = RecoverIfNeeded();
+ if (base::PLATFORM_FILE_OK != error)
+ return error;
+
+ if (!file_util::PathExists(GetDictionaryLocation())) {
+ map_valid_ = true; // It's just empty.
+ return base::PLATFORM_FILE_OK;
+ }
+
+ std::string contents;
+ if (!file_util::ReadFileToString(GetDictionaryLocation(), &contents))
+ return base::PLATFORM_FILE_ERROR_FAILED;
+ StringType data;
+#if defined(OS_POSIX)
+ data = contents;
+#elif defined(OS_WIN)
+ errno_t local_errno;
+ size_t size = 0;
+
+ local_errno = mbstowcs_s(&size, NULL, 0, contents.c_str(), 0);
+ // FIXME: If either of these two happen, the dictionary is corrupt or
+ // otherwise unusable. We should probably log an error and continue, but I
+ // won't do that yet.
+ // Max entries + entry length + a little padding.
+ if (local_errno || size > 4000 * (256 + 120))
+ return base::PLATFORM_FILE_ERROR_FAILED;
+ scoped_ptr<wchar_t> buffer(new wchar_t[size]);
+ local_errno =
+ mbstowcs_s(&size, buffer.get(), size, contents.c_str(), size - 1);
+ if (local_errno) {
+ return base::PLATFORM_FILE_ERROR_FAILED; // This should never happen.
+ }
+ data = buffer.get();
+#else
+#error // Must define the appropriate conversion here.
+#endif
+ LoadMapFromString(&map_, data);
+ return base::PLATFORM_FILE_OK;
+}
+
+void ObfuscatedNameMap::LoadMapFromString(
+ MapType* map, const StringType& serialized) {
+ // Format: ([a-z0-0]+:[$legal_set_of_filename_chars]+:\n)*
+ // Empty is legal; it's easier than deleting the dict when we remove the
+ // last file from the dir, probably?
+ // Note that ':' is the separator *and* the terminator [along with the
+ // newline], since a newline could legally be in the filename.
+ StringType hash, name;
+ MapType temp_map;
+ size_t i;
+ for (i = 0; i < serialized.length(); ++i) {
+ size_t hash_start = i;
+ i = serialized.find(SEPARATOR, i);
+ if (i == StringType::npos)
+ break;
+ size_t hash_end = i;
+ size_t name_start = i + SEPARATOR_LENGTH;
+ size_t name_end = serialized.find(TERMINATOR, name_start);
+ if (name_end == StringType::npos)
+ break; // TODO(ericu): Log an error here, but continue?
+ i = name_end + TERMINATOR_LENGTH;
+ hash = serialized.substr(hash_start, hash_end - hash_start);
+ name = serialized.substr(name_start, name_end - name_start);
+ temp_map[hash] = name;
+ }
+// if (i != serialized.length())
+// ; // TODO(ericu): Log an error here, but continue?
+ map->swap(temp_map);
+}
+
+StringType ObfuscatedNameMap::ConvertMapToString(const MapType& map) {
+ StringType serialized;
+ for (MapType::const_iterator iter = map.begin();
+ iter != map.end(); ++iter) {
+ serialized += iter->first + SEPARATOR + iter->second + TERMINATOR;
+ }
+ return serialized;
+}
+
+PlatformFileError ObfuscatedNameMap::InitMapNext() {
+ CHECK(!map_next_valid_);
+ PlatformFileError error = LoadFromFileIfNeeded();
+ if (base::PLATFORM_FILE_OK != error)
+ return error;
+ map_next_ = map_;
+ map_next_valid_ = true;
+ return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError ObfuscatedNameMap::RecoverIfNeeded() {
+ // TODO(ericu): if DICT_NEXT doesn't exist, return base::PLATFORM_FILE_OK.
+ // TODO(ericu): read map_ from DICT, map_next from DICT_NEXT.
+ // TODO(ericu): find the *one* element that differs.
+ // TODO(ericu): if it's not exactly one, goto handle_error
+ // TODO(ericu):
+ // if it's a deletion:
+ // if the file's gone, commit the dict, else revert the dict
+ // else if it's an addition:
+ // if the file's there, commit the dict, else revert the dict
+ // else // it's a move:
+ // if the old file's gone and the new file's there, commit the dict.
+ // if the old file's there and the new file's not, revert the dict.
+ // else goto handle_error
+ // return base::PLATFORM_FILE_OK;
+ // handle_error: either return an error here, or revert the dict so that
+ // progress can be made; it's a policy decision.
+ // either way, make sure that map_valid_ is valid.
+ //
+ return base::PLATFORM_FILE_OK;
+}
+
+PlatformFileError ObfuscatedNameMap::WriteToNextFile() {
+ StringType contents = ConvertMapToString(map_next_);
+ std::string data;
+#if defined(OS_POSIX)
+ data.swap(contents);
+#elif defined(OS_WIN)
+ data = base::SysWideToUTF8(contents);
+#else
+#error // Must define the appropriate conversion here.
+#endif
+ size_t bytes_written = 0;
+ FilePath location = GetDictionaryNextLocation();
+ while (bytes_written < data.length()) {
+ int write_response = file_util::WriteFile(
+ location, data.c_str() + bytes_written, data.length());
+ if (write_response <= 0) {
+ if (bytes_written)
+ file_util::Delete(GetDictionaryNextLocation(), false /* recursive */);
+ return base::PLATFORM_FILE_ERROR_FAILED;
+ }
+ bytes_written += write_response;
+ }
+ return base::PLATFORM_FILE_OK;
+}
+
+const StringType::value_type ObfuscatedNameMap::DICTIONARY_NAME[] =
+ FILE_PATH_LITERAL("dict");
+const StringType::value_type ObfuscatedNameMap::DICTIONARY_NEXT_NAME[] =
+ FILE_PATH_LITERAL("dict_next");
+const StringType::value_type ObfuscatedNameMap::SEPARATOR[] =
+ FILE_PATH_LITERAL(":");
+const size_t ObfuscatedNameMap::SEPARATOR_LENGTH = 1;
+const StringType::value_type ObfuscatedNameMap::TERMINATOR[] =
+ FILE_PATH_LITERAL(":\n");
+const size_t ObfuscatedNameMap::TERMINATOR_LENGTH = 2;
+
+} // namespace fileapi
Property changes on: webkit\fileapi\obfuscated_name_map.cc
___________________________________________________________________
Added: svn:eol-style
+ LF

Powered by Google App Engine
This is Rietveld 408576698