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

Side by Side Diff: chrome/browser/chromeos/extensions/file_browser_extension_api.cc

Issue 8619007: Revert "Move a bunch of ChromeOS APIs out of chrome/browser/extensions." (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 1 month 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/chromeos/extensions/file_browser_extension_api.h"
6
7 #include "base/base64.h"
8 #include "base/bind.h"
9 #include "base/command_line.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/memory/singleton.h"
13 #include "base/string_util.h"
14 #include "base/stringprintf.h"
15 #include "base/time.h"
16 #include "base/values.h"
17 #include "chrome/browser/chromeos/extensions/file_browser_event_router.h"
18 #include "chrome/browser/chromeos/extensions/file_manager_util.h"
19 #include "chrome/browser/extensions/extension_event_router.h"
20 #include "chrome/browser/extensions/extension_function_dispatcher.h"
21 #include "chrome/browser/extensions/extension_process_manager.h"
22 #include "chrome/browser/extensions/extension_service.h"
23 #include "chrome/browser/extensions/extension_tab_util.h"
24 #include "chrome/browser/extensions/process_map.h"
25 #include "chrome/browser/prefs/pref_service.h"
26 #include "chrome/browser/prefs/scoped_user_pref_update.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/ui/browser.h"
29 #include "chrome/browser/ui/views/select_file_dialog_extension.h"
30 #include "chrome/browser/ui/webui/extension_icon_source.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/extensions/extension.h"
33 #include "chrome/common/extensions/file_browser_handler.h"
34 #include "chrome/common/pref_names.h"
35 #include "content/browser/child_process_security_policy.h"
36 #include "content/browser/renderer_host/render_view_host.h"
37 #include "content/browser/tab_contents/tab_contents.h"
38 #include "content/public/browser/browser_thread.h"
39 #include "content/public/browser/render_process_host.h"
40 #include "googleurl/src/gurl.h"
41 #include "grit/generated_resources.h"
42 #include "grit/platform_locale_settings.h"
43 #include "ui/base/l10n/l10n_util.h"
44 #include "webkit/fileapi/file_system_context.h"
45 #include "webkit/fileapi/file_system_file_util.h"
46 #include "webkit/fileapi/file_system_mount_point_provider.h"
47 #include "webkit/fileapi/file_system_operation.h"
48 #include "webkit/fileapi/file_system_operation_context.h"
49 #include "webkit/fileapi/file_system_path_manager.h"
50 #include "webkit/fileapi/file_system_types.h"
51 #include "webkit/fileapi/file_system_util.h"
52
53 using content::BrowserThread;
54
55 namespace {
56
57 // Error messages.
58 const char kFileError[] = "File error %d";
59 const char kInvalidFileUrl[] = "Invalid file URL";
60 const char kVolumeDevicePathNotFound[] = "Device path not found";
61
62 #ifdef OS_CHROMEOS
63 // Volume type strings.
64 const char kVolumeTypeFlash[] = "flash";
65 const char kVolumeTypeOptical[] = "optical";
66 const char kVolumeTypeHardDrive[] = "hdd";
67 const char kVolumeTypeUnknown[] = "undefined";
68 #endif
69
70 // Internal task ids.
71 const char kEnqueueTaskId[] = "enqueue";
72
73 const int kReadOnlyFilePermissions = base::PLATFORM_FILE_OPEN |
74 base::PLATFORM_FILE_READ |
75 base::PLATFORM_FILE_EXCLUSIVE_READ |
76 base::PLATFORM_FILE_ASYNC;
77
78 const int kReadWriteFilePermissions = base::PLATFORM_FILE_OPEN |
79 base::PLATFORM_FILE_CREATE |
80 base::PLATFORM_FILE_OPEN_ALWAYS |
81 base::PLATFORM_FILE_CREATE_ALWAYS |
82 base::PLATFORM_FILE_OPEN_TRUNCATED |
83 base::PLATFORM_FILE_READ |
84 base::PLATFORM_FILE_WRITE |
85 base::PLATFORM_FILE_EXCLUSIVE_READ |
86 base::PLATFORM_FILE_EXCLUSIVE_WRITE |
87 base::PLATFORM_FILE_ASYNC |
88 base::PLATFORM_FILE_WRITE_ATTRIBUTES;
89
90 struct LastUsedHandler {
91 LastUsedHandler(int t, const FileBrowserHandler* h, URLPatternSet p)
92 : timestamp(t),
93 handler(h),
94 patterns(p) {
95 }
96
97 int timestamp;
98 const FileBrowserHandler* handler;
99 URLPatternSet patterns;
100 };
101
102 typedef std::vector<LastUsedHandler> LastUsedHandlerList;
103 typedef std::set<const FileBrowserHandler*> ActionSet;
104
105 // Breaks down task_id that is used between getFileTasks() and executeTask() on
106 // its building blocks. task_id field the following structure:
107 // <extension-id>|<task-action-id>
108 // Currently, the only supported task-type is of 'context'.
109 bool CrackTaskIdentifier(const std::string& task_id,
110 std::string* target_extension_id,
111 std::string* action_id) {
112 std::vector<std::string> result;
113 int count = Tokenize(task_id, std::string("|"), &result);
114 if (count != 2)
115 return false;
116 *target_extension_id = result[0];
117 *action_id = result[1];
118 return true;
119 }
120
121 std::string MakeTaskID(const char* extension_id,
122 const char* action_id) {
123 return base::StringPrintf("%s|%s", extension_id, action_id);
124 }
125
126 bool GetFileBrowserHandlers(Profile* profile,
127 const GURL& selected_file_url,
128 ActionSet* results) {
129 ExtensionService* service = profile->GetExtensionService();
130 if (!service)
131 return false; // In unit-tests, we may not have an ExtensionService.
132
133 for (ExtensionList::const_iterator iter = service->extensions()->begin();
134 iter != service->extensions()->end();
135 ++iter) {
136 const Extension* extension = iter->get();
137 if (!extension->file_browser_handlers())
138 continue;
139
140 for (Extension::FileBrowserHandlerList::const_iterator action_iter =
141 extension->file_browser_handlers()->begin();
142 action_iter != extension->file_browser_handlers()->end();
143 ++action_iter) {
144 const FileBrowserHandler* action = action_iter->get();
145 if (!action->MatchesURL(selected_file_url))
146 continue;
147
148 results->insert(action_iter->get());
149 }
150 }
151 return true;
152 }
153
154 bool SortByLastUsedTimestampDesc(const LastUsedHandler& a,
155 const LastUsedHandler& b) {
156 return a.timestamp > b.timestamp;
157 }
158
159 // TODO(zelidrag): Wire this with ICU to make this sort I18N happy.
160 bool SortByTaskName(const LastUsedHandler& a, const LastUsedHandler& b) {
161 return base::strcasecmp(a.handler->title().data(),
162 b.handler->title().data()) > 0;
163 }
164
165 void SortLastUsedHandlerList(LastUsedHandlerList *list) {
166 // Sort by the last used descending.
167 std::sort(list->begin(), list->end(), SortByLastUsedTimestampDesc);
168 if (list->size() > 1) {
169 // Sort the rest by name.
170 std::sort(list->begin() + 1, list->end(), SortByTaskName);
171 }
172 }
173
174 URLPatternSet GetAllMatchingPatterns(const FileBrowserHandler* handler,
175 const std::vector<GURL>& files_list) {
176 URLPatternSet matching_patterns;
177 const URLPatternSet& patterns = handler->file_url_patterns();
178 for (URLPatternSet::const_iterator pattern_it = patterns.begin();
179 pattern_it != patterns.end(); ++pattern_it) {
180 for (std::vector<GURL>::const_iterator file_it = files_list.begin();
181 file_it != files_list.end(); ++file_it) {
182 if (pattern_it->MatchesURL(*file_it)) {
183 matching_patterns.AddPattern(*pattern_it);
184 break;
185 }
186 }
187 }
188
189 return matching_patterns;
190 }
191
192 // Given the list of selected files, returns array of context menu tasks
193 // that are shared
194 bool FindCommonTasks(Profile* profile,
195 const std::vector<GURL>& files_list,
196 LastUsedHandlerList* named_action_list) {
197 named_action_list->clear();
198 ActionSet common_tasks;
199 for (std::vector<GURL>::const_iterator it = files_list.begin();
200 it != files_list.end(); ++it) {
201 ActionSet file_actions;
202 if (!GetFileBrowserHandlers(profile, *it, &file_actions))
203 return false;
204 // If there is nothing to do for one file, the intersection of tasks for all
205 // files will be empty at the end.
206 if (!file_actions.size())
207 return true;
208
209 // For the very first file, just copy elements.
210 if (it == files_list.begin()) {
211 common_tasks = file_actions;
212 } else {
213 if (common_tasks.size()) {
214 // For all additional files, find intersection between the accumulated
215 // and file specific set.
216 ActionSet intersection;
217 std::set_intersection(common_tasks.begin(), common_tasks.end(),
218 file_actions.begin(), file_actions.end(),
219 std::inserter(intersection,
220 intersection.begin()));
221 common_tasks = intersection;
222 }
223 }
224 }
225
226 const DictionaryValue* prefs_tasks =
227 profile->GetPrefs()->GetDictionary(prefs::kLastUsedFileBrowserHandlers);
228 for (ActionSet::const_iterator iter = common_tasks.begin();
229 iter != common_tasks.end(); ++iter) {
230 // Get timestamp of when this task was used last time.
231 int last_used_timestamp = 0;
232 prefs_tasks->GetInteger(MakeTaskID((*iter)->extension_id().data(),
233 (*iter)->id().data()),
234 &last_used_timestamp);
235 URLPatternSet matching_patterns = GetAllMatchingPatterns(*iter, files_list);
236 named_action_list->push_back(LastUsedHandler(last_used_timestamp, *iter,
237 matching_patterns));
238 }
239
240 SortLastUsedHandlerList(named_action_list);
241 return true;
242 }
243
244 ListValue* URLPatternSetToStringList(const URLPatternSet& patterns) {
245 ListValue* list = new ListValue();
246 for (URLPatternSet::const_iterator it = patterns.begin();
247 it != patterns.end(); ++it) {
248 list->Append(new StringValue(it->GetAsString()));
249 }
250
251 return list;
252 }
253
254 // Update file handler usage stats.
255 void UpdateFileHandlerUsageStats(Profile* profile, const std::string& task_id) {
256 if (!profile || !profile->GetPrefs())
257 return;
258 DictionaryPrefUpdate prefs_usage_update(profile->GetPrefs(),
259 prefs::kLastUsedFileBrowserHandlers);
260 prefs_usage_update->SetWithoutPathExpansion(task_id,
261 new base::FundamentalValue(
262 static_cast<int>(base::Time::Now().ToInternalValue()/
263 base::Time::kMicrosecondsPerSecond)));
264 }
265
266 #ifdef OS_CHROMEOS
267 base::DictionaryValue* MountPointToValue(Profile* profile,
268 const chromeos::disks::DiskMountManager::MountPointInfo& mount_point_info) {
269
270 base::DictionaryValue *mount_info = new base::DictionaryValue();
271
272 mount_info->SetString("mountType",
273 chromeos::disks::DiskMountManager::MountTypeToString(
274 mount_point_info.mount_type));
275
276 if (mount_point_info.mount_type == chromeos::MOUNT_TYPE_ARCHIVE) {
277 GURL source_url;
278 if (file_manager_util::ConvertFileToFileSystemUrl(profile,
279 FilePath(mount_point_info.source_path),
280 file_manager_util::GetFileBrowserExtensionUrl().GetOrigin(),
281 &source_url)) {
282 mount_info->SetString("sourceUrl", source_url.spec());
283 }
284 } else {
285 mount_info->SetString("sourceUrl", mount_point_info.source_path);
286 }
287
288 FilePath relative_mount_path;
289 // Convert mount point path to relative path with the external file system
290 // exposed within File API.
291 if (file_manager_util::ConvertFileToRelativeFileSystemPath(profile,
292 FilePath(mount_point_info.mount_path),
293 &relative_mount_path)) {
294 mount_info->SetString("mountPath", relative_mount_path.value());
295 }
296
297 mount_info->SetString("mountCondition",
298 chromeos::disks::DiskMountManager::MountConditionToString(
299 mount_point_info.mount_condition));
300
301 return mount_info;
302 }
303 #endif
304
305 } // namespace
306
307 class RequestLocalFileSystemFunction::LocalFileSystemCallbackDispatcher
308 : public fileapi::FileSystemCallbackDispatcher {
309 public:
310 explicit LocalFileSystemCallbackDispatcher(
311 RequestLocalFileSystemFunction* function,
312 Profile* profile,
313 int child_id,
314 scoped_refptr<const Extension> extension)
315 : function_(function),
316 profile_(profile),
317 child_id_(child_id),
318 extension_(extension) {
319 DCHECK(function_);
320 }
321
322 // fileapi::FileSystemCallbackDispatcher overrides.
323 virtual void DidSucceed() OVERRIDE {
324 NOTREACHED();
325 }
326
327 virtual void DidReadMetadata(const base::PlatformFileInfo& info,
328 const FilePath& unused) OVERRIDE {
329 NOTREACHED();
330 }
331
332 virtual void DidReadDirectory(
333 const std::vector<base::FileUtilProxy::Entry>& entries,
334 bool has_more) OVERRIDE {
335 NOTREACHED();
336 }
337
338 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE {
339 NOTREACHED();
340 }
341
342 virtual void DidOpenFileSystem(const std::string& name,
343 const GURL& root_path) OVERRIDE {
344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
345 // Set up file permission access.
346 if (!SetupFileSystemAccessPermissions()) {
347 DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
348 return;
349 }
350
351 BrowserThread::PostTask(
352 BrowserThread::UI, FROM_HERE,
353 base::Bind(
354 &RequestLocalFileSystemFunction::RespondSuccessOnUIThread,
355 function_,
356 name,
357 root_path));
358 }
359
360 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE {
361 BrowserThread::PostTask(
362 BrowserThread::UI, FROM_HERE,
363 base::Bind(
364 &RequestLocalFileSystemFunction::RespondFailedOnUIThread,
365 function_,
366 error_code));
367 }
368
369 private:
370
371 // Grants file system access permissions to file browser component.
372 bool SetupFileSystemAccessPermissions() {
373 if (!extension_.get())
374 return false;
375
376 // Make sure that only component extension can access the entire
377 // local file system.
378 if (extension_->location() != Extension::COMPONENT
379 #ifndef NDEBUG
380 && !CommandLine::ForCurrentProcess()->HasSwitch(
381 switches::kExposePrivateExtensionApi)
382 #endif
383 ) {
384 NOTREACHED() << "Private method access by non-component extension "
385 << extension_->id();
386 return false;
387 }
388
389 fileapi::FileSystemPathManager* path_manager =
390 profile_->GetFileSystemContext()->path_manager();
391 fileapi::ExternalFileSystemMountPointProvider* provider =
392 path_manager->external_provider();
393 if (!provider)
394 return false;
395
396 // Grant full access to File API from this component extension.
397 provider->GrantFullAccessToExtension(extension_->id());
398
399 // Grant R/W file permissions to the renderer hosting component
400 // extension for all paths exposed by our local file system provider.
401 std::vector<FilePath> root_dirs = provider->GetRootDirectories();
402 for (std::vector<FilePath>::iterator iter = root_dirs.begin();
403 iter != root_dirs.end();
404 ++iter) {
405 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
406 child_id_, *iter, kReadWriteFilePermissions);
407 }
408 return true;
409 }
410
411 RequestLocalFileSystemFunction* function_;
412 Profile* profile_;
413 // Renderer process id.
414 int child_id_;
415 // Extension source URL.
416 scoped_refptr<const Extension> extension_;
417 DISALLOW_COPY_AND_ASSIGN(LocalFileSystemCallbackDispatcher);
418 };
419
420 void RequestLocalFileSystemFunction::RequestOnFileThread(
421 const GURL& source_url, int child_id) {
422 fileapi::FileSystemOperation* operation =
423 new fileapi::FileSystemOperation(
424 new LocalFileSystemCallbackDispatcher(
425 this,
426 profile(),
427 child_id,
428 GetExtension()),
429 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
430 profile()->GetFileSystemContext());
431 GURL origin_url = source_url.GetOrigin();
432 operation->OpenFileSystem(origin_url, fileapi::kFileSystemTypeExternal,
433 false); // create
434 }
435
436 bool RequestLocalFileSystemFunction::RunImpl() {
437 if (!dispatcher() || !render_view_host() || !render_view_host()->process())
438 return false;
439
440 BrowserThread::PostTask(
441 BrowserThread::FILE, FROM_HERE,
442 base::Bind(
443 &RequestLocalFileSystemFunction::RequestOnFileThread,
444 this,
445 source_url_,
446 render_view_host()->process()->GetID()));
447 // Will finish asynchronously.
448 return true;
449 }
450
451 void RequestLocalFileSystemFunction::RespondSuccessOnUIThread(
452 const std::string& name, const GURL& root_path) {
453 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
454 result_.reset(new DictionaryValue());
455 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get());
456 dict->SetString("name", name);
457 dict->SetString("path", root_path.spec());
458 dict->SetInteger("error", base::PLATFORM_FILE_OK);
459 SendResponse(true);
460 }
461
462 void RequestLocalFileSystemFunction::RespondFailedOnUIThread(
463 base::PlatformFileError error_code) {
464 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
465 error_ = base::StringPrintf(kFileError, static_cast<int>(error_code));
466 SendResponse(false);
467 }
468
469 bool FileWatchBrowserFunctionBase::GetLocalFilePath(
470 const GURL& file_url, FilePath* local_path, FilePath* virtual_path) {
471 fileapi::FileSystemPathManager* path_manager =
472 profile_->GetFileSystemContext()->path_manager();
473 GURL file_origin_url;
474 fileapi::FileSystemType type;
475 if (!CrackFileSystemURL(file_url, &file_origin_url, &type,
476 virtual_path)) {
477 return false;
478 }
479 if (type != fileapi::kFileSystemTypeExternal)
480 return false;
481
482 FilePath root_path =
483 path_manager->ValidateFileSystemRootAndGetPathOnFileThread(
484 file_origin_url,
485 fileapi::kFileSystemTypeExternal,
486 *virtual_path,
487 false);
488 if (root_path == FilePath())
489 return false;
490
491 *local_path = root_path.Append(*virtual_path);
492 return true;
493 }
494
495 void FileWatchBrowserFunctionBase::RespondOnUIThread(bool success) {
496 result_.reset(Value::CreateBooleanValue(success));
497 SendResponse(success);
498 }
499
500 bool FileWatchBrowserFunctionBase::RunImpl() {
501 if (!render_view_host() || !render_view_host()->process())
502 return false;
503
504 // First param is url of a file to watch.
505 std::string url;
506 if (!args_->GetString(0, &url) || url.empty())
507 return false;
508
509 GURL file_watch_url(url);
510 BrowserThread::PostTask(
511 BrowserThread::FILE, FROM_HERE,
512 base::Bind(
513 &FileWatchBrowserFunctionBase::RunFileWatchOperationOnFileThread,
514 this,
515 file_watch_url,
516 extension_id()));
517
518 return true;
519 }
520
521 void FileWatchBrowserFunctionBase::RunFileWatchOperationOnFileThread(
522 const GURL& file_url, const std::string& extension_id) {
523 FilePath local_path;
524 FilePath virtual_path;
525 if (!GetLocalFilePath(file_url, &local_path, &virtual_path) ||
526 local_path == FilePath()) {
527 BrowserThread::PostTask(
528 BrowserThread::UI, FROM_HERE,
529 base::Bind(
530 &FileWatchBrowserFunctionBase::RespondOnUIThread,
531 this,
532 false));
533 }
534 if (!PerformFileWatchOperation(local_path, virtual_path, extension_id)) {
535 BrowserThread::PostTask(
536 BrowserThread::UI, FROM_HERE,
537 base::Bind(
538 &FileWatchBrowserFunctionBase::RespondOnUIThread,
539 this,
540 false));
541 }
542 BrowserThread::PostTask(
543 BrowserThread::UI, FROM_HERE,
544 base::Bind(
545 &FileWatchBrowserFunctionBase::RespondOnUIThread,
546 this,
547 true));
548 }
549
550 bool AddFileWatchBrowserFunction::PerformFileWatchOperation(
551 const FilePath& local_path, const FilePath& virtual_path,
552 const std::string& extension_id) {
553 #if defined(OS_CHROMEOS)
554 return profile_->GetExtensionService()->file_browser_event_router()->
555 AddFileWatch(local_path, virtual_path, extension_id);
556 #else
557 return true;
558 #endif // OS_CHROMEOS
559 }
560
561 bool RemoveFileWatchBrowserFunction::PerformFileWatchOperation(
562 const FilePath& local_path, const FilePath& unused,
563 const std::string& extension_id) {
564 #if defined(OS_CHROMEOS)
565 profile_->GetExtensionService()->file_browser_event_router()->
566 RemoveFileWatch(local_path, extension_id);
567 #endif
568 return true;
569 }
570
571 bool GetFileTasksFileBrowserFunction::RunImpl() {
572 ListValue* files_list = NULL;
573 if (!args_->GetList(0, &files_list))
574 return false;
575
576 std::vector<GURL> file_urls;
577 for (size_t i = 0; i < files_list->GetSize(); ++i) {
578 std::string file_url;
579 if (!files_list->GetString(i, &file_url))
580 return false;
581
582 // We need case-insensitive matching, and pattern in handler is already
583 // in lower case.
584 StringToLowerASCII(&file_url);
585 file_urls.push_back(GURL(file_url));
586 }
587
588 ListValue* result_list = new ListValue();
589 result_.reset(result_list);
590
591 LastUsedHandlerList common_tasks;
592 if (!FindCommonTasks(profile_, file_urls, &common_tasks))
593 return false;
594
595 ExtensionService* service = profile_->GetExtensionService();
596 for (LastUsedHandlerList::const_iterator iter = common_tasks.begin();
597 iter != common_tasks.end();
598 ++iter) {
599 const FileBrowserHandler* handler = iter->handler;
600 const std::string extension_id = handler->extension_id();
601 const Extension* extension = service->GetExtensionById(extension_id, false);
602 CHECK(extension);
603 DictionaryValue* task = new DictionaryValue();
604 task->SetString("taskId", MakeTaskID(extension_id.data(),
605 handler->id().data()));
606 task->SetString("title", handler->title());
607 task->Set("patterns", URLPatternSetToStringList(iter->patterns));
608 // TODO(zelidrag): Figure out how to expose icon URL that task defined in
609 // manifest instead of the default extension icon.
610 GURL icon =
611 ExtensionIconSource::GetIconURL(extension,
612 Extension::EXTENSION_ICON_BITTY,
613 ExtensionIconSet::MATCH_BIGGER,
614 false, NULL); // grayscale
615 task->SetString("iconUrl", icon.spec());
616 result_list->Append(task);
617 }
618
619 // TODO(zelidrag, serya): Add intent content tasks to result_list once we
620 // implement that API.
621 SendResponse(true);
622 return true;
623 }
624
625 class ExecuteTasksFileBrowserFunction::ExecuteTasksFileSystemCallbackDispatcher
626 : public fileapi::FileSystemCallbackDispatcher {
627 public:
628 explicit ExecuteTasksFileSystemCallbackDispatcher(
629 ExecuteTasksFileBrowserFunction* function,
630 Profile* profile,
631 int child_id,
632 const GURL& source_url,
633 scoped_refptr<const Extension> extension,
634 const std::string task_id,
635 const std::vector<GURL>& file_urls)
636 : function_(function),
637 target_process_id_(0),
638 profile_(profile),
639 source_url_(source_url),
640 extension_(extension),
641 task_id_(task_id),
642 origin_file_urls_(file_urls) {
643 DCHECK(function_);
644 ExtractTargetExtensionAndProcessID();
645 }
646
647 // fileapi::FileSystemCallbackDispatcher overrides.
648 virtual void DidSucceed() OVERRIDE {
649 NOTREACHED();
650 }
651
652 virtual void DidReadMetadata(const base::PlatformFileInfo& info,
653 const FilePath& unused) OVERRIDE {
654 NOTREACHED();
655 }
656
657 virtual void DidReadDirectory(
658 const std::vector<base::FileUtilProxy::Entry>& entries,
659 bool has_more) OVERRIDE {
660 NOTREACHED();
661 }
662
663 virtual void DidWrite(int64 bytes, bool complete) OVERRIDE {
664 NOTREACHED();
665 }
666
667 virtual void DidOpenFileSystem(const std::string& file_system_name,
668 const GURL& file_system_root) OVERRIDE {
669 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
670 ExecuteTasksFileBrowserFunction::FileDefinitionList file_list;
671 for (std::vector<GURL>::iterator iter = origin_file_urls_.begin();
672 iter != origin_file_urls_.end();
673 ++iter) {
674 // Set up file permission access.
675 ExecuteTasksFileBrowserFunction::FileDefinition file;
676 if (!SetupFileAccessPermissions(*iter, &file.target_file_url,
677 &file.virtual_path, &file.is_directory)) {
678 continue;
679 }
680 file_list.push_back(file);
681 }
682 if (file_list.empty()) {
683 BrowserThread::PostTask(
684 BrowserThread::UI, FROM_HERE,
685 base::Bind(
686 &ExecuteTasksFileBrowserFunction::ExecuteFailedOnUIThread,
687 function_));
688 return;
689 }
690
691 BrowserThread::PostTask(
692 BrowserThread::UI, FROM_HERE,
693 base::Bind(
694 &ExecuteTasksFileBrowserFunction::ExecuteFileActionsOnUIThread,
695 function_,
696 task_id_,
697 file_system_name,
698 file_system_root,
699 file_list));
700 }
701
702 virtual void DidFail(base::PlatformFileError error_code) OVERRIDE {
703 BrowserThread::PostTask(
704 BrowserThread::UI, FROM_HERE,
705 base::Bind(
706 &ExecuteTasksFileBrowserFunction::ExecuteFailedOnUIThread,
707 function_));
708 }
709
710 private:
711 // Extracts target extension's id and process from the tasks's id.
712 void ExtractTargetExtensionAndProcessID() {
713 // Get task details.
714 std::string action_id;
715 if (!CrackTaskIdentifier(task_id_, &target_extension_id_, &action_id))
716 return;
717
718 GURL extension_url =
719 Extension::GetBaseURLFromExtensionId(target_extension_id_);
720 ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
721
722 SiteInstance* site_instance = manager->GetSiteInstanceForURL(extension_url);
723 if (!site_instance || !site_instance->HasProcess())
724 return;
725 content::RenderProcessHost* process = site_instance->GetProcess();
726
727 target_process_id_ = process->GetID();
728 }
729
730 // Checks legitimacy of file url and grants file RO access permissions from
731 // handler (target) extension and its renderer process.
732 bool SetupFileAccessPermissions(const GURL& origin_file_url,
733 GURL* target_file_url, FilePath* file_path, bool* is_directory) {
734 if (!extension_.get())
735 return false;
736
737 if (target_process_id_ == 0)
738 return false;
739
740 GURL file_origin_url;
741 FilePath virtual_path;
742 fileapi::FileSystemType type;
743 if (!CrackFileSystemURL(origin_file_url, &file_origin_url, &type,
744 &virtual_path)) {
745 return false;
746 }
747
748 if (type != fileapi::kFileSystemTypeExternal)
749 return false;
750
751 fileapi::FileSystemPathManager* path_manager =
752 profile_->GetFileSystemContext()->path_manager();
753 if (!path_manager->IsAccessAllowed(file_origin_url,
754 type,
755 virtual_path)) {
756 return false;
757 }
758
759 // Make sure this url really being used by the right caller extension.
760 if (source_url_.GetOrigin() != file_origin_url) {
761 DidFail(base::PLATFORM_FILE_ERROR_SECURITY);
762 return false;
763 }
764
765 FilePath root_path =
766 path_manager->ValidateFileSystemRootAndGetPathOnFileThread(
767 file_origin_url,
768 fileapi::kFileSystemTypeExternal,
769 virtual_path,
770 false); // create
771 FilePath final_file_path = root_path.Append(virtual_path);
772
773 fileapi::ExternalFileSystemMountPointProvider* external_provider =
774 path_manager->external_provider();
775 if (!external_provider)
776 return false;
777
778 // Check if this file system entry exists first.
779 base::PlatformFileInfo file_info;
780
781 if (!file_util::PathExists(final_file_path) ||
782 file_util::IsLink(final_file_path) ||
783 !file_util::GetFileInfo(final_file_path, &file_info))
784 return false;
785
786 // TODO(zelidrag): Let's just prevent all symlinks for now. We don't want a
787 // USB drive content to point to something in the rest of the file system.
788 // Ideally, we should permit symlinks within the boundary of the same
789 // virtual mount point.
790 if (file_info.is_symbolic_link)
791 return false;
792
793 // TODO(zelidrag): Add explicit R/W + R/O permissions for non-component
794 // extensions.
795
796 // Grant R/O access permission to non-component extension and R/W to
797 // component extensions.
798 ChildProcessSecurityPolicy::GetInstance()->GrantPermissionsForFile(
799 target_process_id_,
800 final_file_path,
801 extension_->location() != Extension::COMPONENT ?
802 kReadOnlyFilePermissions : kReadWriteFilePermissions);
803
804 // Grant access to this particular file to target extension. This will
805 // ensure that the target extension can access only this FS entry and
806 // prevent from traversing FS hierarchy upward.
807 external_provider->GrantFileAccessToExtension(target_extension_id_,
808 virtual_path);
809
810 // Output values.
811 GURL target_origin_url(Extension::GetBaseURLFromExtensionId(
812 target_extension_id_));
813 GURL base_url = fileapi::GetFileSystemRootURI(target_origin_url,
814 fileapi::kFileSystemTypeExternal);
815 *target_file_url = GURL(base_url.spec() + virtual_path.value());
816 FilePath root(FILE_PATH_LITERAL("/"));
817 *file_path = root.Append(virtual_path);
818 *is_directory = file_info.is_directory;
819 return true;
820 }
821
822 ExecuteTasksFileBrowserFunction* function_;
823 int target_process_id_;
824 Profile* profile_;
825 // Extension source URL.
826 GURL source_url_;
827 scoped_refptr<const Extension> extension_;
828 std::string task_id_;
829 std::string target_extension_id_;
830 std::vector<GURL> origin_file_urls_;
831 DISALLOW_COPY_AND_ASSIGN(ExecuteTasksFileSystemCallbackDispatcher);
832 };
833
834 bool ExecuteTasksFileBrowserFunction::RunImpl() {
835 // First param is task id that was to the extension with getFileTasks call.
836 std::string task_id;
837 if (!args_->GetString(0, &task_id) || !task_id.size())
838 return false;
839
840 // The second param is the list of files that need to be executed with this
841 // task.
842 ListValue* files_list = NULL;
843 if (!args_->GetList(1, &files_list))
844 return false;
845
846 if (!files_list->GetSize())
847 return true;
848
849 return InitiateFileTaskExecution(task_id, files_list);
850 }
851
852 bool ExecuteTasksFileBrowserFunction::InitiateFileTaskExecution(
853 const std::string& task_id, ListValue* files_list) {
854 std::vector<GURL> file_urls;
855 for (size_t i = 0; i < files_list->GetSize(); i++) {
856 std::string origin_file_url;
857 if (!files_list->GetString(i, &origin_file_url)) {
858 error_ = kInvalidFileUrl;
859 return false;
860 }
861 file_urls.push_back(GURL(origin_file_url));
862 }
863 // Get local file system instance on file thread.
864 BrowserThread::PostTask(
865 BrowserThread::FILE, FROM_HERE,
866 base::Bind(
867 &ExecuteTasksFileBrowserFunction::RequestFileEntryOnFileThread,
868 this,
869 source_url_,
870 task_id,
871 file_urls));
872 result_.reset(new base::FundamentalValue(true));
873 return true;
874 }
875
876 void ExecuteTasksFileBrowserFunction::RequestFileEntryOnFileThread(
877 const GURL& source_url, const std::string& task_id,
878 const std::vector<GURL>& file_urls) {
879 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
880 fileapi::FileSystemOperation* operation =
881 new fileapi::FileSystemOperation(
882 new ExecuteTasksFileSystemCallbackDispatcher(
883 this,
884 profile(),
885 render_view_host()->process()->GetID(),
886 source_url,
887 GetExtension(),
888 task_id,
889 file_urls),
890 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
891 profile()->GetFileSystemContext());
892 GURL origin_url = source_url.GetOrigin();
893 operation->OpenFileSystem(origin_url, fileapi::kFileSystemTypeExternal,
894 false); // create
895 }
896
897 void ExecuteTasksFileBrowserFunction::ExecuteFailedOnUIThread() {
898 SendResponse(false);
899 }
900
901
902 void ExecuteTasksFileBrowserFunction::ExecuteFileActionsOnUIThread(
903 const std::string& task_id,
904 const std::string& file_system_name,
905 const GURL& file_system_root,
906 const FileDefinitionList& file_list) {
907 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
908 ExtensionService* service = profile_->GetExtensionService();
909 if (!service)
910 return;
911 // Get task details.
912 std::string handler_extension_id;
913 std::string action_id;
914 if (!CrackTaskIdentifier(task_id, &handler_extension_id,
915 &action_id)) {
916 LOG(WARNING) << "Invalid task " << task_id;
917 SendResponse(false);
918 return;
919 }
920
921 const Extension* extension = service->GetExtensionById(handler_extension_id,
922 false);
923 if (!extension) {
924 SendResponse(false);
925 return;
926 }
927
928 ExtensionEventRouter* event_router = profile_->GetExtensionEventRouter();
929 if (!event_router) {
930 SendResponse(false);
931 return;
932 }
933
934 scoped_ptr<ListValue> event_args(new ListValue());
935 event_args->Append(Value::CreateStringValue(action_id));
936 DictionaryValue* details = new DictionaryValue();
937 event_args->Append(details);
938 // Get file definitions. These will be replaced with Entry instances by
939 // chromeHidden.Event.dispatchJSON() method from even_binding.js.
940 ListValue* files_urls = new ListValue();
941 details->Set("entries", files_urls);
942 for (FileDefinitionList::const_iterator iter = file_list.begin();
943 iter != file_list.end();
944 ++iter) {
945 DictionaryValue* file_def = new DictionaryValue();
946 files_urls->Append(file_def);
947 file_def->SetString("fileSystemName", file_system_name);
948 file_def->SetString("fileSystemRoot", file_system_root.spec());
949 file_def->SetString("fileFullPath", iter->virtual_path.value());
950 file_def->SetBoolean("fileIsDirectory", iter->is_directory);
951 }
952 // Get tab id.
953 Browser* browser = GetCurrentBrowser();
954 if (browser) {
955 TabContents* contents = browser->GetSelectedTabContents();
956 if (contents)
957 details->SetInteger("tab_id", ExtensionTabUtil::GetTabId(contents));
958 }
959
960 UpdateFileHandlerUsageStats(profile_, task_id);
961
962 std::string json_args;
963 base::JSONWriter::Write(event_args.get(), false, &json_args);
964 event_router->DispatchEventToExtension(
965 handler_extension_id, std::string("fileBrowserHandler.onExecute"),
966 json_args, profile_,
967 GURL());
968 SendResponse(true);
969 }
970
971 FileBrowserFunction::FileBrowserFunction() {
972 }
973
974 FileBrowserFunction::~FileBrowserFunction() {
975 }
976
977 int32 FileBrowserFunction::GetTabId() const {
978 if (!dispatcher()) {
979 LOG(WARNING) << "No dispatcher";
980 return 0;
981 }
982 if (!dispatcher()->delegate()) {
983 LOG(WARNING) << "No delegate";
984 return 0;
985 }
986 TabContents* tab_contents =
987 dispatcher()->delegate()->GetAssociatedTabContents();
988 if (!tab_contents) {
989 LOG(WARNING) << "No associated tab contents";
990 return 0;
991 }
992 return ExtensionTabUtil::GetTabId(tab_contents);
993 }
994
995 void FileBrowserFunction::GetLocalPathsOnFileThreadAndRunCallbackOnUIThread(
996 const UrlList& file_urls,
997 GetLocalPathsCallback callback) {
998 BrowserThread::PostTask(
999 BrowserThread::FILE, FROM_HERE,
1000 base::Bind(
1001 &FileBrowserFunction::GetLocalPathsOnFileThread,
1002 this,
1003 file_urls, callback));
1004 }
1005
1006 // GetFileSystemRootPathOnFileThread can only be called from the file thread,
1007 // so here we are. This function takes a vector of virtual paths, converts
1008 // them to local paths and calls |callback| with the result vector, on the UI
1009 // thread.
1010 void FileBrowserFunction::GetLocalPathsOnFileThread(
1011 const UrlList& file_urls,
1012 GetLocalPathsCallback callback) {
1013 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1014 FilePathList selected_files;
1015
1016 // FilePath(virtual_path) doesn't work on win, so limit this to ChromeOS.
1017 #if defined(OS_CHROMEOS)
1018 GURL origin_url = source_url().GetOrigin();
1019 fileapi::FileSystemPathManager* path_manager =
1020 profile()->GetFileSystemContext()->path_manager();
1021
1022 size_t len = file_urls.size();
1023 selected_files.reserve(len);
1024 for (size_t i = 0; i < len; ++i) {
1025 const GURL& file_url = file_urls[i];
1026 GURL file_origin_url;
1027 FilePath virtual_path;
1028 fileapi::FileSystemType type;
1029 if (!CrackFileSystemURL(file_url, &file_origin_url, &type,
1030 &virtual_path)) {
1031 continue;
1032 }
1033 if (type != fileapi::kFileSystemTypeExternal) {
1034 NOTREACHED();
1035 continue;
1036 }
1037 FilePath root = path_manager->ValidateFileSystemRootAndGetPathOnFileThread(
1038 origin_url,
1039 fileapi::kFileSystemTypeExternal,
1040 FilePath(virtual_path),
1041 false);
1042 if (!root.empty()) {
1043 selected_files.push_back(root.Append(virtual_path));
1044 } else {
1045 LOG(WARNING) << "GetLocalPathsOnFileThread failed "
1046 << file_url.spec();
1047 }
1048 }
1049 #endif
1050
1051 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
1052 base::Bind(callback, selected_files));
1053 }
1054
1055 bool SelectFileFunction::RunImpl() {
1056 if (args_->GetSize() != 2) {
1057 return false;
1058 }
1059 std::string file_url;
1060 args_->GetString(0, &file_url);
1061 UrlList file_paths;
1062 file_paths.push_back(GURL(file_url));
1063
1064 GetLocalPathsOnFileThreadAndRunCallbackOnUIThread(
1065 file_paths,
1066 base::Bind(&SelectFileFunction::GetLocalPathsResponseOnUIThread, this));
1067 return true;
1068 }
1069
1070 void SelectFileFunction::GetLocalPathsResponseOnUIThread(
1071 const FilePathList& files) {
1072 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1073 if (files.size() != 1) {
1074 SendResponse(false);
1075 return;
1076 }
1077 int index;
1078 args_->GetInteger(1, &index);
1079 int32 tab_id = GetTabId();
1080 SelectFileDialogExtension::OnFileSelected(tab_id, files[0], index);
1081 SendResponse(true);
1082 }
1083
1084
1085 ViewFilesFunction::ViewFilesFunction() {
1086 }
1087
1088 ViewFilesFunction::~ViewFilesFunction() {
1089 }
1090
1091 bool ViewFilesFunction::RunImpl() {
1092 if (args_->GetSize() < 1) {
1093 return false;
1094 }
1095
1096 ListValue* path_list = NULL;
1097 args_->GetList(0, &path_list);
1098 DCHECK(path_list);
1099
1100 std::string internal_task_id;
1101 args_->GetString(1, &internal_task_id);
1102
1103 std::string virtual_path;
1104 size_t len = path_list->GetSize();
1105 UrlList file_urls;
1106 file_urls.reserve(len);
1107 for (size_t i = 0; i < len; ++i) {
1108 path_list->GetString(i, &virtual_path);
1109 file_urls.push_back(GURL(virtual_path));
1110 }
1111
1112 GetLocalPathsOnFileThreadAndRunCallbackOnUIThread(
1113 file_urls,
1114 base::Bind(&ViewFilesFunction::GetLocalPathsResponseOnUIThread,
1115 this,
1116 internal_task_id));
1117 return true;
1118 }
1119
1120 void ViewFilesFunction::GetLocalPathsResponseOnUIThread(
1121 const std::string& internal_task_id,
1122 const FilePathList& files) {
1123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1124 for (FilePathList::const_iterator iter = files.begin();
1125 iter != files.end();
1126 ++iter) {
1127 file_manager_util::ViewItem(*iter,
1128 internal_task_id == kEnqueueTaskId ||
1129 // Start the first one, enqueue others.
1130 iter != files.begin());
1131 }
1132 SendResponse(true);
1133 }
1134
1135 SelectFilesFunction::SelectFilesFunction() {
1136 }
1137
1138 SelectFilesFunction::~SelectFilesFunction() {
1139 }
1140
1141 bool SelectFilesFunction::RunImpl() {
1142 if (args_->GetSize() != 1) {
1143 return false;
1144 }
1145
1146 ListValue* path_list = NULL;
1147 args_->GetList(0, &path_list);
1148 DCHECK(path_list);
1149
1150 std::string virtual_path;
1151 size_t len = path_list->GetSize();
1152 UrlList file_urls;
1153 file_urls.reserve(len);
1154 for (size_t i = 0; i < len; ++i) {
1155 path_list->GetString(i, &virtual_path);
1156 file_urls.push_back(GURL(virtual_path));
1157 }
1158
1159 GetLocalPathsOnFileThreadAndRunCallbackOnUIThread(
1160 file_urls,
1161 base::Bind(&SelectFilesFunction::GetLocalPathsResponseOnUIThread, this));
1162 return true;
1163 }
1164
1165 void SelectFilesFunction::GetLocalPathsResponseOnUIThread(
1166 const FilePathList& files) {
1167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1168 int32 tab_id = GetTabId();
1169 SelectFileDialogExtension::OnMultiFilesSelected(tab_id, files);
1170 SendResponse(true);
1171 }
1172
1173 bool CancelFileDialogFunction::RunImpl() {
1174 int32 tab_id = GetTabId();
1175 SelectFileDialogExtension::OnFileSelectionCanceled(tab_id);
1176 SendResponse(true);
1177 return true;
1178 }
1179
1180 AddMountFunction::AddMountFunction() {
1181 }
1182
1183 AddMountFunction::~AddMountFunction() {
1184 }
1185
1186 bool AddMountFunction::RunImpl() {
1187 // The third argument is simply ignored.
1188 if (args_->GetSize() != 2 && args_->GetSize() != 3) {
1189 error_ = "Invalid argument count";
1190 return false;
1191 }
1192
1193 std::string file_url;
1194 if (!args_->GetString(0, &file_url)) {
1195 return false;
1196 }
1197
1198 std::string mount_type_str;
1199 if (!args_->GetString(1, &mount_type_str)) {
1200 return false;
1201 }
1202
1203 UrlList file_paths;
1204 file_paths.push_back(GURL(file_url));
1205
1206 #if defined(OS_CHROMEOS)
1207 GetLocalPathsOnFileThreadAndRunCallbackOnUIThread(
1208 file_paths,
1209 base::Bind(&AddMountFunction::GetLocalPathsResponseOnUIThread,
1210 this,
1211 mount_type_str));
1212 #endif // OS_CHROMEOS
1213
1214 return true;
1215 }
1216
1217 void AddMountFunction::GetLocalPathsResponseOnUIThread(
1218 const std::string& mount_type_str,
1219 const FilePathList& files) {
1220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1221
1222 if (!files.size()) {
1223 SendResponse(false);
1224 return;
1225 }
1226
1227 #ifdef OS_CHROMEOS
1228 FilePath::StringType source_file = files[0].value();
1229
1230 chromeos::disks::DiskMountManager* disk_mount_manager =
1231 chromeos::disks::DiskMountManager::GetInstance();
1232
1233 chromeos::MountType mount_type =
1234 disk_mount_manager->MountTypeFromString(mount_type_str);
1235 if (mount_type == chromeos::MOUNT_TYPE_INVALID) {
1236 error_ = "Invalid mount type";
1237 SendResponse(false);
1238 return;
1239 }
1240
1241 disk_mount_manager->MountPath(source_file.data(), mount_type);
1242 #endif
1243
1244 SendResponse(true);
1245 }
1246
1247 RemoveMountFunction::RemoveMountFunction() {
1248 }
1249
1250 RemoveMountFunction::~RemoveMountFunction() {
1251 }
1252
1253 bool RemoveMountFunction::RunImpl() {
1254 if (args_->GetSize() != 1) {
1255 return false;
1256 }
1257
1258 std::string mount_path;
1259 if (!args_->GetString(0, &mount_path)) {
1260 return false;
1261 }
1262
1263 UrlList file_paths;
1264 file_paths.push_back(GURL(mount_path));
1265 GetLocalPathsOnFileThreadAndRunCallbackOnUIThread(
1266 file_paths,
1267 base::Bind(&RemoveMountFunction::GetLocalPathsResponseOnUIThread, this));
1268 return true;
1269 }
1270
1271 void RemoveMountFunction::GetLocalPathsResponseOnUIThread(
1272 const FilePathList& files) {
1273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1274
1275 if (files.size() != 1) {
1276 SendResponse(false);
1277 return;
1278 }
1279 #ifdef OS_CHROMEOS
1280 chromeos::disks::DiskMountManager::GetInstance()->UnmountPath(
1281 files[0].value());
1282 #endif
1283
1284 SendResponse(true);
1285 }
1286
1287 GetMountPointsFunction::GetMountPointsFunction() {
1288 }
1289
1290 GetMountPointsFunction::~GetMountPointsFunction() {
1291 }
1292
1293 bool GetMountPointsFunction::RunImpl() {
1294 if (args_->GetSize())
1295 return false;
1296
1297 base::ListValue *mounts = new base::ListValue();
1298 result_.reset(mounts);
1299
1300 #ifdef OS_CHROMEOS
1301 chromeos::disks::DiskMountManager* disk_mount_manager =
1302 chromeos::disks::DiskMountManager::GetInstance();
1303 chromeos::disks::DiskMountManager::MountPointMap mount_points =
1304 disk_mount_manager->mount_points();
1305
1306 for (chromeos::disks::DiskMountManager::MountPointMap::const_iterator it =
1307 mount_points.begin();
1308 it != mount_points.end();
1309 ++it) {
1310 mounts->Append(MountPointToValue(profile_, it->second));
1311 }
1312 #endif
1313
1314 SendResponse(true);
1315 return true;
1316 }
1317
1318 GetSizeStatsFunction::GetSizeStatsFunction() {
1319 }
1320
1321 GetSizeStatsFunction::~GetSizeStatsFunction() {
1322 }
1323
1324 bool GetSizeStatsFunction::RunImpl() {
1325 if (args_->GetSize() != 1) {
1326 return false;
1327 }
1328
1329 std::string mount_url;
1330 if (!args_->GetString(0, &mount_url))
1331 return false;
1332
1333 UrlList mount_paths;
1334 mount_paths.push_back(GURL(mount_url));
1335
1336 GetLocalPathsOnFileThreadAndRunCallbackOnUIThread(
1337 mount_paths,
1338 base::Bind(&GetSizeStatsFunction::GetLocalPathsResponseOnUIThread, this));
1339 return true;
1340 }
1341
1342 void GetSizeStatsFunction::GetLocalPathsResponseOnUIThread(
1343 const FilePathList& files) {
1344 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1345
1346 if (files.size() != 1) {
1347 SendResponse(false);
1348 return;
1349 }
1350
1351 BrowserThread::PostTask(
1352 BrowserThread::FILE, FROM_HERE,
1353 base::Bind(
1354 &GetSizeStatsFunction::CallGetSizeStatsOnFileThread,
1355 this,
1356 files[0].value()));
1357 }
1358
1359 void GetSizeStatsFunction::CallGetSizeStatsOnFileThread(
1360 const std::string& mount_path) {
1361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1362
1363 size_t total_size_kb = 0;
1364 size_t remaining_size_kb = 0;
1365 #ifdef OS_CHROMEOS
1366 chromeos::disks::DiskMountManager::GetInstance()->
1367 GetSizeStatsOnFileThread(mount_path, &total_size_kb, &remaining_size_kb);
1368 #endif
1369
1370 BrowserThread::PostTask(
1371 BrowserThread::UI, FROM_HERE,
1372 base::Bind(
1373 &GetSizeStatsFunction::GetSizeStatsCallbackOnUIThread,
1374 this,
1375 mount_path, total_size_kb, remaining_size_kb));
1376 }
1377
1378 void GetSizeStatsFunction::GetSizeStatsCallbackOnUIThread(
1379 const std::string& mount_path,
1380 size_t total_size_kb,
1381 size_t remaining_size_kb) {
1382 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1383
1384 base::DictionaryValue* sizes = new base::DictionaryValue();
1385 result_.reset(sizes);
1386
1387 sizes->SetInteger("totalSizeKB", total_size_kb);
1388 sizes->SetInteger("remainingSizeKB", remaining_size_kb);
1389
1390 SendResponse(true);
1391 }
1392
1393 FormatDeviceFunction::FormatDeviceFunction() {
1394 }
1395
1396 FormatDeviceFunction::~FormatDeviceFunction() {
1397 }
1398
1399 bool FormatDeviceFunction::RunImpl() {
1400 if (args_->GetSize() != 1) {
1401 return false;
1402 }
1403
1404 std::string volume_file_url;
1405 if (!args_->GetString(0, &volume_file_url)) {
1406 NOTREACHED();
1407 return false;
1408 }
1409
1410 UrlList file_paths;
1411 file_paths.push_back(GURL(volume_file_url));
1412
1413 GetLocalPathsOnFileThreadAndRunCallbackOnUIThread(
1414 file_paths,
1415 base::Bind(&FormatDeviceFunction::GetLocalPathsResponseOnUIThread, this));
1416 return true;
1417 }
1418
1419 void FormatDeviceFunction::GetLocalPathsResponseOnUIThread(
1420 const FilePathList& files) {
1421 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1422
1423 if (files.size() != 1) {
1424 SendResponse(false);
1425 return;
1426 }
1427
1428 #ifdef OS_CHROMEOS
1429 chromeos::disks::DiskMountManager::GetInstance()->FormatMountedDevice(
1430 files[0].value());
1431 #endif
1432
1433 SendResponse(true);
1434 }
1435
1436 GetVolumeMetadataFunction::GetVolumeMetadataFunction() {
1437 }
1438
1439 GetVolumeMetadataFunction::~GetVolumeMetadataFunction() {
1440 }
1441
1442 bool GetVolumeMetadataFunction::RunImpl() {
1443 if (args_->GetSize() != 1) {
1444 error_ = "Invalid argument count";
1445 return false;
1446 }
1447
1448 std::string volume_device_path;
1449 if (!args_->GetString(0, &volume_device_path)) {
1450 NOTREACHED();
1451 }
1452
1453 #ifdef OS_CHROMEOS
1454 chromeos::disks::DiskMountManager* disk_mount_manager =
1455 chromeos::disks::DiskMountManager::GetInstance();
1456 chromeos::disks::DiskMountManager::DiskMap::const_iterator volume_it =
1457 disk_mount_manager->disks().find(volume_device_path);
1458
1459 if (volume_it != disk_mount_manager->disks().end() &&
1460 !volume_it->second->is_hidden()) {
1461 chromeos::disks::DiskMountManager::Disk* volume = volume_it->second;
1462 DictionaryValue* volume_info = new DictionaryValue();
1463 result_.reset(volume_info);
1464 // Localising mount path.
1465 std::string mount_path;
1466 if (!volume->mount_path().empty()) {
1467 FilePath relative_mount_path;
1468 file_manager_util::ConvertFileToRelativeFileSystemPath(profile_,
1469 FilePath(volume->mount_path()), &relative_mount_path);
1470 mount_path = relative_mount_path.value();
1471 }
1472 volume_info->SetString("devicePath", volume->device_path());
1473 volume_info->SetString("mountPath", mount_path);
1474 volume_info->SetString("systemPath", volume->system_path());
1475 volume_info->SetString("filePath", volume->file_path());
1476 volume_info->SetString("deviceLabel", volume->device_label());
1477 volume_info->SetString("driveLabel", volume->drive_label());
1478 volume_info->SetString("deviceType",
1479 DeviceTypeToString(volume->device_type()));
1480 volume_info->SetInteger("totalSize", volume->total_size_in_bytes());
1481 volume_info->SetBoolean("isParent", volume->is_parent());
1482 volume_info->SetBoolean("isReadOnly", volume->is_read_only());
1483 volume_info->SetBoolean("hasMedia", volume->has_media());
1484 volume_info->SetBoolean("isOnBootDevice", volume->on_boot_device());
1485
1486 return true;
1487 }
1488 #endif
1489 error_ = kVolumeDevicePathNotFound;
1490 return false;
1491 }
1492
1493 #ifdef OS_CHROMEOS
1494 std::string GetVolumeMetadataFunction::DeviceTypeToString(
1495 chromeos::DeviceType type) {
1496 switch (type) {
1497 case chromeos::FLASH:
1498 return kVolumeTypeFlash;
1499 case chromeos::OPTICAL:
1500 return kVolumeTypeOptical;
1501 case chromeos::HDD:
1502 return kVolumeTypeHardDrive;
1503 default:
1504 break;
1505 }
1506 return kVolumeTypeUnknown;
1507 }
1508 #endif
1509
1510 bool FileDialogStringsFunction::RunImpl() {
1511 result_.reset(new DictionaryValue());
1512 DictionaryValue* dict = reinterpret_cast<DictionaryValue*>(result_.get());
1513
1514 #define SET_STRING(ns, id) \
1515 dict->SetString(#id, l10n_util::GetStringUTF16(ns##_##id))
1516
1517 SET_STRING(IDS, WEB_FONT_FAMILY);
1518 SET_STRING(IDS, WEB_FONT_SIZE);
1519
1520 SET_STRING(IDS_FILE_BROWSER, ROOT_DIRECTORY_LABEL);
1521 SET_STRING(IDS_FILE_BROWSER, DOWNLOADS_DIRECTORY_LABEL);
1522 SET_STRING(IDS_FILE_BROWSER, ARCHIVE_DIRECTORY_LABEL);
1523 SET_STRING(IDS_FILE_BROWSER, REMOVABLE_DIRECTORY_LABEL);
1524 SET_STRING(IDS_FILE_BROWSER, NAME_COLUMN_LABEL);
1525 SET_STRING(IDS_FILE_BROWSER, SIZE_COLUMN_LABEL);
1526 SET_STRING(IDS_FILE_BROWSER, TYPE_COLUMN_LABEL);
1527 SET_STRING(IDS_FILE_BROWSER, DATE_COLUMN_LABEL);
1528 SET_STRING(IDS_FILE_BROWSER, PREVIEW_COLUMN_LABEL);
1529
1530 SET_STRING(IDS_FILE_BROWSER, DOWNLOADS_DIRECTORY_WARNING);
1531
1532 SET_STRING(IDS_FILE_BROWSER, ERROR_CREATING_FOLDER);
1533 SET_STRING(IDS_FILE_BROWSER, ERROR_INVALID_CHARACTER);
1534 SET_STRING(IDS_FILE_BROWSER, ERROR_RESERVED_NAME);
1535 SET_STRING(IDS_FILE_BROWSER, ERROR_HIDDEN_NAME);
1536 SET_STRING(IDS_FILE_BROWSER, ERROR_WHITESPACE_NAME);
1537 SET_STRING(IDS_FILE_BROWSER, NEW_FOLDER_PROMPT);
1538 SET_STRING(IDS_FILE_BROWSER, ERROR_NEW_FOLDER_EMPTY_NAME);
1539 SET_STRING(IDS_FILE_BROWSER, NEW_FOLDER_BUTTON_LABEL);
1540 SET_STRING(IDS_FILE_BROWSER, FILENAME_LABEL);
1541
1542 SET_STRING(IDS_FILE_BROWSER, DIMENSIONS_LABEL);
1543 SET_STRING(IDS_FILE_BROWSER, DIMENSIONS_FORMAT);
1544
1545 SET_STRING(IDS_FILE_BROWSER, EJECT_BUTTON);
1546 SET_STRING(IDS_FILE_BROWSER, IMAGE_DIMENSIONS);
1547 SET_STRING(IDS_FILE_BROWSER, VOLUME_LABEL);
1548 SET_STRING(IDS_FILE_BROWSER, READ_ONLY);
1549
1550 SET_STRING(IDS_FILE_BROWSER, ARCHIVE_MOUNT_FAILED);
1551 SET_STRING(IDS_FILE_BROWSER, MOUNT_ARCHIVE);
1552 SET_STRING(IDS_FILE_BROWSER, UNMOUNT_ARCHIVE);
1553 SET_STRING(IDS_FILE_BROWSER, FORMAT_DEVICE);
1554
1555 SET_STRING(IDS_FILE_BROWSER, GALLERY);
1556 SET_STRING(IDS_FILE_BROWSER, GALLERY_EDIT);
1557 SET_STRING(IDS_FILE_BROWSER, GALLERY_SHARE);
1558 SET_STRING(IDS_FILE_BROWSER, GALLERY_ENTER_WHEN_DONE);
1559 SET_STRING(IDS_FILE_BROWSER, GALLERY_AUTOFIX);
1560 SET_STRING(IDS_FILE_BROWSER, GALLERY_FIXED);
1561 SET_STRING(IDS_FILE_BROWSER, GALLERY_CROP);
1562 SET_STRING(IDS_FILE_BROWSER, GALLERY_EXPOSURE);
1563 SET_STRING(IDS_FILE_BROWSER, GALLERY_BRIGHTNESS);
1564 SET_STRING(IDS_FILE_BROWSER, GALLERY_CONTRAST);
1565 SET_STRING(IDS_FILE_BROWSER, GALLERY_ROTATE_LEFT);
1566 SET_STRING(IDS_FILE_BROWSER, GALLERY_ROTATE_RIGHT);
1567 SET_STRING(IDS_FILE_BROWSER, GALLERY_UNDO);
1568 SET_STRING(IDS_FILE_BROWSER, GALLERY_REDO);
1569
1570 SET_STRING(IDS_FILE_BROWSER, CONFIRM_OVERWRITE_FILE);
1571 SET_STRING(IDS_FILE_BROWSER, FILE_ALREADY_EXISTS);
1572 SET_STRING(IDS_FILE_BROWSER, DIRECTORY_ALREADY_EXISTS);
1573 SET_STRING(IDS_FILE_BROWSER, ERROR_RENAMING);
1574 SET_STRING(IDS_FILE_BROWSER, RENAME_PROMPT);
1575 SET_STRING(IDS_FILE_BROWSER, RENAME_BUTTON_LABEL);
1576
1577 SET_STRING(IDS_FILE_BROWSER, ERROR_DELETING);
1578 SET_STRING(IDS_FILE_BROWSER, DELETE_BUTTON_LABEL);
1579
1580 SET_STRING(IDS_FILE_BROWSER, ERROR_MOVING);
1581 SET_STRING(IDS_FILE_BROWSER, MOVE_BUTTON_LABEL);
1582
1583 SET_STRING(IDS_FILE_BROWSER, ERROR_PASTING);
1584 SET_STRING(IDS_FILE_BROWSER, PASTE_BUTTON_LABEL);
1585
1586 SET_STRING(IDS_FILE_BROWSER, COPY_BUTTON_LABEL);
1587 SET_STRING(IDS_FILE_BROWSER, CUT_BUTTON_LABEL);
1588
1589 SET_STRING(IDS_FILE_BROWSER, SELECTION_COPIED);
1590 SET_STRING(IDS_FILE_BROWSER, SELECTION_CUT);
1591 SET_STRING(IDS_FILE_BROWSER, PASTE_STARTED);
1592 SET_STRING(IDS_FILE_BROWSER, PASTE_SOME_PROGRESS);
1593 SET_STRING(IDS_FILE_BROWSER, PASTE_COMPLETE);
1594 SET_STRING(IDS_FILE_BROWSER, PASTE_CANCELLED);
1595 SET_STRING(IDS_FILE_BROWSER, PASTE_TARGET_EXISTS_ERROR);
1596 SET_STRING(IDS_FILE_BROWSER, PASTE_FILESYSTEM_ERROR);
1597 SET_STRING(IDS_FILE_BROWSER, PASTE_UNEXPECTED_ERROR);
1598
1599 SET_STRING(IDS_FILE_BROWSER, DEVICE_TYPE_FLASH);
1600 SET_STRING(IDS_FILE_BROWSER, DEVICE_TYPE_HDD);
1601 SET_STRING(IDS_FILE_BROWSER, DEVICE_TYPE_OPTICAL);
1602 SET_STRING(IDS_FILE_BROWSER, DEVICE_TYPE_UNDEFINED);
1603
1604 SET_STRING(IDS_FILE_BROWSER, CANCEL_LABEL);
1605 SET_STRING(IDS_FILE_BROWSER, OPEN_LABEL);
1606 SET_STRING(IDS_FILE_BROWSER, SAVE_LABEL);
1607 SET_STRING(IDS_FILE_BROWSER, OK_LABEL);
1608
1609 SET_STRING(IDS_FILE_BROWSER, DEFAULT_NEW_FOLDER_NAME);
1610 SET_STRING(IDS_FILE_BROWSER, MORE_FILES);
1611
1612 SET_STRING(IDS_FILE_BROWSER, CONFIRM_DELETE_ONE);
1613 SET_STRING(IDS_FILE_BROWSER, CONFIRM_DELETE_SOME);
1614
1615 SET_STRING(IDS_FILE_BROWSER, UNKNOWN_FILESYSTEM_WARNING);
1616 SET_STRING(IDS_FILE_BROWSER, UNSUPPORTED_FILESYSTEM_WARNING);
1617 SET_STRING(IDS_FILE_BROWSER, FORMATTING_WARNING);
1618
1619 SET_STRING(IDS_FILE_BROWSER, SELECT_FOLDER_TITLE);
1620 SET_STRING(IDS_FILE_BROWSER, SELECT_OPEN_FILE_TITLE);
1621 SET_STRING(IDS_FILE_BROWSER, SELECT_OPEN_MULTI_FILE_TITLE);
1622 SET_STRING(IDS_FILE_BROWSER, SELECT_SAVEAS_FILE_TITLE);
1623
1624 SET_STRING(IDS_FILE_BROWSER, COMPUTING_SELECTION);
1625 SET_STRING(IDS_FILE_BROWSER, NOTHING_SELECTED);
1626 SET_STRING(IDS_FILE_BROWSER, ONE_FILE_SELECTED);
1627 SET_STRING(IDS_FILE_BROWSER, ONE_DIRECTORY_SELECTED);
1628 SET_STRING(IDS_FILE_BROWSER, MANY_FILES_SELECTED);
1629 SET_STRING(IDS_FILE_BROWSER, MANY_DIRECTORIES_SELECTED);
1630 SET_STRING(IDS_FILE_BROWSER, MANY_ENTRIES_SELECTED);
1631
1632 SET_STRING(IDS_FILE_BROWSER, PLAYBACK_ERROR);
1633
1634 // MP3 metadata extractor plugin
1635 SET_STRING(IDS_FILE_BROWSER, ID3_ALBUM); // TALB
1636 SET_STRING(IDS_FILE_BROWSER, ID3_BPM); // TBPM
1637 SET_STRING(IDS_FILE_BROWSER, ID3_COMPOSER); // TCOM
1638 SET_STRING(IDS_FILE_BROWSER, ID3_COPYRIGHT_MESSAGE); // TCOP
1639 SET_STRING(IDS_FILE_BROWSER, ID3_DATE); // TDAT
1640 SET_STRING(IDS_FILE_BROWSER, ID3_PLAYLIST_DELAY); // TDLY
1641 SET_STRING(IDS_FILE_BROWSER, ID3_ENCODED_BY); // TENC
1642 SET_STRING(IDS_FILE_BROWSER, ID3_LYRICIST); // TEXT
1643 SET_STRING(IDS_FILE_BROWSER, ID3_FILE_TYPE); // TFLT
1644 SET_STRING(IDS_FILE_BROWSER, ID3_TIME); // TIME
1645 SET_STRING(IDS_FILE_BROWSER, ID3_TITLE); // TIT2
1646 SET_STRING(IDS_FILE_BROWSER, ID3_LENGTH); // TLEN
1647 SET_STRING(IDS_FILE_BROWSER, ID3_FILE_OWNER); // TOWN
1648 SET_STRING(IDS_FILE_BROWSER, ID3_LEAD_PERFORMER); // TPE1
1649 SET_STRING(IDS_FILE_BROWSER, ID3_BAND); // TPE2
1650 SET_STRING(IDS_FILE_BROWSER, ID3_TRACK_NUMBER); // TRCK
1651 SET_STRING(IDS_FILE_BROWSER, ID3_YEAR); // TYER
1652 SET_STRING(IDS_FILE_BROWSER, ID3_COPYRIGHT); // WCOP
1653 SET_STRING(IDS_FILE_BROWSER, ID3_OFFICIAL_AUDIO_FILE_WEBPAGE); // WOAF
1654 SET_STRING(IDS_FILE_BROWSER, ID3_OFFICIAL_ARTIST); // WOAR
1655 SET_STRING(IDS_FILE_BROWSER, ID3_OFFICIAL_AUDIO_SOURCE_WEBPAGE); // WOAS
1656 SET_STRING(IDS_FILE_BROWSER, ID3_PUBLISHERS_OFFICIAL_WEBPAGE); // WPUB
1657 SET_STRING(IDS_FILE_BROWSER, ID3_USER_DEFINED_URL_LINK_FRAME); // WXXX
1658
1659 // File types
1660 SET_STRING(IDS_FILE_BROWSER, FOLDER);
1661 SET_STRING(IDS_FILE_BROWSER, DEVICE);
1662 SET_STRING(IDS_FILE_BROWSER, IMAGE_FILE_TYPE);
1663 SET_STRING(IDS_FILE_BROWSER, VIDEO_FILE_TYPE);
1664 SET_STRING(IDS_FILE_BROWSER, AUDIO_FILE_TYPE);
1665 SET_STRING(IDS_FILE_BROWSER, HTML_DOCUMENT_FILE_TYPE);
1666 SET_STRING(IDS_FILE_BROWSER, ZIP_ARCHIVE_FILE_TYPE);
1667 SET_STRING(IDS_FILE_BROWSER, PLAIN_TEXT_FILE_TYPE);
1668 SET_STRING(IDS_FILE_BROWSER, PDF_DOCUMENT_FILE_TYPE);
1669
1670 SET_STRING(IDS_FILEBROWSER, ENQUEUE);
1671 #undef SET_STRING
1672
1673 // TODO(serya): Create a new string in .grd file for this one in M13.
1674 dict->SetString("PREVIEW_IMAGE",
1675 l10n_util::GetStringUTF16(IDS_CERT_MANAGER_VIEW_CERT_BUTTON));
1676 dict->SetString("PLAY_MEDIA",
1677 l10n_util::GetStringUTF16(IDS_CONTENT_CONTEXT_PLAY));
1678 #if defined(OS_CHROMEOS)
1679 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePhotoEditor))
1680 dict->SetString("ENABLE_PHOTO_EDITOR", "true");
1681 #endif
1682
1683 return true;
1684 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698