diff options
Diffstat (limited to 'webkit/fileapi/sandbox_mount_point_provider.cc')
-rw-r--r-- | webkit/fileapi/sandbox_mount_point_provider.cc | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/webkit/fileapi/sandbox_mount_point_provider.cc b/webkit/fileapi/sandbox_mount_point_provider.cc new file mode 100644 index 0000000..ac82cc8 --- /dev/null +++ b/webkit/fileapi/sandbox_mount_point_provider.cc @@ -0,0 +1,312 @@ +// 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/sandbox_mount_point_provider.h" + +#include "base/logging.h" +#include "base/message_loop.h" +#include "base/message_loop_proxy.h" +#include "base/rand_util.h" +#include "base/scoped_callback_factory.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "googleurl/src/gurl.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebCString.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" +#include "webkit/fileapi/file_system_path_manager.h" +#include "webkit/fileapi/file_system_util.h" +#include "webkit/glue/webkit_glue.h" + +namespace { + +static const FilePath::CharType kFileSystemUniqueNamePrefix[] = + FILE_PATH_LITERAL("chrome-"); +static const int kFileSystemUniqueLength = 16; +static const unsigned kFileSystemUniqueDirectoryNameLength = + kFileSystemUniqueLength + arraysize(kFileSystemUniqueNamePrefix) - 1; + +// Restricted names. +// http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#naming-restrictions +static const char* const kRestrictedNames[] = { + "con", "prn", "aux", "nul", + "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", + "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", +}; + +// Restricted chars. +static const FilePath::CharType kRestrictedChars[] = { + '/', '\\', '<', '>', ':', '?', '*', '"', '|', +}; + +inline std::string FilePathStringToASCII( + const FilePath::StringType& path_string) { +#if defined(OS_WIN) + return WideToASCII(path_string); +#elif defined(OS_POSIX) + return path_string; +#endif +} + +FilePath::StringType CreateUniqueDirectoryName(const GURL& origin_url) { + // This can be anything but need to be unpredictable. + static const FilePath::CharType letters[] = FILE_PATH_LITERAL( + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"); + FilePath::StringType unique(kFileSystemUniqueNamePrefix); + for (int i = 0; i < kFileSystemUniqueLength; ++i) + unique += letters[base::RandInt(0, arraysize(letters) - 2)]; + return unique; +} + +bool ReadOriginDirectory(const FilePath& base_path, + const GURL& origin_url, + FilePath* unique) { + file_util::FileEnumerator file_enum( + base_path, false /* recursive */, + file_util::FileEnumerator::DIRECTORIES, + FilePath::StringType(kFileSystemUniqueNamePrefix) + + FILE_PATH_LITERAL("*")); + FilePath current; + bool found = false; + while (!(current = file_enum.Next()).empty()) { + if (current.BaseName().value().length() != + kFileSystemUniqueDirectoryNameLength) + continue; + if (found) { + // TODO(kinuko): Should notify the user to ask for some action. + LOG(WARNING) << "Unexpectedly found more than one FileSystem " + << "directories for " << origin_url; + return false; + } + found = true; + *unique = current; + } + return !unique->empty(); +} + +FilePath GetFileSystemRootPathOnFileThreadHelper( + const GURL& origin_url, const FilePath &origin_base_path, bool create) { + FilePath root; + if (ReadOriginDirectory(origin_base_path, origin_url, &root)) + return root; + + if (!create) + return FilePath(); + + // Creates the root directory. + root = origin_base_path.Append(CreateUniqueDirectoryName(origin_url)); + if (!file_util::CreateDirectory(root)) + return FilePath(); + + return root; +} + +} // anonymous namespace + +namespace fileapi { + +const FilePath::CharType SandboxMountPointProvider::kFileSystemDirectory[] = + FILE_PATH_LITERAL("FileSystem"); + +const char SandboxMountPointProvider::kPersistentName[] = "Persistent"; +const char SandboxMountPointProvider::kTemporaryName[] = "Temporary"; + +SandboxMountPointProvider::SandboxMountPointProvider( + FileSystemPathManager* path_manager, + scoped_refptr<base::MessageLoopProxy> file_message_loop, + const FilePath& profile_path) + : path_manager_(path_manager), + file_message_loop_(file_message_loop), + base_path_(profile_path.Append(kFileSystemDirectory)) { +} + +bool SandboxMountPointProvider::IsAccessAllowed(const GURL& origin_url) { + // We essentially depend on quota to do our access controls. + return path_manager_->IsAllowedScheme(origin_url); +} + +class SandboxMountPointProvider::GetFileSystemRootPathTask + : public base::RefCountedThreadSafe< + SandboxMountPointProvider::GetFileSystemRootPathTask> { + public: + GetFileSystemRootPathTask( + scoped_refptr<base::MessageLoopProxy> file_message_loop, + const std::string& name, + FileSystemPathManager::GetRootPathCallback* callback) + : file_message_loop_(file_message_loop), + origin_message_loop_proxy_( + base::MessageLoopProxy::CreateForCurrentThread()), + name_(name), + callback_(callback) { + } + + void Start(const GURL& origin_url, + const FilePath& origin_base_path, + bool create) { + file_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, + &GetFileSystemRootPathTask::GetFileSystemRootPathOnFileThread, + origin_url, origin_base_path, create)); + } + + private: + void GetFileSystemRootPathOnFileThread( + const GURL& origin_url, + const FilePath& origin_base_path, + bool create) { + DispatchCallbackOnCallerThread( + GetFileSystemRootPathOnFileThreadHelper( + origin_url, origin_base_path, create)); + } + + void DispatchCallbackOnCallerThread(const FilePath& root_path) { + origin_message_loop_proxy_->PostTask(FROM_HERE, + NewRunnableMethod(this, &GetFileSystemRootPathTask::DispatchCallback, + root_path)); + } + + void DispatchCallback(const FilePath& root_path) { + callback_->Run(!root_path.empty(), root_path, name_); + callback_.reset(); + } + + scoped_refptr<base::MessageLoopProxy> file_message_loop_; + scoped_refptr<base::MessageLoopProxy> origin_message_loop_proxy_; + std::string name_; + scoped_ptr<FileSystemPathManager::GetRootPathCallback> callback_; +}; + +bool SandboxMountPointProvider::IsRestrictedFileName(const FilePath& filename) + const { + if (filename.value().empty()) + return false; + + if (IsWhitespace(filename.value()[filename.value().size() - 1]) || + filename.value()[filename.value().size() - 1] == '.') + return true; + + std::string filename_lower = StringToLowerASCII( + FilePathStringToASCII(filename.value())); + + for (size_t i = 0; i < arraysize(kRestrictedNames); ++i) { + // Exact match. + if (filename_lower == kRestrictedNames[i]) + return true; + // Starts with "RESTRICTED_NAME.". + if (filename_lower.find(std::string(kRestrictedNames[i]) + ".") == 0) + return true; + } + + for (size_t i = 0; i < arraysize(kRestrictedChars); ++i) { + if (filename.value().find(kRestrictedChars[i]) != + FilePath::StringType::npos) + return true; + } + + return false; +} + +void SandboxMountPointProvider::GetFileSystemRootPath( + const GURL& origin_url, fileapi::FileSystemType type, + bool create, FileSystemPathManager::GetRootPathCallback* callback_ptr) { + scoped_ptr<FileSystemPathManager::GetRootPathCallback> callback(callback_ptr); + std::string name; + FilePath origin_base_path; + + if (!GetOriginBasePathAndName(origin_url, &origin_base_path, type, &name)) { + callback->Run(false, FilePath(), std::string()); + return; + } + + scoped_refptr<GetFileSystemRootPathTask> task( + new GetFileSystemRootPathTask(file_message_loop_, + name, + callback.release())); + task->Start(origin_url, origin_base_path, create); +}; + +FilePath SandboxMountPointProvider::GetFileSystemRootPathOnFileThread( + const GURL& origin_url, FileSystemType type, bool create) { + FilePath origin_base_path; + if (!GetOriginBasePathAndName(origin_url, &origin_base_path, type, NULL)) { + return FilePath(); + } + return GetFileSystemRootPathOnFileThreadHelper( + origin_url, origin_base_path, create); +} + +// static +std::string SandboxMountPointProvider::GetOriginIdentifierFromURL( + const GURL& url) { + WebKit::WebSecurityOrigin web_security_origin = + WebKit::WebSecurityOrigin::createFromString(UTF8ToUTF16(url.spec())); + return web_security_origin.databaseIdentifier().utf8(); +} + +// static +FilePath SandboxMountPointProvider::GetFileSystemBaseDirectoryForOriginAndType( + const FilePath& base_path, const std::string& origin_identifier, + fileapi::FileSystemType type) { + if (origin_identifier.empty()) + return FilePath(); + std::string type_string = + FileSystemPathManager::GetFileSystemTypeString(type); + if (type_string.empty()) { + LOG(WARNING) << "Unknown filesystem type is requested:" << type; + return FilePath(); + } + return base_path.AppendASCII(origin_identifier) + .AppendASCII(type_string); +} + +SandboxMountPointProvider::OriginEnumerator::OriginEnumerator( + const FilePath& base_path) + : enumerator_(base_path, false /* recursive */, + file_util::FileEnumerator::DIRECTORIES) { +} + +std::string SandboxMountPointProvider::OriginEnumerator::Next() { + current_ = enumerator_.Next(); + return FilePathStringToASCII(current_.BaseName().value()); +} + +bool SandboxMountPointProvider::OriginEnumerator::HasTemporary() { + return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII( + SandboxMountPointProvider::kTemporaryName)); +} + +bool SandboxMountPointProvider::OriginEnumerator::HasPersistent() { + return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII( + SandboxMountPointProvider::kPersistentName)); +} + +bool SandboxMountPointProvider::GetOriginBasePathAndName( + const GURL& origin_url, + FilePath* origin_base_path, + FileSystemType type, + std::string* name) { + + if (path_manager_->is_incognito()) + // TODO(kinuko): return an isolated temporary directory. + return false; + + if (!path_manager_->IsAllowedScheme(origin_url)) + return false; + + std::string origin_identifier = GetOriginIdentifierFromURL(origin_url); + *origin_base_path = GetFileSystemBaseDirectoryForOriginAndType( + base_path(), origin_identifier, type); + if (origin_base_path->empty()) + return false; + + std::string type_string = + FileSystemPathManager::GetFileSystemTypeString(type); + DCHECK(!type_string.empty()); + if (name) + *name = origin_identifier + ":" + type_string; + return true; +} + +} // namespace fileapi |