| Index: webkit/fileapi/file_system_path_manager.cc
|
| ===================================================================
|
| --- webkit/fileapi/file_system_path_manager.cc (revision 79142)
|
| +++ webkit/fileapi/file_system_path_manager.cc (working copy)
|
| @@ -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.
|
|
|
| @@ -14,171 +14,33 @@
|
| #include "base/string_util.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/WebFileSystem.h"
|
| -#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
|
| +#include "webkit/fileapi/file_system_util.h"
|
| +#include "webkit/fileapi/sandbox_mount_point_provider.h"
|
| #include "webkit/glue/webkit_glue.h"
|
|
|
| // We use some of WebKit types for conversions between origin identifiers
|
| // and origin URLs.
|
| using WebKit::WebFileSystem;
|
| -using WebKit::WebSecurityOrigin;
|
| -using WebKit::WebString;
|
|
|
| using base::PlatformFileError;
|
|
|
| -namespace fileapi {
|
| -
|
| -const FilePath::CharType FileSystemPathManager::kFileSystemDirectory[] =
|
| - FILE_PATH_LITERAL("FileSystem");
|
| -
|
| -const char FileSystemPathManager::kPersistentName[] = "Persistent";
|
| -const char FileSystemPathManager::kTemporaryName[] = "Temporary";
|
| -
|
| -static const FilePath::CharType kFileSystemUniqueNamePrefix[] =
|
| - FILE_PATH_LITERAL("chrome-");
|
| -static const int kFileSystemUniqueLength = 16;
|
| -static const unsigned kFileSystemUniqueDirectoryNameLength =
|
| - kFileSystemUniqueLength + arraysize(kFileSystemUniqueNamePrefix) - 1;
|
| -
|
| -namespace {
|
| -
|
| -// 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;
|
| -}
|
| -
|
| static const char kExtensionScheme[] = "chrome-extension";
|
|
|
| -} // anonymous namespace
|
| +namespace fileapi {
|
|
|
| -class FileSystemPathManager::GetFileSystemRootPathTask
|
| - : public base::RefCountedThreadSafe<
|
| - FileSystemPathManager::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& base_path,
|
| - bool create) {
|
| - FilePath root;
|
| - if (ReadOriginDirectory(base_path, origin_url, &root)) {
|
| - DispatchCallbackOnCallerThread(root);
|
| - return;
|
| - }
|
| -
|
| - if (!create) {
|
| - DispatchCallbackOnCallerThread(FilePath());
|
| - return;
|
| - }
|
| -
|
| - // Creates the root directory.
|
| - root = base_path.Append(CreateUniqueDirectoryName(origin_url));
|
| - if (!file_util::CreateDirectory(root)) {
|
| - DispatchCallbackOnCallerThread(FilePath());
|
| - return;
|
| - }
|
| - DispatchCallbackOnCallerThread(root);
|
| - }
|
| -
|
| - 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();
|
| - }
|
| -
|
| - 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_;
|
| -};
|
| -
|
| FileSystemPathManager::FileSystemPathManager(
|
| scoped_refptr<base::MessageLoopProxy> file_message_loop,
|
| const FilePath& profile_path,
|
| bool is_incognito,
|
| bool allow_file_access_from_files)
|
| - : file_message_loop_(file_message_loop),
|
| - base_path_(profile_path.Append(kFileSystemDirectory)),
|
| - is_incognito_(is_incognito),
|
| - allow_file_access_from_files_(allow_file_access_from_files) {
|
| + : is_incognito_(is_incognito),
|
| + allow_file_access_from_files_(allow_file_access_from_files),
|
| + sandbox_provider_(
|
| + new SandboxMountPointProvider(
|
| + ALLOW_THIS_IN_INITIALIZER_LIST(this),
|
| + file_message_loop,
|
| + profile_path)) {
|
| }
|
|
|
| FileSystemPathManager::~FileSystemPathManager() {}
|
| @@ -186,95 +48,88 @@
|
| void FileSystemPathManager::GetFileSystemRootPath(
|
| const GURL& origin_url, fileapi::FileSystemType type,
|
| bool create, GetRootPathCallback* callback_ptr) {
|
| - scoped_ptr<GetRootPathCallback> callback(callback_ptr);
|
| - if (is_incognito_) {
|
| - // TODO(kinuko): return an isolated temporary directory.
|
| - callback->Run(false, FilePath(), std::string());
|
| - return;
|
| - }
|
|
|
| - if (!IsAllowedScheme(origin_url)) {
|
| - callback->Run(false, FilePath(), std::string());
|
| - return;
|
| + switch (type) {
|
| + case kFileSystemTypeTemporary:
|
| + case kFileSystemTypePersistent:
|
| + sandbox_provider_->GetFileSystemRootPath(
|
| + origin_url, type, create, callback_ptr);
|
| + break;
|
| + case kFileSystemTypeUnknown:
|
| + default:
|
| + NOTREACHED();
|
| + callback_ptr->Run(false, FilePath(), std::string());
|
| }
|
| +}
|
|
|
| - std::string origin_identifier = GetOriginIdentifierFromURL(origin_url);
|
| - FilePath origin_base_path = GetFileSystemBaseDirectoryForOriginAndType(
|
| - base_path(), origin_identifier, type);
|
| - if (origin_base_path.empty()) {
|
| - callback->Run(false, FilePath(), std::string());
|
| - return;
|
| +FilePath FileSystemPathManager::GetFileSystemRootPathOnFileThread(
|
| + const GURL& origin_url, FileSystemType type, bool create) {
|
| + switch (type) {
|
| + case kFileSystemTypeTemporary:
|
| + case kFileSystemTypePersistent:
|
| + return sandbox_provider_->GetFileSystemRootPathOnFileThread(
|
| + origin_url, type, create);
|
| + break;
|
| + case kFileSystemTypeUnknown:
|
| + default:
|
| + NOTREACHED();
|
| + return FilePath();
|
| }
|
| -
|
| - std::string type_string = GetFileSystemTypeString(type);
|
| - DCHECK(!type_string.empty());
|
| -
|
| - scoped_refptr<GetFileSystemRootPathTask> task(
|
| - new GetFileSystemRootPathTask(file_message_loop_,
|
| - origin_identifier + ":" + type_string,
|
| - callback.release()));
|
| - task->Start(origin_url, origin_base_path, create);
|
| }
|
|
|
| bool FileSystemPathManager::CrackFileSystemPath(
|
| const FilePath& path, GURL* origin_url, FileSystemType* type,
|
| FilePath* virtual_path) const {
|
| - // Any paths that includes parent references are considered invalid.
|
| - if (path.ReferencesParent())
|
| - return false;
|
| + // TODO(ericu):
|
| + // Paths come in here [for now] as a URL, followed by a virtual path in
|
| + // platform format. For example, on Windows, this will look like
|
| + // filesystem:http://www.example.com/temporary/\path\to\file.txt.
|
| + // A potentially dangerous malicious path on Windows might look like:
|
| + // filesystem:http://www.example.com/temporary/foo/../../\path\to\file.txt.
|
| + // This code is ugly, but will get cleaned up as we fix the calling side.
|
| + // Eventually there won't be a distinction between a filesystem path and a
|
| + // filesystem URL--they'll all be URLs.
|
| + // We should be passing these to WebKit as string, not FilePath, for ease of
|
| + // manipulation, or possibly as GURL/KURL.
|
|
|
| - // The path should be a child of the profile FileSystem path.
|
| - FilePath relative;
|
| - if (!base_path_.AppendRelativePath(path, &relative))
|
| - return false;
|
| + std::string path_as_string;
|
| +#ifdef OS_WIN
|
| + path_as_string = WideToUTF8(path.value());
|
| +#else
|
| + path_as_string = path.value();
|
| +#endif
|
| + GURL path_as_url(path_as_string);
|
|
|
| - // The relative path from the profile FileSystem path should contain
|
| - // at least three components, one for storage identifier, one for type
|
| - // and one for the 'unique' part.
|
| - std::vector<FilePath::StringType> components;
|
| - relative.GetComponents(&components);
|
| - if (components.size() < 3)
|
| + FilePath local_path;
|
| + GURL local_url;
|
| + FileSystemType local_type;
|
| + if (!CrackFileSystemURL(path_as_url, &local_url, &local_type, &local_path))
|
| return false;
|
|
|
| - // The second component of the relative path to the root directory
|
| - // must be kPersistent or kTemporary.
|
| - if (!IsStringASCII(components[1]))
|
| - return false;
|
| +#if defined(FILE_PATH_USES_WIN_SEPARATORS)
|
| + // TODO(ericu): This puts the separators back to windows-standard; they come
|
| + // out of the above code as '/' no matter the platform. Long-term, we'll
|
| + // want to let the underlying FileSystemFileUtil implementation do this part,
|
| + // since they won't all need it.
|
| + local_path = local_path.NormalizeWindowsPathSeparators();
|
| +#endif
|
|
|
| - std::string ascii_type_component = FilePathStringToASCII(components[1]);
|
| - FileSystemType cracked_type = kFileSystemTypeUnknown;
|
| - if (ascii_type_component == kPersistentName)
|
| - cracked_type = kFileSystemTypePersistent;
|
| - else if (ascii_type_component == kTemporaryName)
|
| - cracked_type = kFileSystemTypeTemporary;
|
| - else
|
| - return false;
|
| + // Any paths that include parent references are considered invalid.
|
| + // These should have been taken care of in CrackFileSystemURL.
|
| + DCHECK(!local_path.ReferencesParent());
|
|
|
| - DCHECK(cracked_type != kFileSystemTypeUnknown);
|
| -
|
| - // The given |path| seems valid. Populates the |origin_url|, |type|
|
| + // The given |local_path| seems valid. Populates the |origin_url|, |type|
|
| // and |virtual_path| if they are given.
|
|
|
| if (origin_url) {
|
| - WebSecurityOrigin web_security_origin =
|
| - WebSecurityOrigin::createFromDatabaseIdentifier(
|
| - webkit_glue::FilePathStringToWebString(components[0]));
|
| - *origin_url = GURL(web_security_origin.toString());
|
| -
|
| - // We need this work-around for file:/// URIs as
|
| - // createFromDatabaseIdentifier returns empty origin_url for them.
|
| - if (allow_file_access_from_files_ && origin_url->spec().empty() &&
|
| - components[0].find(FILE_PATH_LITERAL("file")) == 0)
|
| - *origin_url = GURL("file:///");
|
| + *origin_url = local_url;
|
| }
|
|
|
| if (type)
|
| - *type = cracked_type;
|
| + *type = local_type;
|
|
|
| if (virtual_path) {
|
| - virtual_path->clear();
|
| - for (size_t i = 3; i < components.size(); ++i)
|
| - *virtual_path = virtual_path->Append(components[i]);
|
| + *virtual_path = local_path;
|
| }
|
|
|
| return true;
|
| @@ -289,89 +144,29 @@
|
| }
|
|
|
| // static
|
| -bool FileSystemPathManager::IsRestrictedFileName(const FilePath& filename) {
|
| - 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;
|
| -}
|
| -
|
| -// static
|
| std::string FileSystemPathManager::GetFileSystemTypeString(
|
| fileapi::FileSystemType type) {
|
| if (type == fileapi::kFileSystemTypeTemporary)
|
| - return fileapi::FileSystemPathManager::kTemporaryName;
|
| + return fileapi::SandboxMountPointProvider::kTemporaryName;
|
| else if (type == fileapi::kFileSystemTypePersistent)
|
| - return fileapi::FileSystemPathManager::kPersistentName;
|
| + return fileapi::SandboxMountPointProvider::kPersistentName;
|
| return std::string();
|
| }
|
|
|
| -// static
|
| -std::string FileSystemPathManager::GetOriginIdentifierFromURL(
|
| - const GURL& url) {
|
| - WebKit::WebSecurityOrigin web_security_origin =
|
| - WebKit::WebSecurityOrigin::createFromString(UTF8ToUTF16(url.spec()));
|
| - return web_security_origin.databaseIdentifier().utf8();
|
| -}
|
| -
|
| -// static
|
| -FilePath FileSystemPathManager::GetFileSystemBaseDirectoryForOriginAndType(
|
| - const FilePath& base_path, const std::string& origin_identifier,
|
| - fileapi::FileSystemType type) {
|
| - if (origin_identifier.empty())
|
| - return FilePath();
|
| - std::string type_string = GetFileSystemTypeString(type);
|
| - if (type_string.empty()) {
|
| - LOG(WARNING) << "Unknown filesystem type is requested:" << type;
|
| - return FilePath();
|
| +// Checks if a given |name| contains any restricted names/chars in it.
|
| +bool FileSystemPathManager::IsRestrictedFileName(
|
| + FileSystemType type, const FilePath& filename) {
|
| + switch (type) {
|
| + case kFileSystemTypeTemporary:
|
| + case kFileSystemTypePersistent:
|
| + return sandbox_provider_->IsRestrictedFileName(filename);
|
| + case kFileSystemTypeUnknown:
|
| + default:
|
| + NOTREACHED();
|
| + return true;
|
| }
|
| - return base_path.AppendASCII(origin_identifier)
|
| - .AppendASCII(type_string);
|
| }
|
|
|
| -FileSystemPathManager::OriginEnumerator::OriginEnumerator(
|
| - const FilePath& base_path)
|
| - : enumerator_(base_path, false /* recursive */,
|
| - file_util::FileEnumerator::DIRECTORIES) {
|
| -}
|
| -
|
| -std::string FileSystemPathManager::OriginEnumerator::Next() {
|
| - current_ = enumerator_.Next();
|
| - return FilePathStringToASCII(current_.BaseName().value());
|
| -}
|
| -
|
| -bool FileSystemPathManager::OriginEnumerator::HasTemporary() {
|
| - return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII(
|
| - FileSystemPathManager::kTemporaryName));
|
| -}
|
| -
|
| -bool FileSystemPathManager::OriginEnumerator::HasPersistent() {
|
| - return !current_.empty() && file_util::DirectoryExists(current_.AppendASCII(
|
| - FileSystemPathManager::kPersistentName));
|
| -}
|
| -
|
| } // namespace fileapi
|
|
|
| COMPILE_ASSERT(int(WebFileSystem::TypeTemporary) == \
|
|
|