| // Copyright (c) 2012 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 STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_H_ |
| #define STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_H_ |
| |
| #include <stdint.h> |
| |
| #include <map> |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "base/callback_forward.h" |
| #include "base/files/file.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util_proxy.h" |
| #include "base/macros.h" |
| #include "storage/browser/blob/shareable_file_reference.h" |
| #include "storage/browser/fileapi/file_system_file_util.h" |
| #include "storage/browser/fileapi/file_system_url.h" |
| #include "storage/browser/fileapi/sandbox_directory_database.h" |
| #include "storage/browser/fileapi/sandbox_file_system_backend_delegate.h" |
| #include "storage/browser/storage_browser_export.h" |
| #include "storage/common/fileapi/file_system_types.h" |
| |
| namespace base { |
| class SequencedTaskRunner; |
| class TimeTicks; |
| } |
| |
| namespace content { |
| class ObfuscatedFileUtilTest; |
| class QuotaBackendImplTest; |
| } |
| |
| namespace storage { |
| class SpecialStoragePolicy; |
| } |
| |
| class GURL; |
| |
| namespace storage { |
| |
| class FileSystemOperationContext; |
| class SandboxOriginDatabaseInterface; |
| class TimedTaskHelper; |
| |
| // This file util stores directory information in LevelDB to obfuscate |
| // and to neutralize virtual file paths given by arbitrary apps. |
| // Files are stored with two-level isolation: per-origin and per-type. |
| // The isolation is done by storing data in separate directory partitions. |
| // For example, a file in Temporary file system for origin 'www.example.com' |
| // is stored in a different partition for a file in Persistent file system |
| // for the same origin, or for Temporary file system for another origin. |
| // |
| // * Per-origin directory name information is stored in a separate LevelDB, |
| // which is maintained by SandboxOriginDatabase. |
| // * Per-type directory name information is given by |
| // GetTypeStringForURLCallback that is given in CTOR. |
| // We use a small static mapping (e.g. 't' for Temporary type) for |
| // regular sandbox filesystems. |
| // |
| // The overall implementation philosophy of this class is that partial failures |
| // should leave us with an intact database; we'd prefer to leak the occasional |
| // backing file than have a database entry whose backing file is missing. When |
| // doing FSCK operations, if you find a loose backing file with no reference, |
| // you may safely delete it. |
| // |
| // This class must be deleted on the FILE thread, because that's where |
| // DropDatabases needs to be called. |
| class STORAGE_EXPORT ObfuscatedFileUtil : public FileSystemFileUtil { |
| public: |
| // Origin enumerator interface. |
| // An instance of this interface is assumed to be called on the file thread. |
| class AbstractOriginEnumerator { |
| public: |
| virtual ~AbstractOriginEnumerator() {} |
| |
| // Returns the next origin. Returns empty if there are no more origins. |
| virtual GURL Next() = 0; |
| |
| // Returns the current origin's information. |
| // |type_string| must be ascii string. |
| virtual bool HasTypeDirectory(const std::string& type_string) const = 0; |
| }; |
| |
| typedef base::Callback<std::string(const FileSystemURL&)> |
| GetTypeStringForURLCallback; |
| |
| // |get_type_string_for_url| is user-defined callback that should return |
| // a type string for the given FileSystemURL. The type string is used |
| // to provide per-type isolation in the sandboxed filesystem directory. |
| // Note that this method is called on file_task_runner. |
| // |
| // |known_type_strings| are known type string names that this file system |
| // should care about. |
| // This info is used to determine whether we could delete the entire |
| // origin directory or not in DeleteDirectoryForOriginAndType. If no directory |
| // for any known type exists the origin directory may get deleted when |
| // one origin/type pair is deleted. |
| // |
| ObfuscatedFileUtil(storage::SpecialStoragePolicy* special_storage_policy, |
| const base::FilePath& file_system_directory, |
| leveldb::Env* env_override, |
| base::SequencedTaskRunner* file_task_runner, |
| const GetTypeStringForURLCallback& get_type_string_for_url, |
| const std::set<std::string>& known_type_strings, |
| SandboxFileSystemBackendDelegate* sandbox_delegate); |
| ~ObfuscatedFileUtil() override; |
| |
| // FileSystemFileUtil overrides. |
| base::File CreateOrOpen(FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| int file_flags) override; |
| base::File::Error EnsureFileExists(FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| bool* created) override; |
| base::File::Error CreateDirectory(FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| bool exclusive, |
| bool recursive) override; |
| base::File::Error GetFileInfo(FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| base::File::Info* file_info, |
| base::FilePath* platform_file) override; |
| std::unique_ptr<AbstractFileEnumerator> CreateFileEnumerator( |
| FileSystemOperationContext* context, |
| const FileSystemURL& root_url) override; |
| base::File::Error GetLocalFilePath(FileSystemOperationContext* context, |
| const FileSystemURL& file_system_url, |
| base::FilePath* local_path) override; |
| base::File::Error Touch(FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| const base::Time& last_access_time, |
| const base::Time& last_modified_time) override; |
| base::File::Error Truncate(FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| int64_t length) override; |
| base::File::Error CopyOrMoveFile(FileSystemOperationContext* context, |
| const FileSystemURL& src_url, |
| const FileSystemURL& dest_url, |
| CopyOrMoveOption option, |
| bool copy) override; |
| base::File::Error CopyInForeignFile(FileSystemOperationContext* context, |
| const base::FilePath& src_file_path, |
| const FileSystemURL& dest_url) override; |
| base::File::Error DeleteFile(FileSystemOperationContext* context, |
| const FileSystemURL& url) override; |
| base::File::Error DeleteDirectory(FileSystemOperationContext* context, |
| const FileSystemURL& url) override; |
| storage::ScopedFile CreateSnapshotFile( |
| FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| base::File::Error* error, |
| base::File::Info* file_info, |
| base::FilePath* platform_path) override; |
| |
| // Same as the other CreateFileEnumerator, but with recursive support. |
| std::unique_ptr<AbstractFileEnumerator> CreateFileEnumerator( |
| FileSystemOperationContext* context, |
| const FileSystemURL& root_url, |
| bool recursive); |
| |
| // Returns true if the directory |url| is empty. |
| bool IsDirectoryEmpty( |
| FileSystemOperationContext* context, |
| const FileSystemURL& url); |
| |
| // Gets the topmost directory specific to this origin and type. This will |
| // contain both the directory database's files and all the backing file |
| // subdirectories. |
| // Returns the topmost origin directory if |type_string| is empty. |
| // Returns an empty path if the directory is undefined. |
| // If the directory is defined, it will be returned, even if |
| // there is a file system error (e.g. the directory doesn't exist on disk and |
| // |create| is false). Callers should always check |error_code| to make sure |
| // the returned path is usable. |
| base::FilePath GetDirectoryForOriginAndType( |
| const GURL& origin, |
| const std::string& type_string, |
| bool create, |
| base::File::Error* error_code); |
| |
| // Deletes the topmost directory specific to this origin and type. This will |
| // delete its directory database. |
| // Deletes the topmost origin directory if |type_string| is empty. |
| bool DeleteDirectoryForOriginAndType( |
| const GURL& origin, |
| const std::string& type_string); |
| |
| // Frees resources used by an origin's filesystem. |
| void CloseFileSystemForOriginAndType(const GURL& origin, |
| const std::string& type_string); |
| |
| // This method and all methods of its returned class must be called only on |
| // the FILE thread. The caller is responsible for deleting the returned |
| // object. |
| AbstractOriginEnumerator* CreateOriginEnumerator(); |
| |
| // Deletes a directory database from the database list in the ObfuscatedFSFU |
| // and destroys the database on the disk. |
| void DestroyDirectoryDatabase(const GURL& origin, |
| const std::string& type_string); |
| |
| // Computes a cost for storing a given file in the obfuscated FSFU. |
| // As the cost of a file is independent of the cost of its parent directories, |
| // this ignores all but the BaseName of the supplied path. In order to |
| // compute the cost of adding a multi-segment directory recursively, call this |
| // on each path segment and add the results. |
| static int64_t ComputeFilePathCost(const base::FilePath& path); |
| |
| // Tries to prepopulate directory database for the given type strings. |
| // This tries from the first one in the given type_strings and stops |
| // once it succeeds to do so for one database (i.e. it prepopulates |
| // at most one database). |
| void MaybePrepopulateDatabase( |
| const std::vector<std::string>& type_strings_to_prepopulate); |
| |
| private: |
| typedef SandboxDirectoryDatabase::FileId FileId; |
| typedef SandboxDirectoryDatabase::FileInfo FileInfo; |
| |
| friend class ObfuscatedFileEnumerator; |
| friend class content::ObfuscatedFileUtilTest; |
| friend class content::QuotaBackendImplTest; |
| |
| // Helper method to create an obfuscated file util for regular |
| // (temporary, persistent) file systems. Used only for testing. |
| // Note: this is implemented in sandbox_file_system_backend_delegate.cc. |
| static ObfuscatedFileUtil* CreateForTesting( |
| storage::SpecialStoragePolicy* special_storage_policy, |
| const base::FilePath& file_system_directory, |
| leveldb::Env* env_override, |
| base::SequencedTaskRunner* file_task_runner); |
| |
| base::FilePath GetDirectoryForURL( |
| const FileSystemURL& url, |
| bool create, |
| base::File::Error* error_code); |
| |
| // This just calls get_type_string_for_url_ callback that is given in ctor. |
| std::string CallGetTypeStringForURL(const FileSystemURL& url); |
| |
| base::File::Error GetFileInfoInternal( |
| SandboxDirectoryDatabase* db, |
| FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| FileId file_id, |
| FileInfo* local_info, |
| base::File::Info* file_info, |
| base::FilePath* platform_file_path); |
| |
| // Creates a new file, both the underlying backing file and the entry in the |
| // database. |dest_file_info| is an in-out parameter. Supply the name and |
| // parent_id; data_path is ignored. On success, data_path will |
| // always be set to the relative path [from the root of the type-specific |
| // filesystem directory] of a NEW backing file. Returns the new file. |
| base::File CreateAndOpenFile( |
| FileSystemOperationContext* context, |
| const FileSystemURL& dest_url, |
| FileInfo* dest_file_info, |
| int file_flags); |
| |
| // The same as CreateAndOpenFile except that a file is not returned and if a |
| // path is provided in |source_path|, it will be used as a source from which |
| // to COPY data. |
| base::File::Error CreateFile( |
| FileSystemOperationContext* context, |
| const base::FilePath& source_file_path, |
| const FileSystemURL& dest_url, |
| FileInfo* dest_file_info); |
| |
| // Updates |db| and |dest_file_info| at the end of creating a new file. |
| base::File::Error CommitCreateFile( |
| const base::FilePath& root, |
| const base::FilePath& local_path, |
| SandboxDirectoryDatabase* db, |
| FileInfo* dest_file_info); |
| |
| // This converts from a relative path [as is stored in the FileInfo.data_path |
| // field] to an absolute platform path that can be given to the native |
| // filesystem. |
| base::FilePath DataPathToLocalPath( |
| const FileSystemURL& url, |
| const base::FilePath& data_file_path); |
| |
| std::string GetDirectoryDatabaseKey(const GURL& origin, |
| const std::string& type_string); |
| |
| // This returns NULL if |create| flag is false and a filesystem does not |
| // exist for the given |url|. |
| // For read operations |create| should be false. |
| SandboxDirectoryDatabase* GetDirectoryDatabase(const FileSystemURL& url, |
| bool create); |
| |
| // Gets the topmost directory specific to this origin. This will |
| // contain both the filesystem type subdirectories. |
| base::FilePath GetDirectoryForOrigin(const GURL& origin, |
| bool create, |
| base::File::Error* error_code); |
| |
| void InvalidateUsageCache(FileSystemOperationContext* context, |
| const GURL& origin, |
| FileSystemType type); |
| |
| void MarkUsed(); |
| void DropDatabases(); |
| |
| // Initializes the origin database. |origin_hint| may be used as a hint |
| // for initializing database if it's not empty. |
| bool InitOriginDatabase(const GURL& origin_hint, bool create); |
| |
| base::File::Error GenerateNewLocalPath( |
| SandboxDirectoryDatabase* db, |
| FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| base::FilePath* root, |
| base::FilePath* local_path); |
| |
| base::File CreateOrOpenInternal( |
| FileSystemOperationContext* context, |
| const FileSystemURL& url, |
| int file_flags); |
| |
| bool HasIsolatedStorage(const GURL& origin); |
| |
| typedef std::map<std::string, SandboxDirectoryDatabase*> DirectoryMap; |
| DirectoryMap directories_; |
| std::unique_ptr<SandboxOriginDatabaseInterface> origin_database_; |
| scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_; |
| base::FilePath file_system_directory_; |
| leveldb::Env* env_override_; |
| |
| // Used to delete database after a certain period of inactivity. |
| int64_t db_flush_delay_seconds_; |
| |
| scoped_refptr<base::SequencedTaskRunner> file_task_runner_; |
| std::unique_ptr<TimedTaskHelper> timer_; |
| |
| GetTypeStringForURLCallback get_type_string_for_url_; |
| std::set<std::string> known_type_strings_; |
| |
| // Not owned. |
| SandboxFileSystemBackendDelegate* sandbox_delegate_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtil); |
| }; |
| |
| } // namespace storage |
| |
| #endif // STORAGE_BROWSER_FILEAPI_OBFUSCATED_FILE_UTIL_H_ |