diff options
Diffstat (limited to 'webkit/fileapi/file_system_path_manager.cc')
-rw-r--r-- | webkit/fileapi/file_system_path_manager.cc | 373 |
1 files changed, 84 insertions, 289 deletions
diff --git a/webkit/fileapi/file_system_path_manager.cc b/webkit/fileapi/file_system_path_manager.cc index 61aa49e..64f3274 100644 --- a/webkit/fileapi/file_system_path_manager.cc +++ b/webkit/fileapi/file_system_path_manager.cc @@ -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 - -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_; -}; +namespace fileapi { 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 @@ FileSystemPathManager::~FileSystemPathManager() {} 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; - - // The path should be a child of the profile FileSystem path. - FilePath relative; - if (!base_path_.AppendRelativePath(path, &relative)) - return false; - - // 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) - 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. + + 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 second component of the relative path to the root directory - // must be kPersistent or kTemporary. - if (!IsStringASCII(components[1])) + FilePath local_path; + GURL local_url; + FileSystemType local_type; + if (!CrackFileSystemURL(path_as_url, &local_url, &local_type, &local_path)) return false; - 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; +#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 - DCHECK(cracked_type != kFileSystemTypeUnknown); + // Any paths that include parent references are considered invalid. + // These should have been taken care of in CrackFileSystemURL. + DCHECK(!local_path.ReferencesParent()); - // 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,87 +144,27 @@ bool FileSystemPathManager::IsAllowedScheme(const GURL& url) const { } // 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 |