This source file includes following definitions.
- FileHandlerCanHandleFileWithExtension
- FileHandlerCanHandleFileWithMimeType
- DoCheckWritableFile
- TaskDone
- Error
- CheckLocalWritableFiles
- CheckRemoteWritableFile
- RemoteCheckDone
- FileHandlerForId
- FirstFileHandlerForFile
- FindFileHandlersForFiles
- FileHandlerCanHandleFile
- CreateFileEntry
- CheckWritableFiles
- HasFileSystemWritePermission
- ValidateFileEntryAndGetPath
#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
#include "apps/browser/file_handler_util.h"
#include "base/file_util.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/render_process_host.h"
#include "extensions/browser/extension_prefs.h"
#include "net/base/mime_util.h"
#include "webkit/browser/fileapi/isolated_context.h"
#include "webkit/common/fileapi/file_system_mount_option.h"
#include "webkit/common/fileapi/file_system_types.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/drive/file_system_util.h"
#endif
using apps::file_handler_util::GrantedFileEntry;
namespace extensions {
namespace app_file_handler_util {
const char kInvalidParameters[] = "Invalid parameters";
const char kSecurityError[] = "Security error";
namespace {
bool FileHandlerCanHandleFileWithExtension(
const FileHandlerInfo& handler,
const base::FilePath& path) {
for (std::set<std::string>::const_iterator extension =
handler.extensions.begin();
extension != handler.extensions.end(); ++extension) {
if (*extension == "*")
return true;
if (path.MatchesExtension(
base::FilePath::kExtensionSeparator +
base::FilePath::FromUTF8Unsafe(*extension).value())) {
return true;
}
if (extension->empty() &&
path.MatchesExtension(base::FilePath::StringType())) {
return true;
}
}
return false;
}
bool FileHandlerCanHandleFileWithMimeType(
const FileHandlerInfo& handler,
const std::string& mime_type) {
for (std::set<std::string>::const_iterator type = handler.types.begin();
type != handler.types.end(); ++type) {
if (net::MatchesMimeType(*type, mime_type))
return true;
}
return false;
}
bool DoCheckWritableFile(const base::FilePath& path, bool is_directory) {
if (base::PathExists(path) && base::IsLink(path))
return false;
if (is_directory)
return base::DirectoryExists(path);
int creation_flags = base::File::FLAG_CREATE | base::File::FLAG_READ |
base::File::FLAG_WRITE;
base::File file(path, creation_flags);
if (file.IsValid())
return true;
return file.error_details() == base::File::FILE_ERROR_EXISTS;
}
class WritableFileChecker
: public base::RefCountedThreadSafe<WritableFileChecker> {
public:
WritableFileChecker(
const std::vector<base::FilePath>& paths,
Profile* profile,
bool is_directory,
const base::Closure& on_success,
const base::Callback<void(const base::FilePath&)>& on_failure);
void Check();
private:
friend class base::RefCountedThreadSafe<WritableFileChecker>;
virtual ~WritableFileChecker();
void TaskDone();
void Error(const base::FilePath& error_path);
void CheckLocalWritableFiles();
#if defined(OS_CHROMEOS)
void CheckRemoteWritableFile(const base::FilePath& remote_path,
drive::FileError error,
const base::FilePath& local_path);
void RemoteCheckDone(const base::FilePath& remote_path,
drive::FileError error);
#endif
const std::vector<base::FilePath> paths_;
Profile* profile_;
const bool is_directory_;
int outstanding_tasks_;
base::FilePath error_path_;
base::Closure on_success_;
base::Callback<void(const base::FilePath&)> on_failure_;
};
WritableFileChecker::WritableFileChecker(
const std::vector<base::FilePath>& paths,
Profile* profile,
bool is_directory,
const base::Closure& on_success,
const base::Callback<void(const base::FilePath&)>& on_failure)
: paths_(paths),
profile_(profile),
is_directory_(is_directory),
outstanding_tasks_(1),
on_success_(on_success),
on_failure_(on_failure) {}
void WritableFileChecker::Check() {
#if defined(OS_CHROMEOS)
if (drive::util::IsUnderDriveMountPoint(paths_[0])) {
outstanding_tasks_ = paths_.size();
for (std::vector<base::FilePath>::const_iterator it = paths_.begin();
it != paths_.end();
++it) {
DCHECK(drive::util::IsUnderDriveMountPoint(*it));
if (is_directory_) {
drive::util::CheckDirectoryExists(
profile_,
*it,
base::Bind(&WritableFileChecker::RemoteCheckDone, this, *it));
} else {
drive::util::PrepareWritableFileAndRun(
profile_,
*it,
base::Bind(&WritableFileChecker::CheckRemoteWritableFile, this,
*it));
}
}
return;
}
#endif
content::BrowserThread::PostTask(
content::BrowserThread::FILE,
FROM_HERE,
base::Bind(&WritableFileChecker::CheckLocalWritableFiles, this));
}
WritableFileChecker::~WritableFileChecker() {}
void WritableFileChecker::TaskDone() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (--outstanding_tasks_ == 0) {
if (error_path_.empty())
on_success_.Run();
else
on_failure_.Run(error_path_);
}
}
void WritableFileChecker::Error(const base::FilePath& error_path) {
DCHECK(!error_path.empty());
error_path_ = error_path;
TaskDone();
}
void WritableFileChecker::CheckLocalWritableFiles() {
DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
std::string error;
for (std::vector<base::FilePath>::const_iterator it = paths_.begin();
it != paths_.end();
++it) {
if (!DoCheckWritableFile(*it, is_directory_)) {
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&WritableFileChecker::Error, this, *it));
return;
}
}
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&WritableFileChecker::TaskDone, this));
}
#if defined(OS_CHROMEOS)
void WritableFileChecker::CheckRemoteWritableFile(
const base::FilePath& remote_path,
drive::FileError error,
const base::FilePath& ) {
RemoteCheckDone(remote_path, error);
}
void WritableFileChecker::RemoteCheckDone(
const base::FilePath& remote_path,
drive::FileError error) {
if (error == drive::FILE_ERROR_OK) {
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&WritableFileChecker::TaskDone, this));
} else {
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
base::Bind(&WritableFileChecker::Error, this, remote_path));
}
}
#endif
}
typedef std::vector<FileHandlerInfo> FileHandlerList;
const FileHandlerInfo* FileHandlerForId(const Extension& app,
const std::string& handler_id) {
const FileHandlerList* file_handlers = FileHandlers::GetFileHandlers(&app);
if (!file_handlers)
return NULL;
for (FileHandlerList::const_iterator i = file_handlers->begin();
i != file_handlers->end(); i++) {
if (i->id == handler_id)
return &*i;
}
return NULL;
}
const FileHandlerInfo* FirstFileHandlerForFile(
const Extension& app,
const std::string& mime_type,
const base::FilePath& path) {
const FileHandlerList* file_handlers = FileHandlers::GetFileHandlers(&app);
if (!file_handlers)
return NULL;
for (FileHandlerList::const_iterator i = file_handlers->begin();
i != file_handlers->end(); i++) {
if (FileHandlerCanHandleFile(*i, mime_type, path))
return &*i;
}
return NULL;
}
std::vector<const FileHandlerInfo*> FindFileHandlersForFiles(
const Extension& app, const PathAndMimeTypeSet& files) {
std::vector<const FileHandlerInfo*> handlers;
if (files.empty())
return handlers;
const FileHandlerList* file_handlers = FileHandlers::GetFileHandlers(&app);
if (!file_handlers)
return handlers;
for (FileHandlerList::const_iterator data = file_handlers->begin();
data != file_handlers->end(); ++data) {
bool handles_all_types = true;
for (PathAndMimeTypeSet::const_iterator it = files.begin();
it != files.end(); ++it) {
if (!FileHandlerCanHandleFile(*data, it->second, it->first)) {
handles_all_types = false;
break;
}
}
if (handles_all_types)
handlers.push_back(&*data);
}
return handlers;
}
bool FileHandlerCanHandleFile(
const FileHandlerInfo& handler,
const std::string& mime_type,
const base::FilePath& path) {
return FileHandlerCanHandleFileWithMimeType(handler, mime_type) ||
FileHandlerCanHandleFileWithExtension(handler, path);
}
GrantedFileEntry CreateFileEntry(
Profile* profile,
const Extension* extension,
int renderer_id,
const base::FilePath& path,
bool is_directory) {
GrantedFileEntry result;
fileapi::IsolatedContext* isolated_context =
fileapi::IsolatedContext::GetInstance();
DCHECK(isolated_context);
result.filesystem_id = isolated_context->RegisterFileSystemForPath(
fileapi::kFileSystemTypeNativeForPlatformApp, path,
&result.registered_name);
content::ChildProcessSecurityPolicy* policy =
content::ChildProcessSecurityPolicy::GetInstance();
policy->GrantReadFileSystem(renderer_id, result.filesystem_id);
if (HasFileSystemWritePermission(extension)) {
if (is_directory) {
policy->GrantCreateReadWriteFileSystem(renderer_id, result.filesystem_id);
} else {
policy->GrantWriteFileSystem(renderer_id, result.filesystem_id);
policy->GrantDeleteFromFileSystem(renderer_id, result.filesystem_id);
}
}
result.id = result.filesystem_id + ":" + result.registered_name;
return result;
}
void CheckWritableFiles(
const std::vector<base::FilePath>& paths,
Profile* profile,
bool is_directory,
const base::Closure& on_success,
const base::Callback<void(const base::FilePath&)>& on_failure) {
scoped_refptr<WritableFileChecker> checker(new WritableFileChecker(
paths, profile, is_directory, on_success, on_failure));
checker->Check();
}
bool HasFileSystemWritePermission(const Extension* extension) {
return extension->HasAPIPermission(APIPermission::kFileSystemWrite);
}
bool ValidateFileEntryAndGetPath(
const std::string& filesystem_name,
const std::string& filesystem_path,
const content::RenderViewHost* render_view_host,
base::FilePath* file_path,
std::string* error) {
if (filesystem_path.empty()) {
*error = kInvalidParameters;
return false;
}
std::string filesystem_id;
if (!fileapi::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) {
*error = kInvalidParameters;
return false;
}
content::ChildProcessSecurityPolicy* policy =
content::ChildProcessSecurityPolicy::GetInstance();
if (!policy->CanReadFileSystem(render_view_host->GetProcess()->GetID(),
filesystem_id)) {
*error = kSecurityError;
return false;
}
fileapi::IsolatedContext* context = fileapi::IsolatedContext::GetInstance();
base::FilePath relative_path =
base::FilePath::FromUTF8Unsafe(filesystem_path);
base::FilePath virtual_path = context->CreateVirtualRootPath(filesystem_id)
.Append(relative_path);
fileapi::FileSystemType type;
fileapi::FileSystemMountOption mount_option;
if (!context->CrackVirtualPath(
virtual_path, &filesystem_id, &type, file_path, &mount_option)) {
*error = kInvalidParameters;
return false;
}
if (type != fileapi::kFileSystemTypeNativeForPlatformApp &&
type != fileapi::kFileSystemTypeDragged) {
*error = kInvalidParameters;
return false;
}
return true;
}
}
}