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

Side by Side Diff: extensions/browser/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 "extensions/browser/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 "content/public/browser/browser_context.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 content::BrowserContext* context,
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 content::BrowserContext* context_;
132 const std::set<base::FilePath> directory_paths_;
133 size_t 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 content::BrowserContext* context,
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 context_(context),
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(context_, path)) {
160 if (is_directory) {
161 delegate->IsNonNativeLocalPathDirectory(
162 context_, path,
163 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
164 } else {
165 delegate->PrepareNonNativeLocalFileForWritableApp(
166 context_, path,
167 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
168 }
169 continue;
170 }
171 #endif
172 content::BrowserThread::PostTaskAndReplyWithResult(
173 content::BrowserThread::FILE, FROM_HERE,
174 base::Bind(&PrepareNativeLocalFileForWritableApp, path, is_directory),
175 base::Bind(&WritableFileChecker::OnPrepareFileDone, this, path));
176 }
177 }
178
179 WritableFileChecker::~WritableFileChecker() {}
180
181 void WritableFileChecker::TaskDone() {
182 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
183 if (--outstanding_tasks_ == 0) {
184 if (error_path_.empty())
185 on_success_.Run();
186 else
187 on_failure_.Run(error_path_);
188 }
189 }
190
191 // Reports an error in completing a work item. This may be called more than
192 // once, but only the last message will be retained.
193 void WritableFileChecker::Error(const base::FilePath& error_path) {
194 DCHECK(!error_path.empty());
195 error_path_ = error_path;
196 TaskDone();
197 }
198
199 void WritableFileChecker::OnPrepareFileDone(const base::FilePath& path,
200 bool success) {
201 if (success)
202 TaskDone();
203 else
204 Error(path);
205 }
206
207 } // namespace
208
209 const FileHandlerInfo* FileHandlerForId(const Extension& app,
210 const std::string& handler_id) {
211 const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
212 if (!file_handlers)
213 return NULL;
214
215 for (FileHandlersInfo::const_iterator i = file_handlers->begin();
216 i != file_handlers->end(); i++) {
217 if (i->id == handler_id)
218 return &*i;
219 }
220 return NULL;
221 }
222
223 std::vector<const FileHandlerInfo*> FindFileHandlersForEntries(
224 const Extension& app,
225 const std::vector<EntryInfo> entries) {
226 std::vector<const FileHandlerInfo*> handlers;
227 if (entries.empty())
228 return handlers;
229
230 // Look for file handlers which can handle all the MIME types specified.
231 const FileHandlersInfo* file_handlers = FileHandlers::GetFileHandlers(&app);
232 if (!file_handlers)
233 return handlers;
234
235 for (FileHandlersInfo::const_iterator data = file_handlers->begin();
236 data != file_handlers->end(); ++data) {
237 bool handles_all_types = true;
238 for (std::vector<EntryInfo>::const_iterator it = entries.begin();
239 it != entries.end(); ++it) {
240 if (!FileHandlerCanHandleEntry(*data, *it)) {
241 handles_all_types = false;
242 break;
243 }
244 }
245 if (handles_all_types)
246 handlers.push_back(&*data);
247 }
248 return handlers;
249 }
250
251 bool FileHandlerCanHandleEntry(const FileHandlerInfo& handler,
252 const EntryInfo& entry) {
253 if (entry.is_directory)
254 return handler.include_directories;
255
256 return FileHandlerCanHandleFileWithMimeType(handler, entry.mime_type) ||
257 FileHandlerCanHandleFileWithExtension(handler, entry.path);
258 }
259
260 GrantedFileEntry CreateFileEntry(content::BrowserContext* context,
261 const Extension* extension,
262 int renderer_id,
263 const base::FilePath& path,
264 bool is_directory) {
265 GrantedFileEntry result;
266 storage::IsolatedContext* isolated_context =
267 storage::IsolatedContext::GetInstance();
268 DCHECK(isolated_context);
269
270 result.filesystem_id = isolated_context->RegisterFileSystemForPath(
271 storage::kFileSystemTypeNativeForPlatformApp, std::string(), path,
272 &result.registered_name);
273
274 content::ChildProcessSecurityPolicy* policy =
275 content::ChildProcessSecurityPolicy::GetInstance();
276 policy->GrantReadFileSystem(renderer_id, result.filesystem_id);
277 if (HasFileSystemWritePermission(extension)) {
278 if (is_directory) {
279 policy->GrantCreateReadWriteFileSystem(renderer_id, result.filesystem_id);
280 } else {
281 policy->GrantWriteFileSystem(renderer_id, result.filesystem_id);
282 policy->GrantDeleteFromFileSystem(renderer_id, result.filesystem_id);
283 }
284 }
285
286 result.id = result.filesystem_id + ":" + result.registered_name;
287 return result;
288 }
289
290 void PrepareFilesForWritableApp(
291 const std::vector<base::FilePath>& paths,
292 content::BrowserContext* context,
293 const std::set<base::FilePath>& directory_paths,
294 const base::Closure& on_success,
295 const base::Callback<void(const base::FilePath&)>& on_failure) {
296 scoped_refptr<WritableFileChecker> checker(new WritableFileChecker(
297 paths, context, directory_paths, on_success, on_failure));
298 checker->Check();
299 }
300
301 bool HasFileSystemWritePermission(const Extension* extension) {
302 return extension->permissions_data()->HasAPIPermission(
303 APIPermission::kFileSystemWrite);
304 }
305
306 bool ValidateFileEntryAndGetPath(const std::string& filesystem_name,
307 const std::string& filesystem_path,
308 int render_process_id,
309 base::FilePath* file_path,
310 std::string* error) {
311 if (filesystem_path.empty()) {
312 *error = kInvalidParameters;
313 return false;
314 }
315
316 std::string filesystem_id;
317 if (!storage::CrackIsolatedFileSystemName(filesystem_name, &filesystem_id)) {
318 *error = kInvalidParameters;
319 return false;
320 }
321
322 // Only return the display path if the process has read access to the
323 // filesystem.
324 content::ChildProcessSecurityPolicy* policy =
325 content::ChildProcessSecurityPolicy::GetInstance();
326 if (!policy->CanReadFileSystem(render_process_id, filesystem_id)) {
327 *error = kSecurityError;
328 return false;
329 }
330
331 storage::IsolatedContext* context = storage::IsolatedContext::GetInstance();
332 base::FilePath relative_path =
333 base::FilePath::FromUTF8Unsafe(filesystem_path);
334 base::FilePath virtual_path =
335 context->CreateVirtualRootPath(filesystem_id).Append(relative_path);
336 storage::FileSystemType type;
337 storage::FileSystemMountOption mount_option;
338 std::string cracked_id;
339 if (!context->CrackVirtualPath(virtual_path, &filesystem_id, &type,
340 &cracked_id, file_path, &mount_option)) {
341 *error = kInvalidParameters;
342 return false;
343 }
344
345 // The file system API is only intended to operate on file entries that
346 // correspond to a native file, selected by the user so only allow file
347 // systems returned by the file system API or from a drag and drop operation.
348 if (type != storage::kFileSystemTypeNativeForPlatformApp &&
349 type != storage::kFileSystemTypeDragged) {
350 *error = kInvalidParameters;
351 return false;
352 }
353
354 return true;
355 }
356
357 } // namespace app_file_handler_util
358
359 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698