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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
6
7 #include "base/files/file.h"
8 #include "base/files/file_path.h"
9 #include "base/files/file_util.h"
10 #include "build/build_config.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/child_process_security_policy.h"
14 #include "extensions/browser/api/extensions_api_client.h"
15 #include "extensions/browser/entry_info.h"
16 #include "extensions/browser/extension_prefs.h"
17 #include "extensions/browser/granted_file_entry.h"
18 #include "extensions/common/permissions/permissions_data.h"
19 #include "net/base/mime_util.h"
20 #include "storage/browser/fileapi/isolated_context.h"
21 #include "storage/common/fileapi/file_system_mount_option.h"
22 #include "storage/common/fileapi/file_system_types.h"
23
24 #if defined(OS_CHROMEOS)
25 #include "extensions/browser/api/file_handlers/non_native_file_system_delegate.h "
26 #endif
27
28 namespace extensions {
29
30 namespace app_file_handler_util {
31
32 const char kInvalidParameters[] = "Invalid parameters";
33 const char kSecurityError[] = "Security error";
34
35 namespace {
36
37 bool FileHandlerCanHandleFileWithExtension(const FileHandlerInfo& handler,
38 const base::FilePath& path) {
39 for (std::set<std::string>::const_iterator extension =
40 handler.extensions.begin();
41 extension != handler.extensions.end(); ++extension) {
42 if (*extension == "*")
43 return true;
44
45 // Accept files whose extension or combined extension (e.g. ".tar.gz")
46 // match the supported extensions of file handler.
47 base::FilePath::StringType handler_extention(
48 base::FilePath::kExtensionSeparator +
49 base::FilePath::FromUTF8Unsafe(*extension).value());
50 if (base::FilePath::CompareEqualIgnoreCase(handler_extention,
51 path.Extension()) ||
52 base::FilePath::CompareEqualIgnoreCase(handler_extention,
53 path.FinalExtension())) {
54 return true;
55 }
56
57 // Also accept files with no extension for handlers that support an
58 // empty extension, i.e. both "foo" and "foo." match.
59 if (extension->empty() &&
60 path.MatchesExtension(base::FilePath::StringType())) {
61 return true;
62 }
63 }
64 return false;
65 }
66
67 bool FileHandlerCanHandleFileWithMimeType(const FileHandlerInfo& handler,
68 const std::string& mime_type) {
69 for (std::set<std::string>::const_iterator type = handler.types.begin();
70 type != handler.types.end(); ++type) {
71 if (net::MatchesMimeType(*type, mime_type))
72 return true;
73 }
74 return false;
75 }
76
77 bool PrepareNativeLocalFileForWritableApp(const base::FilePath& path,
78 bool is_directory) {
79 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE);
80
81 // Don't allow links.
82 if (base::PathExists(path) && base::IsLink(path))
83 return false;
84
85 if (is_directory)
86 return base::DirectoryExists(path);
87
88 // Create the file if it doesn't already exist.
89 int creation_flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ;
90 base::File file(path, creation_flags);
91
92 return file.IsValid();
93 }
94
95 // Checks whether a list of paths are all OK for writing and calls a provided
96 // on_success or on_failure callback when done. A path is OK for writing if it
97 // is not a symlink, is not in a blacklisted path and can be opened for writing.
98 // Creates files if they do not exist, but fails for non-existent directory
99 // paths. On Chrome OS, also fails for non-local files that don't already exist.
100 class WritableFileChecker
101 : public base::RefCountedThreadSafe<WritableFileChecker> {
102 public:
103 WritableFileChecker(
104 const std::vector<base::FilePath>& paths,
105 Profile* profile,
106 const std::set<base::FilePath>& directory_paths,
107 const base::Closure& on_success,
108 const base::Callback<void(const base::FilePath&)>& on_failure);
109
110 void Check();
111
112 private:
113 friend class base::RefCountedThreadSafe<WritableFileChecker>;
114 virtual ~WritableFileChecker();
115
116 // Called when a work item is completed. If all work items are done, this
117 // calls the success or failure callback.
118 void TaskDone();
119
120 // Reports an error in completing a work item. This may be called more than
121 // once, but only the last message will be retained.
122 void Error(const base::FilePath& error_path);
123
124 void CheckLocalWritableFiles();
125
126 // Called when processing a file is completed with either a success or an
127 // error.
128 void OnPrepareFileDone(const base::FilePath& path, bool success);
129
130 const std::vector<base::FilePath> paths_;
131 Profile* profile_;
132 const std::set<base::FilePath> directory_paths_;
133 int outstanding_tasks_;
134 base::FilePath error_path_;
135 base::Closure on_success_;
136 base::Callback<void(const base::FilePath&)> on_failure_;
137 };
138
139 WritableFileChecker::WritableFileChecker(
140 const std::vector<base::FilePath>& paths,
141 Profile* profile,
142 const std::set<base::FilePath>& directory_paths,
143 const base::Closure& on_success,
144 const base::Callback<void(const base::FilePath&)>& on_failure)
145 : paths_(paths),
146 profile_(profile),
147 directory_paths_(directory_paths),
148 outstanding_tasks_(1),
149 on_success_(on_success),
150 on_failure_(on_failure) {}
151
152 void WritableFileChecker::Check() {
153 outstanding_tasks_ = paths_.size();
154 for (const auto& path : paths_) {
155 bool is_directory = directory_paths_.find(path) != directory_paths_.end();
156 #if defined(OS_CHROMEOS)
157 NonNativeFileSystemDelegate* delegate =
158 ExtensionsAPIClient::Get()->GetNonNativeFileSystemDelegate();
159 if (delegate && delegate->IsUnderNonNativeLocalPath(profile_, path)) {
160 if (is_directory) {
161 delegate->IsNonNativeLocalPathDirectory(
162 profile_,
163 path,
164 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
165 } else {
166 delegate->PrepareNonNativeLocalFileForWritableApp(
167 profile_,
168 path,
169 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
170 }
171 continue;
172 }
173 #endif
174 content::BrowserThread::PostTaskAndReplyWithResult(
175 content::BrowserThread::FILE, FROM_HERE,
176 base::Bind(&PrepareNativeLocalFileForWritableApp, path, is_directory),
177 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
178 }
179 }
180
181 WritableFileChecker::~WritableFileChecker() {}
182
183 void WritableFileChecker::TaskDone() {
184 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
185 if (--outstanding_tasks_ == 0) {
186 if (error_path_.empty())
187 on_success_.Run();
188 else
189 on_failure_.Run(error_path_);
190 }
191 }
192
193 // Reports an error in completing a work item. This may be called more than
194 // once, but only the last message will be retained.
195 void WritableFileChecker::Error(const base::FilePath& error_path) {
196 DCHECK(!error_path.empty());
197 error_path_ = error_path;
198 TaskDone();
199 }
200
201 void WritableFileChecker::OnPrepareFileDone(const base::FilePath& path,
202 bool success) {
203 if (success)
204 TaskDone();
205 else
206 Error(path);
207 }
208
209 } // namespace
210
211 const FileHandlerInfo* FileHandlerForId(const Extension& app,
212 const std::string& handler_id) {
213 const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
214 if (!file_handlers)
215 return NULL;
216
217 for (FileHandlersInfo::const_iterator i = file_handlers->begin();
218 i != file_handlers->end(); i++) {
219 if (i->id == handler_id)
220 return &*i;
221 }
222 return NULL;
223 }
224
225 std::vector<const FileHandlerInfo*> FindFileHandlersForEntries(
226 const Extension& app,
227 const std::vector<EntryInfo> entries) {
228 std::vector<const FileHandlerInfo*> handlers;
229 if (entries.empty())
230 return handlers;
231
232 // Look for file handlers which can handle all the MIME types specified.
233 const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
234 if (!file_handlers)
235 return handlers;
236
237 for (FileHandlersInfo::const_iterator data = file_handlers->begin();
238 data != file_handlers->end(); ++data) {
239 bool handles_all_types = true;
240 for (std::vector<EntryInfo>::const_iterator it = entries.begin();
241 it != entries.end(); ++it) {
242 if (!FileHandlerCanHandleEntry(*data, *it)) {
243 handles_all_types = false;
244 break;
245 }
246 }
247 if (handles_all_types)
248 handlers.push_back(&*data);
249 }
250 return handlers;
251 }
252
253 bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler,
254 const EntryInfo& entry) {
255 if (entry.is_directory)
256 return handler.include_directories;
257
258 return FileHandlerCanHandleFileWithMimeType(handler, entry.mime_type) ||
259 FileHandlerCanHandleFileWithExtension(handler, entry.path);
260 }
261
262 GrantedFileEntry CreateFileEntry(Profile* profile,
263 const Extension* extension,
264 int renderer_id,
265 const base::FilePath& path,
266 bool is_directory) {
267 GrantedFileEntry result;
268 storage::IsolatedContext* isolated_context =
269 storage::IsolatedContext::GetInstance();
270 DCHECK(isolated_context);
271
272 result.filesystem_id = isolated_context->RegisterFileSystemForPath(
273 storage::kFileSystemTypeNativeForPlatformApp, std::string(), path,
274 &result.registered_name);
275
276 content::ChildProcessSecurityPolicy* policy =
277 content::ChildProcessSecurityPolicy::GetInstance();
278 policy->GrantReadFileSystem(renderer_id, result.filesystem_id);
279 if (HasFileSystemWritePermission(extension)) {
280 if (is_directory) {
281 policy->GrantCreateReadWriteFileSystem(renderer_id, result.filesystem_id);
282 } else {
283 policy->GrantWriteFileSystem(renderer_id, result.filesystem_id);
284 policy->GrantDeleteFromFileSystem(renderer_id, result.filesystem_id);
285 }
286 }
287
288 result.id = result.filesystem_id + ":" + result.registered_name;
289 return result;
290 }
291
292 void PrepareFilesForWritableApp(
293 const std::vector<base::FilePath>& paths,
294 Profile* profile,
295 const std::set<base::FilePath>& directory_paths,
296 const base::Closure& on_success,
297 const base::Callback<void(const base::FilePath&)>& on_failure) {
298 scoped_refptr<WritableFileChecker> checker(new WritableFileChecker(
299 paths, profile, directory_paths, on_success, on_failure));
300 checker->Check();
301 }
302
303 bool HasFileSystemWritePermission(const Extension* extension) {
304 return extension->permissions_data()->HasAPIPermission(
305 APIPermission::kFileSystemWrite);
306 }
307
308 bool ValidateFileEntryAndGetPath(const std::string& filesystem_name,
309 const std::string& filesystem_path,
310 int render_process_id,
311 base::FilePath* file_path,
312 std::string* error) {
313 if (filesystem_path.empty()) {
314 *error = kInvalidParameters;
315 return false;
316 }
317
318 std::string filesystem_id;
319 if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) {
320 *error = kInvalidParameters;
321 return false;
322 }
323
324 // Only return the display path if the process has read access to the
325 // filesystem.
326 content::ChildProcessSecurityPolicy* policy =
327 content::ChildProcessSecurityPolicy::GetInstance();
328 if (!policy->CanReadFileSystem(render_process_id, filesystem_id)) {
329 *error = kSecurityError;
330 return false;
331 }
332
333 storage::IsolatedContext* context = storage::IsolatedContext::GetInstance();
334 base::FilePath relative_path =
335 base::FilePath::FromUTF8Unsafe(filesystem_path);
336 base::FilePath virtual_path =
337 context->CreateVirtualRootPath(filesystem_id).Append(relative_path);
338 storage::FileSystemType type;
339 storage::FileSystemMountOption mount_option;
340 std::string cracked_id;
341 if (!context->CrackVirtualPath(virtual_path, &filesystem_id, &type,
342 &cracked_id, file_path, &mount_option)) {
343 *error = kInvalidParameters;
344 return false;
345 }
346
347 // The file system API is only intended to operate on file entries that
348 // correspond to a native file, selected by the user so only allow file
349 // systems returned by the file system API or from a drag and drop operation.
350 if (type != storage::kFileSystemTypeNativeForPlatformApp &&
351 type != storage::kFileSystemTypeDragged) {
352 *error = kInvalidParameters;
353 return false;
354 }
355
356 return true;
357 }
358
359 } // namespace app_file_handler_util
360
361 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698