Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1297)

Unified Diff: chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc

Issue 2685883008: Revert of Move file_handlers API from //chrome to //extensions (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
diff --git a/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
new file mode 100644
index 0000000000000000000000000000000000000000..20dbf130a0ba724121cb8f54253ef9bd429e4fda
--- /dev/null
+++ b/chrome/browser/extensions/api/file_handlers/app_file_handler_util.cc
@@ -0,0 +1,361 @@
+// 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 "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "build/build_config.h"
+#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/entry_info.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/granted_file_entry.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "net/base/mime_util.h"
+#include "storage/browser/fileapi/isolated_context.h"
+#include "storage/common/fileapi/file_system_mount_option.h"
+#include "storage/common/fileapi/file_system_types.h"
+
+#if defined(OS_CHROMEOS)
+#include "extensions/browser/api/file_handlers/non_native_file_system_delegate.h"
+#endif
+
+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;
+
+ // Accept files whose extension or combined extension (e.g. ".tar.gz")
+ // match the supported extensions of file handler.
+ base::FilePath::StringType handler_extention(
+ base::FilePath::kExtensionSeparator +
+ base::FilePath::FromUTF8Unsafe(*extension).value());
+ if (base::FilePath::CompareEqualIgnoreCase(handler_extention,
+ path.Extension()) ||
+ base::FilePath::CompareEqualIgnoreCase(handler_extention,
+ path.FinalExtension())) {
+ return true;
+ }
+
+ // Also accept files with no extension for handlers that support an
+ // empty extension, i.e. both "foo" and "foo." match.
+ 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 PrepareNativeLocalFileForWritableApp(const base::FilePath& path,
+ bool is_directory) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
+
+ // Don't allow links.
+ if (base::PathExists(path) && base::IsLink(path))
+ return false;
+
+ if (is_directory)
+ return base::DirectoryExists(path);
+
+ // Create the file if it doesn't already exist.
+ int creation_flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ;
+ base::File file(path, creation_flags);
+
+ return file.IsValid();
+}
+
+// Checks whether a list of paths are all OK for writing and calls a provided
+// on_success or on_failure callback when done. A path is OK for writing if it
+// is not a symlink, is not in a blacklisted path and can be opened for writing.
+// Creates files if they do not exist, but fails for non-existent directory
+// paths. On Chrome OS, also fails for non-local files that don't already exist.
+class WritableFileChecker
+ : public base::RefCountedThreadSafe<WritableFileChecker> {
+ public:
+ WritableFileChecker(
+ const std::vector<base::FilePath>& paths,
+ Profile* profile,
+ const std::set<base::FilePath>& directory_paths,
+ const base::Closure& on_success,
+ const base::Callback<void(const base::FilePath&)>& on_failure);
+
+ void Check();
+
+ private:
+ friend class base::RefCountedThreadSafe<WritableFileChecker>;
+ virtual ~WritableFileChecker();
+
+ // Called when a work item is completed. If all work items are done, this
+ // calls the success or failure callback.
+ void TaskDone();
+
+ // Reports an error in completing a work item. This may be called more than
+ // once, but only the last message will be retained.
+ void Error(const base::FilePath& error_path);
+
+ void CheckLocalWritableFiles();
+
+ // Called when processing a file is completed with either a success or an
+ // error.
+ void OnPrepareFileDone(const base::FilePath& path, bool success);
+
+ const std::vector<base::FilePath> paths_;
+ Profile* profile_;
+ const std::set<base::FilePath> directory_paths_;
+ 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,
+ const std::set<base::FilePath>& directory_paths,
+ const base::Closure& on_success,
+ const base::Callback<void(const base::FilePath&)>& on_failure)
+ : paths_(paths),
+ profile_(profile),
+ directory_paths_(directory_paths),
+ outstanding_tasks_(1),
+ on_success_(on_success),
+ on_failure_(on_failure) {}
+
+void WritableFileChecker::Check() {
+ outstanding_tasks_ = paths_.size();
+ for (const auto& path : paths_) {
+ bool is_directory = directory_paths_.find(path) != directory_paths_.end();
+#if defined(OS_CHROMEOS)
+ NonNativeFileSystemDelegate* delegate =
+ ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate();
+ if (delegate && delegate->IsUnderNonNativeLocalPath(profile_, path)) {
+ if (is_directory) {
+ delegate->IsNonNativeLocalPathDirectory(
+ profile_,
+ path,
+ base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
+ } else {
+ delegate->PrepareNonNativeLocalFileForWritableApp(
+ profile_,
+ path,
+ base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
+ }
+ continue;
+ }
+#endif
+ content::BrowserThread::PostTaskAndReplyWithResult(
+ content::BrowserThread::FILE, FROM_HERE,
+ base::Bind(&PrepareNativeLocalFileForWritableApp, path, is_directory),
+ base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
+ }
+}
+
+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_);
+ }
+}
+
+// Reports an error in completing a work item. This may be called more than
+// once, but only the last message will be retained.
+void WritableFileChecker::Error(const base::FilePath& error_path) {
+ DCHECK(!error_path.empty());
+ error_path_ = error_path;
+ TaskDone();
+}
+
+void WritableFileChecker::OnPrepareFileDone(const base::FilePath& path,
+ bool success) {
+ if (success)
+ TaskDone();
+ else
+ Error(path);
+}
+
+} // namespace
+
+const FileHandlerInfo* FileHandlerForId(const Extension& app,
+ const std::string& handler_id) {
+ const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
+ if (!file_handlers)
+ return NULL;
+
+ for (FileHandlersInfo::const_iterator i = file_handlers->begin();
+ i != file_handlers->end(); i++) {
+ if (i->id == handler_id)
+ return &*i;
+ }
+ return NULL;
+}
+
+std::vector<const FileHandlerInfo*> FindFileHandlersForEntries(
+ const Extension& app,
+ const std::vector<EntryInfo> entries) {
+ std::vector<const FileHandlerInfo*> handlers;
+ if (entries.empty())
+ return handlers;
+
+ // Look for file handlers which can handle all the MIME types specified.
+ const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
+ if (!file_handlers)
+ return handlers;
+
+ for (FileHandlersInfo::const_iterator data = file_handlers->begin();
+ data != file_handlers->end(); ++data) {
+ bool handles_all_types = true;
+ for (std::vector<EntryInfo>::const_iterator it = entries.begin();
+ it != entries.end(); ++it) {
+ if (!FileHandlerCanHandleEntry(*data, *it)) {
+ handles_all_types = false;
+ break;
+ }
+ }
+ if (handles_all_types)
+ handlers.push_back(&*data);
+ }
+ return handlers;
+}
+
+bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler,
+ const EntryInfo& entry) {
+ if (entry.is_directory)
+ return handler.include_directories;
+
+ return FileHandlerCanHandleFileWithMimeType(handler, entry.mime_type) ||
+ FileHandlerCanHandleFileWithExtension(handler, entry.path);
+}
+
+GrantedFileEntry CreateFileEntry(Profile* profile,
+ const Extension* extension,
+ int renderer_id,
+ const base::FilePath& path,
+ bool is_directory) {
+ GrantedFileEntry result;
+ storage::IsolatedContext* isolated_context =
+ storage::IsolatedContext::GetInstance();
+ DCHECK(isolated_context);
+
+ result.filesystem_id = isolated_context->RegisterFileSystemForPath(
+ storage::kFileSystemTypeNativeForPlatformApp, std::string(), 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 PrepareFilesForWritableApp(
+ const std::vector<base::FilePath>& paths,
+ Profile* profile,
+ const std::set<base::FilePath>& directory_paths,
+ const base::Closure& on_success,
+ const base::Callback<void(const base::FilePath&)>& on_failure) {
+ scoped_refptr<WritableFileChecker> checker(new WritableFileChecker(
+ paths, profile, directory_paths, on_success, on_failure));
+ checker->Check();
+}
+
+bool HasFileSystemWritePermission(const Extension* extension) {
+ return extension->permissions_data()->HasAPIPermission(
+ APIPermission::kFileSystemWrite);
+}
+
+bool ValidateFileEntryAndGetPath(const std::string& filesystem_name,
+ const std::string& filesystem_path,
+ int render_process_id,
+ base::FilePath* file_path,
+ std::string* error) {
+ if (filesystem_path.empty()) {
+ *error = kInvalidParameters;
+ return false;
+ }
+
+ std::string filesystem_id;
+ if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) {
+ *error = kInvalidParameters;
+ return false;
+ }
+
+ // Only return the display path if the process has read access to the
+ // filesystem.
+ content::ChildProcessSecurityPolicy* policy =
+ content::ChildProcessSecurityPolicy::GetInstance();
+ if (!policy->CanReadFileSystem(render_process_id, filesystem_id)) {
+ *error = kSecurityError;
+ return false;
+ }
+
+ storage::IsolatedContext* context = storage::IsolatedContext::GetInstance();
+ base::FilePath relative_path =
+ base::FilePath::FromUTF8Unsafe(filesystem_path);
+ base::FilePath virtual_path =
+ context->CreateVirtualRootPath(filesystem_id).Append(relative_path);
+ storage::FileSystemType type;
+ storage::FileSystemMountOption mount_option;
+ std::string cracked_id;
+ if (!context->CrackVirtualPath(virtual_path, &filesystem_id, &type,
+ &cracked_id, file_path, &mount_option)) {
+ *error = kInvalidParameters;
+ return false;
+ }
+
+ // The file system API is only intended to operate on file entries that
+ // correspond to a native file, selected by the user so only allow file
+ // systems returned by the file system API or from a drag and drop operation.
+ if (type != storage::kFileSystemTypeNativeForPlatformApp &&
+ type != storage::kFileSystemTypeDragged) {
+ *error = kInvalidParameters;
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace app_file_handler_util
+
+} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698