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

Side by Side Diff: chrome/browser/extensions/api/file_system/file_system_api.cc

Issue 985533004: Implement chrome.fileSystem.requestFileSystem(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed. Created 5 years, 9 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/file_system/file_system_api.h" 5 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
6 6
7 #include <set> 7 #include <set>
8 8
9 #include "apps/saved_files_service.h" 9 #include "apps/saved_files_service.h"
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 #include "ui/base/l10n/l10n_util.h" 51 #include "ui/base/l10n/l10n_util.h"
52 #include "ui/shell_dialogs/select_file_dialog.h" 52 #include "ui/shell_dialogs/select_file_dialog.h"
53 #include "ui/shell_dialogs/selected_file_info.h" 53 #include "ui/shell_dialogs/selected_file_info.h"
54 54
55 #if defined(OS_MACOSX) 55 #if defined(OS_MACOSX)
56 #include <CoreFoundation/CoreFoundation.h> 56 #include <CoreFoundation/CoreFoundation.h>
57 #include "base/mac/foundation_util.h" 57 #include "base/mac/foundation_util.h"
58 #endif 58 #endif
59 59
60 #if defined(OS_CHROMEOS) 60 #if defined(OS_CHROMEOS)
61 #include "base/thread_task_runner_handle.h"
62 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
61 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h" 63 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
64 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
65 #include "components/user_manager/user_manager.h"
66 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
62 #endif 67 #endif
63 68
64 using apps::SavedFileEntry; 69 using apps::SavedFileEntry;
65 using apps::SavedFilesService; 70 using apps::SavedFilesService;
66 using storage::IsolatedContext; 71 using storage::IsolatedContext;
67 72
68 const char kInvalidCallingPage[] = "Invalid calling page. This function can't " 73 const char kInvalidCallingPage[] = "Invalid calling page. This function can't "
69 "be called from a background page."; 74 "be called from a background page.";
70 const char kUserCancelled[] = "User cancelled"; 75 const char kUserCancelled[] = "User cancelled";
71 const char kWritableFileErrorFormat[] = "Error opening %s"; 76 const char kWritableFileErrorFormat[] = "Error opening %s";
72 const char kRequiresFileSystemWriteError[] = 77 const char kRequiresFileSystemWriteError[] =
73 "Operation requires fileSystem.write permission"; 78 "Operation requires fileSystem.write permission";
74 const char kRequiresFileSystemDirectoryError[] = 79 const char kRequiresFileSystemDirectoryError[] =
75 "Operation requires fileSystem.directory permission"; 80 "Operation requires fileSystem.directory permission";
76 const char kMultipleUnsupportedError[] = 81 const char kMultipleUnsupportedError[] =
77 "acceptsMultiple: true is not supported for 'saveFile'"; 82 "acceptsMultiple: true is not supported for 'saveFile'";
78 const char kUnknownIdError[] = "Unknown id"; 83 const char kUnknownIdError[] = "Unknown id";
84 const char kNotSupportedError[] = "Operation not supported.";
benwells 2015/03/20 00:42:39 It would be good to provide users with info on why
mtomasz 2015/03/20 01:56:00 Done.
85
86 #if defined(OS_CHROMEOS)
87 const char kVolumeNotFoundError[] = "Volume not found.";
88 const char kSecurityError[] = "Security error.";
89 #endif
79 90
80 namespace file_system = extensions::api::file_system; 91 namespace file_system = extensions::api::file_system;
81 namespace ChooseEntry = file_system::ChooseEntry; 92 namespace ChooseEntry = file_system::ChooseEntry;
82 93
83 namespace { 94 namespace {
84 95
85 bool g_skip_picker_for_test = false; 96 bool g_skip_picker_for_test = false;
86 bool g_use_suggested_path_for_test = false; 97 bool g_use_suggested_path_for_test = false;
87 base::FilePath* g_path_to_be_picked_for_test; 98 base::FilePath* g_path_to_be_picked_for_test;
88 std::vector<base::FilePath>* g_paths_to_be_picked_for_test; 99 std::vector<base::FilePath>* g_paths_to_be_picked_for_test;
(...skipping 898 matching lines...) Expand 10 before | Expand all | Expand 10 after
987 error_ = kUnknownIdError; 998 error_ = kUnknownIdError;
988 return false; 999 return false;
989 } 1000 }
990 1001
991 bool FileSystemGetObservedEntriesFunction::RunSync() { 1002 bool FileSystemGetObservedEntriesFunction::RunSync() {
992 NOTIMPLEMENTED(); 1003 NOTIMPLEMENTED();
993 error_ = kUnknownIdError; 1004 error_ = kUnknownIdError;
994 return false; 1005 return false;
995 } 1006 }
996 1007
1008 FileSystemRequestFileSystemFunction::FileSystemRequestFileSystemFunction()
1009 : chrome_details_(this) {
1010 }
1011
1012 ExtensionFunction::ResponseAction FileSystemRequestFileSystemFunction::Run() {
1013 using extensions::api::file_system::RequestFileSystem::Params;
1014 const scoped_ptr<Params> params(Params::Create(*args_));
1015 EXTENSION_FUNCTION_VALIDATE(params);
1016
1017 #if !defined(OS_CHROMEOS)
1018 NOTIMPLEMENTED();
1019 return RespondNow(Error(kNotSupportedError));
1020
1021 #else
1022 using file_manager::VolumeManager;
1023 using file_manager::VolumeInfo;
1024 VolumeManager* const volume_manager =
1025 VolumeManager::Get(chrome_details_.GetProfile());
1026 DCHECK(volume_manager);
1027
1028 const bool writable =
1029 params->options.writable.get() && *params->options.writable.get();
1030
1031 // Only kiosk apps in kiosk sessions can use this API. Additionally component
benwells 2015/03/20 00:42:39 This check (kiosk mode) can go up before the code
mtomasz 2015/03/20 01:56:00 Done.
1032 // extensions and apps, which is not documented though.
1033 if ((!user_manager::UserManager::Get()->IsLoggedInAsKioskApp() ||
1034 !KioskModeInfo::IsKioskEnabled(extension())) &&
benwells 2015/03/20 00:42:39 I don't understand kiosk mode that well but rememb
mtomasz 2015/03/20 01:56:00 Yes, the API is meant to work in both modes, but f
1035 extension()->location() != Manifest::COMPONENT) {
1036 return RespondNow(Error(kNotSupportedError));
1037 }
1038
1039 if (writable &&
1040 !app_file_handler_util::HasFileSystemWritePermission(extension_.get())) {
1041 return RespondNow(Error(kRequiresFileSystemWriteError));
1042 }
1043
1044 VolumeInfo volume_info;
1045 if (!volume_manager->FindVolumeInfoById(params->options.volume_id,
1046 &volume_info)) {
1047 return RespondNow(Error(kVolumeNotFoundError));
1048 }
1049
1050 const GURL site = extensions::util::GetSiteForExtensionId(
1051 extension_id(), chrome_details_.GetProfile());
1052 scoped_refptr<storage::FileSystemContext> file_system_context =
1053 content::BrowserContext::GetStoragePartitionForSite(
1054 chrome_details_.GetProfile(), site)->GetFileSystemContext();
1055 storage::ExternalFileSystemBackend* const backend =
1056 file_system_context->external_backend();
1057 DCHECK(backend);
1058
1059 base::FilePath virtual_path;
1060 if (!backend->GetVirtualPath(volume_info.mount_path, &virtual_path))
1061 return RespondNow(Error(kSecurityError));
1062
1063 if (writable && (volume_info.is_read_only))
1064 return RespondNow(Error(kSecurityError));
1065
1066 const bool requires_consent =
1067 !chromeos::KioskAppManager::Get()->IsAutoLaunchEnabled() &&
1068 extension()->location() != Manifest::COMPONENT;
benwells 2015/03/20 00:42:39 Right now this will never be true due to the check
mtomasz 2015/03/20 01:56:00 Not really. It will be true for kiosk apps launche
benwells 2015/03/20 02:43:57 Ohhh, I'd misread the logic above...
1069 if (!requires_consent) {
1070 // Grant the permission without showing the dialog.
1071 base::ThreadTaskRunnerHandle::Get()->PostTask(
1072 FROM_HERE,
1073 base::Bind(&FileSystemRequestFileSystemFunction::OnConsentReceived,
1074 this, volume_info.volume_id, writable, true /* granted */));
1075 } else {
1076 // TODO(mtomasz): Create a better display name, which is the most meaningful
1077 // to the user.
1078 const std::string display_name = !volume_info.volume_label.empty()
1079 ? volume_info.volume_label
1080 : volume_info.volume_id;
1081 RequestConsent(
1082 display_name, writable,
1083 base::Bind(&FileSystemRequestFileSystemFunction::OnConsentReceived,
1084 this, volume_info.volume_id, writable));
1085 }
1086
1087 return RespondLater();
1088 #endif
1089 }
1090
1091 #if defined(OS_CHROMEOS)
1092 void FileSystemRequestFileSystemFunction::RequestConsent(
1093 const std::string& display_name,
1094 bool writable,
1095 const base::Callback<void(bool)>& callback) {
1096 // TODO(mtomasz): Implement the consent dialog.
1097 callback.Run(false);
benwells 2015/03/20 00:42:39 I think you should use PostTask here, as you're ca
mtomasz 2015/03/20 01:56:00 Done.
1098 }
1099
1100 void FileSystemRequestFileSystemFunction::OnConsentReceived(
1101 const std::string& volume_id,
1102 bool writable,
1103 bool granted) {
1104 using file_manager::VolumeManager;
1105 using file_manager::VolumeInfo;
1106
1107 if (!granted) {
1108 SetError(kSecurityError);
1109 SendResponse(false);
1110 return;
1111 }
1112
1113 // Fetch the volume again, in case it's gone by the time the permission is
1114 // granted.
1115 VolumeManager* const volume_manager =
1116 VolumeManager::Get(chrome_details_.GetProfile());
1117 DCHECK(volume_manager);
1118
1119 VolumeInfo volume_info;
1120 if (!volume_manager->FindVolumeInfoById(volume_id, &volume_info)) {
1121 SetError(kVolumeNotFoundError);
1122 SendResponse(false);
1123 return;
1124 }
1125
1126 const GURL site = extensions::util::GetSiteForExtensionId(
1127 extension_id(), chrome_details_.GetProfile());
1128 scoped_refptr<storage::FileSystemContext> file_system_context =
1129 content::BrowserContext::GetStoragePartitionForSite(
1130 chrome_details_.GetProfile(), site)->GetFileSystemContext();
1131 storage::ExternalFileSystemBackend* const backend =
1132 file_system_context->external_backend();
1133 DCHECK(backend);
1134
1135 // The volume may be unmounted and remounted by the time we reach this logic.
1136 // TODO(mtomasz): Add a unique identifier to VolumeInfo to guarantee that the
1137 // permissions are granted to exactly that volume which was plugged in when
1138 // the dialog was shown.
1139 base::FilePath virtual_path;
1140 if (!backend->GetVirtualPath(volume_info.mount_path, &virtual_path)) {
1141 SetError(kSecurityError);
benwells 2015/03/20 00:42:39 Is this the correct error?
mtomasz 2015/03/20 01:56:00 GetVirtualPath() is not used to check if the volum
1142 SendResponse(false);
1143 return;
1144 }
1145
1146 storage::IsolatedContext* const isolated_context =
1147 storage::IsolatedContext::GetInstance();
1148 DCHECK(isolated_context);
1149
1150 const storage::FileSystemURL original_url =
1151 file_system_context->CreateCrackedFileSystemURL(
1152 GURL("chrome-extension://" + extension_id()),
benwells 2015/03/20 00:42:39 I think there is a constant you can use for the sc
mtomasz 2015/03/20 01:56:00 Done.
1153 storage::kFileSystemTypeExternal, virtual_path);
1154
1155 // Set a fixed register name, as the automatic one would leak the mount point
1156 // directory.
1157 std::string register_name = "fs";
1158 const std::string file_system_id =
1159 isolated_context->RegisterFileSystemForPath(
1160 storage::kFileSystemTypeNativeForPlatformApp,
1161 std::string() /* file_system_id */, original_url.path(),
1162 &register_name);
1163 if (file_system_id.empty()) {
1164 SetError(kSecurityError);
1165 SendResponse(false);
1166 return;
1167 }
1168
1169 backend->GrantFileAccessToExtension(extension_->id(), virtual_path);
1170
1171 // Grant file permissions to the renderer hosting component.
1172 content::ChildProcessSecurityPolicy* policy =
1173 content::ChildProcessSecurityPolicy::GetInstance();
1174 DCHECK(policy);
1175
1176 // Read-only permisisons.
1177 policy->GrantReadFile(render_view_host()->GetProcess()->GetID(),
1178 volume_info.mount_path);
1179 policy->GrantReadFileSystem(render_view_host()->GetProcess()->GetID(),
1180 file_system_id);
1181
1182 // Additional write permissions.
1183 if (writable) {
1184 policy->GrantCreateReadWriteFile(render_view_host()->GetProcess()->GetID(),
1185 volume_info.mount_path);
1186 policy->GrantCopyInto(render_view_host()->GetProcess()->GetID(),
1187 volume_info.mount_path);
1188 policy->GrantWriteFileSystem(render_view_host()->GetProcess()->GetID(),
1189 file_system_id);
1190 policy->GrantDeleteFromFileSystem(render_view_host()->GetProcess()->GetID(),
1191 file_system_id);
1192 policy->GrantCreateFileForFileSystem(
1193 render_view_host()->GetProcess()->GetID(), file_system_id);
1194 }
1195
1196 base::DictionaryValue* const dict = new base::DictionaryValue();
1197 dict->SetString("file_system_id", file_system_id);
1198 dict->SetString("file_system_path", register_name);
1199
1200 SetResult(dict);
1201 SendResponse(true);
1202 }
1203 #endif
1204
997 } // namespace extensions 1205 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698