// 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/file_system_operation.h" #include "base/bind.h" #include "base/time.h" #include "base/utf_string_conversions.h" #include "net/base/escape.h" #include "net/url_request/url_request_context.h" #include "webkit/fileapi/file_system_callback_dispatcher.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_file_util_proxy.h" #include "webkit/fileapi/file_system_operation_context.h" #include "webkit/fileapi/file_system_path_manager.h" #include "webkit/fileapi/file_system_quota_util.h" #include "webkit/fileapi/file_system_types.h" #include "webkit/fileapi/file_system_util.h" #include "webkit/fileapi/file_writer_delegate.h" #include "webkit/fileapi/local_file_util.h" #include "webkit/fileapi/quota_file_util.h" #include "webkit/quota/quota_types.h" namespace fileapi { class FileSystemOperation::ScopedQuotaUtilHelper { public: ScopedQuotaUtilHelper(FileSystemContext* context, const GURL& origin_url, FileSystemType type); ~ScopedQuotaUtilHelper(); private: FileSystemQuotaUtil* quota_util_; const GURL& origin_url_; FileSystemType type_; DISALLOW_COPY_AND_ASSIGN(ScopedQuotaUtilHelper); }; FileSystemOperation::ScopedQuotaUtilHelper::ScopedQuotaUtilHelper( FileSystemContext* context, const GURL& origin_url, FileSystemType type) : origin_url_(origin_url), type_(type) { DCHECK(context); DCHECK(type != kFileSystemTypeUnknown); quota_util_ = context->GetQuotaUtil(type_); if (quota_util_) { DCHECK(quota_util_->proxy()); quota_util_->proxy()->StartUpdateOrigin(origin_url_, type_); } } FileSystemOperation::ScopedQuotaUtilHelper::~ScopedQuotaUtilHelper() { if (quota_util_) { DCHECK(quota_util_->proxy()); quota_util_->proxy()->EndUpdateOrigin(origin_url_, type_); } } FileSystemOperation::FileSystemOperation( FileSystemCallbackDispatcher* dispatcher, scoped_refptr proxy, FileSystemContext* file_system_context) : proxy_(proxy), dispatcher_(dispatcher), operation_context_(file_system_context, NULL) { #ifndef NDEBUG pending_operation_ = kOperationNone; #endif } FileSystemOperation::~FileSystemOperation() { if (file_writer_delegate_.get()) { FileSystemOperationContext* c = new FileSystemOperationContext(operation_context_); base::FileUtilProxy::RelayClose( proxy_, base::Bind(&FileSystemFileUtil::Close, base::Unretained(c->src_file_util()), base::Owned(c)), file_writer_delegate_->file(), base::FileUtilProxy::StatusCallback()); } } void FileSystemOperation::OpenFileSystem( const GURL& origin_url, fileapi::FileSystemType type, bool create) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = static_cast( kOperationOpenFileSystem); #endif DCHECK(file_system_context()); operation_context_.set_src_origin_url(origin_url); operation_context_.set_src_type(type); // TODO(ericu): We don't really need to make this call if !create. // Also, in the future we won't need it either way, as long as we do all // permission+quota checks beforehand. We only need it now because we have to // create an unpredictable directory name. Without that, we could lazily // create the root later on the first filesystem write operation, and just // return GetFileSystemRootURI() here. file_system_context()->path_manager()->ValidateFileSystemRootAndGetURL( origin_url, type, create, base::Bind(&FileSystemOperation::DidGetRootPath, base::Owned(this))); } void FileSystemOperation::CreateFile(const GURL& path, bool exclusive) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationCreateFile; #endif if (!SetupSrcContextForWrite(path, true)) { delete this; return; } GetUsageAndQuotaThenCallback( operation_context_.src_origin_url(), base::Bind(&FileSystemOperation::DelayedCreateFileForQuota, base::Unretained(this), exclusive)); } void FileSystemOperation::DelayedCreateFileForQuota( bool exclusive, quota::QuotaStatusCode status, int64 usage, int64 quota) { operation_context_.set_allowed_bytes_growth(quota - usage); quota_util_helper_.reset(new ScopedQuotaUtilHelper( file_system_context(), operation_context_.src_origin_url(), operation_context_.src_type())); FileSystemFileUtilProxy::RelayEnsureFileExists( proxy_, base::Bind(&FileSystemFileUtil::EnsureFileExists, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_), base::Bind( exclusive ? &FileSystemOperation::DidEnsureFileExistsExclusive : &FileSystemOperation::DidEnsureFileExistsNonExclusive, base::Owned(this))); } void FileSystemOperation::CreateDirectory(const GURL& path, bool exclusive, bool recursive) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationCreateDirectory; #endif if (!SetupSrcContextForWrite(path, true)) { delete this; return; } GetUsageAndQuotaThenCallback( operation_context_.src_origin_url(), base::Bind(&FileSystemOperation::DelayedCreateDirectoryForQuota, base::Unretained(this), exclusive, recursive)); } void FileSystemOperation::DelayedCreateDirectoryForQuota( bool exclusive, bool recursive, quota::QuotaStatusCode status, int64 usage, int64 quota) { operation_context_.set_allowed_bytes_growth(quota - usage); quota_util_helper_.reset(new ScopedQuotaUtilHelper( file_system_context(), operation_context_.src_origin_url(), operation_context_.src_type())); base::FileUtilProxy::RelayFileTask( proxy_, FROM_HERE, base::Bind(&FileSystemFileUtil::CreateDirectory, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_, exclusive, recursive), base::Bind(&FileSystemOperation::DidFinishFileOperation, base::Owned(this))); } void FileSystemOperation::Copy(const GURL& src_path, const GURL& dest_path) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationCopy; #endif if (!SetupSrcContextForRead(src_path) || !SetupDestContextForWrite(dest_path, true)) { delete this; return; } GetUsageAndQuotaThenCallback( operation_context_.dest_origin_url(), base::Bind(&FileSystemOperation::DelayedCopyForQuota, base::Unretained(this))); } void FileSystemOperation::DelayedCopyForQuota(quota::QuotaStatusCode status, int64 usage, int64 quota) { operation_context_.set_allowed_bytes_growth(quota - usage); quota_util_helper_.reset(new ScopedQuotaUtilHelper( file_system_context(), operation_context_.dest_origin_url(), operation_context_.dest_type())); base::FileUtilProxy::RelayFileTask( proxy_, FROM_HERE, base::Bind(&FileSystemFileUtil::Copy, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_, dest_virtual_path_), base::Bind(&FileSystemOperation::DidFinishFileOperation, base::Owned(this))); } void FileSystemOperation::Move(const GURL& src_path, const GURL& dest_path) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationMove; #endif if (!SetupSrcContextForWrite(src_path, false) || !SetupDestContextForWrite(dest_path, true)) { delete this; return; } GetUsageAndQuotaThenCallback( operation_context_.dest_origin_url(), base::Bind(&FileSystemOperation::DelayedMoveForQuota, base::Unretained(this))); } void FileSystemOperation::DelayedMoveForQuota(quota::QuotaStatusCode status, int64 usage, int64 quota) { operation_context_.set_allowed_bytes_growth(quota - usage); quota_util_helper_.reset(new ScopedQuotaUtilHelper( file_system_context(), operation_context_.dest_origin_url(), operation_context_.dest_type())); base::FileUtilProxy::RelayFileTask( proxy_, FROM_HERE, base::Bind(&FileSystemFileUtil::Move, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_, dest_virtual_path_), base::Bind(&FileSystemOperation::DidFinishFileOperation, base::Owned(this))); } void FileSystemOperation::DirectoryExists(const GURL& path) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationDirectoryExists; #endif if (!SetupSrcContextForRead(path)) { delete this; return; } FileSystemFileUtilProxy::RelayGetFileInfo( proxy_, base::Bind(&FileSystemFileUtil::GetFileInfo, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_), base::Bind(&FileSystemOperation::DidDirectoryExists, base::Owned(this))); } void FileSystemOperation::FileExists(const GURL& path) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationFileExists; #endif if (!SetupSrcContextForRead(path)) { delete this; return; } FileSystemFileUtilProxy::RelayGetFileInfo( proxy_, base::Bind(&FileSystemFileUtil::GetFileInfo, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_), base::Bind(&FileSystemOperation::DidFileExists, base::Owned(this))); } void FileSystemOperation::GetMetadata(const GURL& path) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationGetMetadata; #endif if (!SetupSrcContextForRead(path)) { delete this; return; } FileSystemFileUtilProxy::RelayGetFileInfo( proxy_, base::Bind(&FileSystemFileUtil::GetFileInfo, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_), base::Bind(&FileSystemOperation::DidGetMetadata, base::Owned(this))); } void FileSystemOperation::ReadDirectory(const GURL& path) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationReadDirectory; #endif if (!SetupSrcContextForRead(path)) { delete this; return; } FileSystemFileUtilProxy::RelayReadDirectory( proxy_, base::Bind(&FileSystemFileUtil::ReadDirectory, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_), base::Bind(&FileSystemOperation::DidReadDirectory, base::Owned(this))); } void FileSystemOperation::Remove(const GURL& path, bool recursive) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationRemove; #endif if (!SetupSrcContextForWrite(path, false)) { delete this; return; } base::FileUtilProxy::RelayFileTask( proxy_, FROM_HERE, base::Bind(&FileSystemFileUtil::Delete, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_, recursive), base::Bind(&FileSystemOperation::DidFinishFileOperation, base::Owned(this))); } void FileSystemOperation::Write( scoped_refptr url_request_context, const GURL& path, const GURL& blob_url, int64 offset) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationWrite; #endif if (!SetupSrcContextForWrite(path, true)) { delete this; return; } DCHECK(blob_url.is_valid()); file_writer_delegate_.reset(new FileWriterDelegate(this, offset, proxy_)); blob_request_.reset( new net::URLRequest(blob_url, file_writer_delegate_.get())); blob_request_->set_context(url_request_context); GetUsageAndQuotaThenCallback( operation_context_.src_origin_url(), base::Bind(&FileSystemOperation::DelayedWriteForQuota, base::Unretained(this))); } void FileSystemOperation::DelayedWriteForQuota(quota::QuotaStatusCode status, int64 usage, int64 quota) { operation_context_.set_allowed_bytes_growth(quota - usage); quota_util_helper_.reset(new ScopedQuotaUtilHelper( file_system_context(), operation_context_.src_origin_url(), operation_context_.src_type())); int file_flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_ASYNC; base::FileUtilProxy::RelayCreateOrOpen( proxy_, base::Bind(&FileSystemFileUtil::CreateOrOpen, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_, file_flags), base::Bind(&FileSystemFileUtil::Close, base::Unretained(operation_context_.src_file_util()), &operation_context_), base::Bind(&FileSystemOperation::OnFileOpenedForWrite, base::Unretained(this))); } void FileSystemOperation::Truncate(const GURL& path, int64 length) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationTruncate; #endif if (!SetupSrcContextForWrite(path, false)) { delete this; return; } GetUsageAndQuotaThenCallback( operation_context_.src_origin_url(), base::Bind(&FileSystemOperation::DelayedTruncateForQuota, base::Unretained(this), length)); } void FileSystemOperation::DelayedTruncateForQuota(int64 length, quota::QuotaStatusCode status, int64 usage, int64 quota) { operation_context_.set_allowed_bytes_growth(quota - usage); quota_util_helper_.reset(new ScopedQuotaUtilHelper( file_system_context(), operation_context_.src_origin_url(), operation_context_.src_type())); base::FileUtilProxy::RelayFileTask( proxy_, FROM_HERE, base::Bind(&FileSystemFileUtil::Truncate, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_, length), base::Bind(&FileSystemOperation::DidFinishFileOperation, base::Owned(this))); } void FileSystemOperation::TouchFile(const GURL& path, const base::Time& last_access_time, const base::Time& last_modified_time) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationTouchFile; #endif if (!SetupSrcContextForWrite(path, true)) { delete this; return; } base::FileUtilProxy::RelayFileTask( proxy_, FROM_HERE, base::Bind(&FileSystemFileUtil::Touch, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_, last_access_time, last_modified_time), base::Bind(&FileSystemOperation::DidTouchFile, base::Owned(this))); } void FileSystemOperation::OpenFile(const GURL& path, int file_flags, base::ProcessHandle peer_handle) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationOpenFile; #endif peer_handle_ = peer_handle; if (file_flags & ( (base::PLATFORM_FILE_ENUMERATE | base::PLATFORM_FILE_TEMPORARY | base::PLATFORM_FILE_HIDDEN))) { delete this; return; } if (file_flags & (base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_OPEN_ALWAYS | base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_OPEN_TRUNCATED | base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_EXCLUSIVE_WRITE | base::PLATFORM_FILE_DELETE_ON_CLOSE | base::PLATFORM_FILE_WRITE_ATTRIBUTES)) { if (!SetupSrcContextForWrite(path, true)) { delete this; return; } } else { if (!SetupSrcContextForRead(path)) { delete this; return; } } GetUsageAndQuotaThenCallback( operation_context_.src_origin_url(), base::Bind(&FileSystemOperation::DelayedOpenFileForQuota, base::Unretained(this), file_flags)); } void FileSystemOperation::DelayedOpenFileForQuota(int file_flags, quota::QuotaStatusCode status, int64 usage, int64 quota) { operation_context_.set_allowed_bytes_growth(quota - usage); quota_util_helper_.reset(new ScopedQuotaUtilHelper( file_system_context(), operation_context_.src_origin_url(), operation_context_.src_type())); base::FileUtilProxy::RelayCreateOrOpen( proxy_, base::Bind(&FileSystemFileUtil::CreateOrOpen, base::Unretained(operation_context_.src_file_util()), &operation_context_, src_virtual_path_, file_flags), base::Bind(&FileSystemFileUtil::Close, base::Unretained(operation_context_.src_file_util()), &operation_context_), base::Bind(&FileSystemOperation::DidOpenFile, base::Owned(this))); } void FileSystemOperation::SyncGetPlatformPath(const GURL& path, FilePath* platform_path) { #ifndef NDEBUG DCHECK(kOperationNone == pending_operation_); pending_operation_ = kOperationGetLocalPath; #endif if (!SetupSrcContextForRead(path)) { delete this; return; } operation_context_.src_file_util()->GetLocalFilePath( &operation_context_, src_virtual_path_, platform_path); delete this; } // We can only get here on a write or truncate that's not yet completed. // We don't support cancelling any other operation at this time. void FileSystemOperation::Cancel(FileSystemOperation* cancel_operation_ptr) { scoped_ptr cancel_operation(cancel_operation_ptr); if (file_writer_delegate_.get()) { #ifndef NDEBUG DCHECK(kOperationWrite == pending_operation_); #endif // Writes are done without proxying through FileUtilProxy after the initial // opening of the PlatformFile. All state changes are done on this thread, // so we're guaranteed to be able to shut down atomically. We do need to // check that the file has been opened [which means the blob_request_ has // been created], so we know how much we need to do. if (blob_request_.get()) // This halts any calls to file_writer_delegate_ from blob_request_. blob_request_->Cancel(); if (dispatcher_.get()) dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_ABORT); cancel_operation->dispatcher_->DidSucceed(); dispatcher_.reset(); } else { #ifndef NDEBUG DCHECK(kOperationTruncate == pending_operation_); #endif // We're cancelling a truncate operation, but we can't actually stop it // since it's been proxied to another thread. We need to save the // cancel_operation so that when the truncate returns, it can see that it's // been cancelled, report it, and report that the cancel has succeeded. DCHECK(!cancel_operation_.get()); cancel_operation_.swap(cancel_operation); } } void FileSystemOperation::GetUsageAndQuotaThenCallback( const GURL& origin_url, const quota::QuotaManager::GetUsageAndQuotaCallback& callback) { quota::QuotaManagerProxy* quota_manager_proxy = file_system_context()->quota_manager_proxy(); if (!quota_manager_proxy || !file_system_context()->GetQuotaUtil( operation_context_.src_type())) { // If we don't have the quota manager or the requested filesystem type // does not support quota, we should be able to let it go. callback.Run(quota::kQuotaStatusOk, 0, kint64max); return; } DCHECK(quota_manager_proxy); DCHECK(quota_manager_proxy->quota_manager()); quota_manager_proxy->quota_manager()->GetUsageAndQuota( operation_context_.src_origin_url(), FileSystemTypeToQuotaStorageType( operation_context_.src_type()), callback); } void FileSystemOperation::DidGetRootPath( bool success, const FilePath& path, const std::string& name) { if (!dispatcher_.get()) return; DCHECK(success || path.empty()); GURL result; if (!dispatcher_.get()) return; // We ignore the path, and return a URL instead. The point was just to verify // that we could create/find the path. if (success) { result = GetFileSystemRootURI( operation_context_.src_origin_url(), operation_context_.src_type()); } dispatcher_->DidOpenFileSystem(name, result); } void FileSystemOperation::DidEnsureFileExistsExclusive( base::PlatformFileError rv, bool created) { if (rv == base::PLATFORM_FILE_OK && !created) { if (dispatcher_.get()) dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_EXISTS); } else { DidFinishFileOperation(rv); } } void FileSystemOperation::DidEnsureFileExistsNonExclusive( base::PlatformFileError rv, bool /* created */) { DidFinishFileOperation(rv); } void FileSystemOperation::DidFinishFileOperation( base::PlatformFileError rv) { if (cancel_operation_.get()) { #ifndef NDEBUG DCHECK(kOperationTruncate == pending_operation_); #endif if (dispatcher_.get()) dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_ABORT); cancel_operation_->dispatcher_->DidSucceed(); } else if (dispatcher_.get()) { if (rv == base::PLATFORM_FILE_OK) dispatcher_->DidSucceed(); else dispatcher_->DidFail(rv); } } void FileSystemOperation::DidDirectoryExists( base::PlatformFileError rv, const base::PlatformFileInfo& file_info, const FilePath& unused) { if (!dispatcher_.get()) return; if (rv == base::PLATFORM_FILE_OK) { if (file_info.is_directory) dispatcher_->DidSucceed(); else dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY); } else { dispatcher_->DidFail(rv); } } void FileSystemOperation::DidFileExists( base::PlatformFileError rv, const base::PlatformFileInfo& file_info, const FilePath& unused) { if (!dispatcher_.get()) return; if (rv == base::PLATFORM_FILE_OK) { if (file_info.is_directory) dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_NOT_A_FILE); else dispatcher_->DidSucceed(); } else { dispatcher_->DidFail(rv); } } void FileSystemOperation::DidGetMetadata( base::PlatformFileError rv, const base::PlatformFileInfo& file_info, const FilePath& platform_path) { if (!dispatcher_.get()) return; if (rv == base::PLATFORM_FILE_OK) dispatcher_->DidReadMetadata(file_info, platform_path); else dispatcher_->DidFail(rv); } void FileSystemOperation::DidReadDirectory( base::PlatformFileError rv, const std::vector& entries) { if (!dispatcher_.get()) return; if (rv == base::PLATFORM_FILE_OK) dispatcher_->DidReadDirectory(entries, false /* has_more */); else dispatcher_->DidFail(rv); } void FileSystemOperation::DidWrite( base::PlatformFileError rv, int64 bytes, bool complete) { if (!dispatcher_.get()) { delete this; return; } if (rv == base::PLATFORM_FILE_OK) dispatcher_->DidWrite(bytes, complete); else dispatcher_->DidFail(rv); if (complete || rv != base::PLATFORM_FILE_OK) delete this; } void FileSystemOperation::DidTouchFile(base::PlatformFileError rv) { if (!dispatcher_.get()) return; if (rv == base::PLATFORM_FILE_OK) dispatcher_->DidSucceed(); else dispatcher_->DidFail(rv); } void FileSystemOperation::DidOpenFile( base::PlatformFileError rv, base::PassPlatformFile file, bool unused) { if (!dispatcher_.get()) return; if (rv == base::PLATFORM_FILE_OK) dispatcher_->DidOpenFile(file.ReleaseValue(), peer_handle_); else dispatcher_->DidFail(rv); } void FileSystemOperation::OnFileOpenedForWrite( base::PlatformFileError rv, base::PassPlatformFile file, bool created) { if (base::PLATFORM_FILE_OK != rv || !dispatcher_.get()) { if (dispatcher_.get()) dispatcher_->DidFail(rv); delete this; return; } file_writer_delegate_->Start(file.ReleaseValue(), blob_request_.get()); } bool FileSystemOperation::VerifyFileSystemPathForRead( const GURL& path, GURL* origin_url, FileSystemType* type, FilePath* virtual_path, FileSystemFileUtil** file_util) { if (!VerifyFileSystemPath(path, origin_url, type, virtual_path, file_util)) return false; // We notify this read access whether the read access succeeds or not. // This must be ok since this is used to let the QM's eviction logic know // someone is interested in reading the origin data and therefore to indicate // that evicting this origin may not be a good idea. FileSystemQuotaUtil* quota_util = file_system_context()->GetQuotaUtil(*type); if (quota_util) { quota_util->NotifyOriginWasAccessedOnIOThread( file_system_context()->quota_manager_proxy(), *origin_url, *type); } return true; } bool FileSystemOperation::VerifyFileSystemPathForWrite( const GURL& path, bool create, GURL* origin_url, FileSystemType* type, FilePath* virtual_path, FileSystemFileUtil** file_util) { if (!VerifyFileSystemPath(path, origin_url, type, virtual_path, file_util)) return false; // Any write access is disallowed on the root path. if (virtual_path->value().length() == 0 || virtual_path->DirName().value() == virtual_path->value()) { dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_SECURITY); return false; } if (create && file_system_context()->path_manager()->IsRestrictedFileName( *type, virtual_path->BaseName())) { dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_SECURITY); return false; } return true; } bool FileSystemOperation::VerifyFileSystemPath( const GURL& path, GURL* origin_url, FileSystemType* type, FilePath* virtual_path, FileSystemFileUtil** file_util) { DCHECK(file_system_context()); if (!CrackFileSystemURL(path, origin_url, type, virtual_path)) { dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_INVALID_URL); return false; } if (!file_system_context()->path_manager()->IsAccessAllowed( *origin_url, *type, *virtual_path)) { dispatcher_->DidFail(base::PLATFORM_FILE_ERROR_SECURITY); return false; } DCHECK(file_util); *file_util = file_system_context()->path_manager()->GetFileUtil(*type); DCHECK(*file_util); return true; } bool FileSystemOperation::SetupSrcContextForRead(const GURL& path) { GURL origin_url; FileSystemType type; FileSystemFileUtil* file_util; bool result = VerifyFileSystemPathForRead( path, &origin_url, &type, &src_virtual_path_, &file_util); operation_context_.set_src_origin_url(origin_url); operation_context_.set_src_type(type); if (!operation_context_.src_file_util()) operation_context_.set_src_file_util(file_util); return result; } bool FileSystemOperation::SetupSrcContextForWrite(const GURL& path, bool create) { GURL origin_url; FileSystemType type; FileSystemFileUtil* file_util; bool result = VerifyFileSystemPathForWrite( path, create, &origin_url, &type, &src_virtual_path_, &file_util); operation_context_.set_src_origin_url(origin_url); operation_context_.set_src_type(type); if (!operation_context_.src_file_util()) operation_context_.set_src_file_util(file_util); return result; } bool FileSystemOperation::SetupDestContextForWrite(const GURL& path, bool create) { GURL origin_url; FileSystemType type; FileSystemFileUtil* file_util; bool result = VerifyFileSystemPathForWrite( path, create, &origin_url, &type, &dest_virtual_path_, &file_util); operation_context_.set_dest_origin_url(origin_url); operation_context_.set_dest_type(type); if (!operation_context_.dest_file_util()) operation_context_.set_dest_file_util(file_util); return result; } } // namespace fileapi