// 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. #include "webkit/fileapi/isolated_file_util.h" #include #include #include "base/memory/scoped_ptr.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_operation_context.h" #include "webkit/fileapi/file_system_path.h" #include "webkit/fileapi/isolated_context.h" #include "webkit/fileapi/native_file_util.h" using base::PlatformFileError; using base::PlatformFileInfo; namespace fileapi { namespace { // Simply enumerate each path from a given paths set. // Used to enumerate top-level paths of an isolated filesystem. class SetFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { public: SetFileEnumerator(const std::vector& paths, const FilePath& root) : paths_(paths), root_(root) { path_iter_ = paths_.begin(); } virtual ~SetFileEnumerator() {} // AbstractFileEnumerator overrides. virtual FilePath Next() OVERRIDE { if (path_iter_ == paths_.end()) return FilePath(); FilePath platform_path = *path_iter_++; NativeFileUtil::GetFileInfo(platform_path, &file_info_); return root_.Append(platform_path.BaseName()); } virtual int64 Size() OVERRIDE { return file_info_.size; } virtual bool IsDirectory() OVERRIDE { return file_info_.is_directory; } virtual base::Time LastModifiedTime() OVERRIDE { return file_info_.last_modified; } virtual bool IsLink() OVERRIDE { return file_info_.is_symbolic_link; } private: std::vector paths_; std::vector::const_iterator path_iter_; FilePath root_; base::PlatformFileInfo file_info_; }; // A wrapper file enumerator which returns a virtual path of the path returned // by the wrapped enumerator. // // A virtual path is constructed as following: // virtual_path = |virtual_base_path| + relative-path-to-|platform_base_path| // // Where |virtual_base_path| is in our case the virtual top-level directory // that looks like: '/'. // // Example: // Suppose virtual_base_path is: '/CAFEBABE', // platform_base_path is: '/full/path/to/example/dir', and // a path returned by wrapped_is: '/full/path/to/example/dir/a/b/c', // Next() would return: '/CAFEBABE/dir/a/b/c'. // class PathConverterEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { public: PathConverterEnumerator( FileSystemFileUtil::AbstractFileEnumerator* wrapped, const FilePath& virtual_base_path, const FilePath& platform_base_path) : wrapped_(wrapped), virtual_base_path_(virtual_base_path), platform_base_path_(platform_base_path) {} virtual ~PathConverterEnumerator() {} // AbstractFileEnumerator overrides. virtual FilePath Next() OVERRIDE { DCHECK(wrapped_.get()); FilePath path = wrapped_->Next(); if (path.empty()) return path; FilePath virtual_path = virtual_base_path_; platform_base_path_.DirName().AppendRelativePath(path, &virtual_path); return virtual_path; } virtual int64 Size() OVERRIDE { return wrapped_->Size(); } virtual bool IsDirectory() OVERRIDE { return wrapped_->IsDirectory(); } virtual base::Time LastModifiedTime() OVERRIDE { return wrapped_->LastModifiedTime(); } virtual bool IsLink() OVERRIDE { return wrapped_->IsLink(); } private: scoped_ptr wrapped_; FilePath virtual_base_path_; FilePath platform_base_path_; }; // Recursively enumerate each path from a given paths set. class RecursiveSetFileEnumerator : public FileSystemFileUtil::AbstractFileEnumerator { public: RecursiveSetFileEnumerator(const FilePath& virtual_base_path, const std::vector& paths, const FilePath& root) : virtual_base_path_(virtual_base_path), paths_(paths), root_(root) { path_iter_ = paths_.begin(); current_enumerator_.reset( new SetFileEnumerator(paths, root)); } virtual ~RecursiveSetFileEnumerator() {} // AbstractFileEnumerator overrides. virtual FilePath Next() OVERRIDE; virtual int64 Size() OVERRIDE { DCHECK(current_enumerator_.get()); return current_enumerator_->Size(); } virtual bool IsDirectory() OVERRIDE { DCHECK(current_enumerator_.get()); return current_enumerator_->IsDirectory(); } virtual base::Time LastModifiedTime() OVERRIDE { DCHECK(current_enumerator_.get()); return current_enumerator_->LastModifiedTime(); } virtual bool IsLink() OVERRIDE { DCHECK(current_enumerator_.get()); return current_enumerator_->IsLink(); } private: FilePath virtual_base_path_; std::vector paths_; std::vector::iterator path_iter_; base::PlatformFileInfo file_info_; FilePath root_; scoped_ptr current_enumerator_; }; FilePath RecursiveSetFileEnumerator::Next() { if (current_enumerator_.get()) { FilePath path = current_enumerator_->Next(); if (!path.empty()) return path; } // We reached the end. if (path_iter_ == paths_.end()) return FilePath(); // Enumerates subdirectories of the next path. FilePath next_path = *path_iter_++; current_enumerator_.reset( new PathConverterEnumerator( NativeFileUtil::CreateFileEnumerator( next_path, true /* recursive */), virtual_base_path_, next_path)); DCHECK(current_enumerator_.get()); return current_enumerator_->Next(); } } // namespace IsolatedFileUtil::IsolatedFileUtil() { } PlatformFileError IsolatedFileUtil::CreateOrOpen( FileSystemOperationContext* context, const FileSystemPath& path, int file_flags, PlatformFile* file_handle, bool* created) { return base::PLATFORM_FILE_ERROR_SECURITY; } PlatformFileError IsolatedFileUtil::Close( FileSystemOperationContext* context, PlatformFile file_handle) { // We don't allow open thus Close won't be called. return base::PLATFORM_FILE_ERROR_SECURITY; } PlatformFileError IsolatedFileUtil::EnsureFileExists( FileSystemOperationContext* context, const FileSystemPath& path, bool* created) { return base::PLATFORM_FILE_ERROR_SECURITY; } PlatformFileError IsolatedFileUtil::CreateDirectory( FileSystemOperationContext* context, const FileSystemPath& path, bool exclusive, bool recursive) { return base::PLATFORM_FILE_ERROR_SECURITY; } PlatformFileError IsolatedFileUtil::GetFileInfo( FileSystemOperationContext* context, const FileSystemPath& path, PlatformFileInfo* file_info, FilePath* platform_path) { DCHECK(file_info); std::string filesystem_id; FilePath root_unused, cracked_path; if (!IsolatedContext::GetInstance()->CrackIsolatedPath( path.internal_path(), &filesystem_id, &root_unused, &cracked_path)) return base::PLATFORM_FILE_ERROR_SECURITY; if (cracked_path.empty()) { // The root directory case. // For now we leave three time fields (modified/accessed/creation time) // NULL as it is not really clear what to be set for this virtual directory. // TODO(kinuko): Maybe we want to set the time when this filesystem is // created (i.e. when the files/directories are dropped). file_info->is_directory = true; file_info->is_symbolic_link = false; file_info->size = 0; return base::PLATFORM_FILE_OK; } base::PlatformFileError error = NativeFileUtil::GetFileInfo(cracked_path, file_info); if (error == base::PLATFORM_FILE_OK) *platform_path = cracked_path; return error; } FileSystemFileUtil::AbstractFileEnumerator* IsolatedFileUtil::CreateFileEnumerator( FileSystemOperationContext* context, const FileSystemPath& root, bool recursive) { std::string filesystem_id; FilePath root_path, cracked_path; if (!IsolatedContext::GetInstance()->CrackIsolatedPath( root.internal_path(), &filesystem_id, &root_path, &cracked_path)) return NULL; FilePath virtual_base_path = IsolatedContext::GetInstance()->CreateVirtualPath(filesystem_id, FilePath()); if (!cracked_path.empty()) { return new PathConverterEnumerator( NativeFileUtil::CreateFileEnumerator(cracked_path, recursive), virtual_base_path, root_path); } // Root path case. std::vector toplevels; IsolatedContext::GetInstance()->GetTopLevelPaths(filesystem_id, &toplevels); if (!recursive) return new SetFileEnumerator(toplevels, root.internal_path()); return new RecursiveSetFileEnumerator( virtual_base_path, toplevels, root.internal_path()); } PlatformFileError IsolatedFileUtil::GetLocalFilePath( FileSystemOperationContext* context, const FileSystemPath& file_system_path, FilePath* local_file_path) { if (GetPlatformPath(file_system_path, local_file_path)) return base::PLATFORM_FILE_OK; return base::PLATFORM_FILE_ERROR_SECURITY; } PlatformFileError IsolatedFileUtil::Touch( FileSystemOperationContext* context, const FileSystemPath& path, const base::Time& last_access_time, const base::Time& last_modified_time) { return base::PLATFORM_FILE_ERROR_SECURITY; } PlatformFileError IsolatedFileUtil::Truncate( FileSystemOperationContext* context, const FileSystemPath& path, int64 length) { return base::PLATFORM_FILE_ERROR_SECURITY; } bool IsolatedFileUtil::PathExists( FileSystemOperationContext* context, const FileSystemPath& path) { FilePath platform_path; if (!GetPlatformPath(path, &platform_path)) return false; if (platform_path.empty()) { // The root directory case. return true; } return NativeFileUtil::PathExists(platform_path); } bool IsolatedFileUtil::DirectoryExists( FileSystemOperationContext* context, const FileSystemPath& path) { FilePath platform_path; if (!GetPlatformPath(path, &platform_path)) return false; if (platform_path.empty()) { // The root directory case. return true; } return NativeFileUtil::DirectoryExists(platform_path); } bool IsolatedFileUtil::IsDirectoryEmpty( FileSystemOperationContext* context, const FileSystemPath& path) { std::string filesystem_id; FilePath platform_path; if (!GetPlatformPath(path, &platform_path)) return false; if (platform_path.empty()) { // The root directory case. std::vector toplevels; bool success = IsolatedContext::GetInstance()->GetTopLevelPaths( filesystem_id, &toplevels); DCHECK(success); return toplevels.empty(); } return NativeFileUtil::IsDirectoryEmpty(platform_path); } PlatformFileError IsolatedFileUtil::CopyOrMoveFile( FileSystemOperationContext* context, const FileSystemPath& src_path, const FileSystemPath& dest_path, bool copy) { return base::PLATFORM_FILE_ERROR_SECURITY; } PlatformFileError IsolatedFileUtil::CopyInForeignFile( FileSystemOperationContext* context, const FilePath& src_file_path, const FileSystemPath& dest_path) { return base::PLATFORM_FILE_ERROR_SECURITY; } PlatformFileError IsolatedFileUtil::DeleteFile( FileSystemOperationContext* context, const FileSystemPath& path) { return base::PLATFORM_FILE_ERROR_SECURITY; } PlatformFileError IsolatedFileUtil::DeleteSingleDirectory( FileSystemOperationContext* context, const FileSystemPath& path) { return base::PLATFORM_FILE_ERROR_SECURITY; } bool IsolatedFileUtil::GetPlatformPath(const FileSystemPath& virtual_path, FilePath* platform_path) const { DCHECK(platform_path); std::string filesystem_id; FilePath root_path; if (!IsolatedContext::GetInstance()->CrackIsolatedPath( virtual_path.internal_path(), &filesystem_id, &root_path, platform_path)) return false; return true; } } // namespace