ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / chromeos / extensions / file_manager / private_api_file_system.cc
blob672bbed123d4c7ed51e4d5d0fb2da0fd43f4cda3
1 // Copyright 2013 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.
5 #include "chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h"
7 #include <sys/statvfs.h>
8 #include <set>
10 #include "base/posix/eintr_wrapper.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/sys_info.h"
14 #include "base/task_runner_util.h"
15 #include "base/threading/sequenced_worker_pool.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/chromeos/drive/drive.pb.h"
18 #include "chrome/browser/chromeos/drive/file_system_interface.h"
19 #include "chrome/browser/chromeos/drive/file_system_util.h"
20 #include "chrome/browser/chromeos/extensions/file_manager/event_router.h"
21 #include "chrome/browser/chromeos/extensions/file_manager/event_router_factory.h"
22 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
23 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
24 #include "chrome/browser/chromeos/file_manager/path_util.h"
25 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
26 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
27 #include "chrome/browser/drive/drive_api_util.h"
28 #include "chrome/browser/drive/event_logger.h"
29 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/browser/profiles/profile_manager.h"
32 #include "chrome/common/extensions/api/file_manager_private.h"
33 #include "chrome/common/extensions/api/file_manager_private_internal.h"
34 #include "chromeos/disks/disk_mount_manager.h"
35 #include "content/public/browser/child_process_security_policy.h"
36 #include "content/public/browser/render_process_host.h"
37 #include "content/public/browser/render_view_host.h"
38 #include "content/public/common/url_constants.h"
39 #include "net/base/escape.h"
40 #include "storage/browser/fileapi/file_stream_reader.h"
41 #include "storage/browser/fileapi/file_system_context.h"
42 #include "storage/browser/fileapi/file_system_file_util.h"
43 #include "storage/browser/fileapi/file_system_operation_context.h"
44 #include "storage/browser/fileapi/file_system_operation_runner.h"
45 #include "storage/common/fileapi/file_system_info.h"
46 #include "storage/common/fileapi/file_system_types.h"
47 #include "storage/common/fileapi/file_system_util.h"
48 #include "third_party/cros_system_api/constants/cryptohome.h"
50 using chromeos::disks::DiskMountManager;
51 using content::BrowserThread;
52 using content::ChildProcessSecurityPolicy;
53 using file_manager::util::EntryDefinition;
54 using file_manager::util::FileDefinition;
55 using storage::FileSystemURL;
57 namespace extensions {
58 namespace {
60 // Retrieves total and remaining available size on |mount_path|.
61 void GetSizeStatsOnBlockingPool(const std::string& mount_path,
62 uint64* total_size,
63 uint64* remaining_size) {
64 struct statvfs stat = {}; // Zero-clear
65 if (HANDLE_EINTR(statvfs(mount_path.c_str(), &stat)) == 0) {
66 *total_size = static_cast<uint64>(stat.f_blocks) * stat.f_frsize;
67 *remaining_size = static_cast<uint64>(stat.f_bavail) * stat.f_frsize;
71 // Retrieves the maximum file name length of the file system of |path|.
72 // Returns 0 if it could not be queried.
73 size_t GetFileNameMaxLengthOnBlockingPool(const std::string& path) {
74 struct statvfs stat = {};
75 if (HANDLE_EINTR(statvfs(path.c_str(), &stat)) != 0) {
76 // The filesystem seems not supporting statvfs(). Assume it to be a commonly
77 // used bound 255, and log the failure.
78 LOG(ERROR) << "Cannot statvfs() the name length limit for: " << path;
79 return 255;
81 return stat.f_namemax;
84 // Returns EventRouter for the |profile_id| if available.
85 file_manager::EventRouter* GetEventRouterByProfileId(void* profile_id) {
86 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
88 // |profile_id| needs to be checked with ProfileManager::IsValidProfile
89 // before using it.
90 Profile* profile = reinterpret_cast<Profile*>(profile_id);
91 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
92 return NULL;
94 return file_manager::EventRouterFactory::GetForProfile(profile);
97 // Notifies the copy progress to extensions via event router.
98 void NotifyCopyProgress(
99 void* profile_id,
100 storage::FileSystemOperationRunner::OperationID operation_id,
101 storage::FileSystemOperation::CopyProgressType type,
102 const FileSystemURL& source_url,
103 const FileSystemURL& destination_url,
104 int64 size) {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
107 file_manager::EventRouter* event_router =
108 GetEventRouterByProfileId(profile_id);
109 if (event_router) {
110 event_router->OnCopyProgress(
111 operation_id, type,
112 source_url.ToGURL(), destination_url.ToGURL(), size);
116 // Callback invoked periodically on progress update of Copy().
117 void OnCopyProgress(
118 void* profile_id,
119 storage::FileSystemOperationRunner::OperationID* operation_id,
120 storage::FileSystemOperation::CopyProgressType type,
121 const FileSystemURL& source_url,
122 const FileSystemURL& destination_url,
123 int64 size) {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
126 BrowserThread::PostTask(
127 BrowserThread::UI, FROM_HERE,
128 base::Bind(&NotifyCopyProgress,
129 profile_id, *operation_id, type,
130 source_url, destination_url, size));
133 // Notifies the copy completion to extensions via event router.
134 void NotifyCopyCompletion(
135 void* profile_id,
136 storage::FileSystemOperationRunner::OperationID operation_id,
137 const FileSystemURL& source_url,
138 const FileSystemURL& destination_url,
139 base::File::Error error) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
142 file_manager::EventRouter* event_router =
143 GetEventRouterByProfileId(profile_id);
144 if (event_router)
145 event_router->OnCopyCompleted(
146 operation_id,
147 source_url.ToGURL(), destination_url.ToGURL(), error);
150 // Callback invoked upon completion of Copy() (regardless of succeeded or
151 // failed).
152 void OnCopyCompleted(
153 void* profile_id,
154 storage::FileSystemOperationRunner::OperationID* operation_id,
155 const FileSystemURL& source_url,
156 const FileSystemURL& destination_url,
157 base::File::Error error) {
158 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
160 BrowserThread::PostTask(
161 BrowserThread::UI, FROM_HERE,
162 base::Bind(&NotifyCopyCompletion,
163 profile_id, *operation_id,
164 source_url, destination_url, error));
167 // Starts the copy operation via FileSystemOperationRunner.
168 storage::FileSystemOperationRunner::OperationID StartCopyOnIOThread(
169 void* profile_id,
170 scoped_refptr<storage::FileSystemContext> file_system_context,
171 const FileSystemURL& source_url,
172 const FileSystemURL& destination_url) {
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
175 // Note: |operation_id| is owned by the callback for
176 // FileSystemOperationRunner::Copy(). It is always called in the next message
177 // loop or later, so at least during this invocation it should alive.
178 storage::FileSystemOperationRunner::OperationID* operation_id =
179 new storage::FileSystemOperationRunner::OperationID;
180 *operation_id = file_system_context->operation_runner()->Copy(
181 source_url,
182 destination_url,
183 storage::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED,
184 base::Bind(&OnCopyProgress, profile_id, base::Unretained(operation_id)),
185 base::Bind(&OnCopyCompleted,
186 profile_id,
187 base::Owned(operation_id),
188 source_url,
189 destination_url));
190 return *operation_id;
193 void OnCopyCancelled(base::File::Error error) {
194 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
196 // We just ignore the status if the copy is actually cancelled or not,
197 // because failing cancellation means the operation is not running now.
198 DLOG_IF(WARNING, error != base::File::FILE_OK)
199 << "Failed to cancel copy: " << error;
202 // Cancels the running copy operation identified by |operation_id|.
203 void CancelCopyOnIOThread(
204 scoped_refptr<storage::FileSystemContext> file_system_context,
205 storage::FileSystemOperationRunner::OperationID operation_id) {
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
208 file_system_context->operation_runner()->Cancel(
209 operation_id, base::Bind(&OnCopyCancelled));
212 // Converts a status code to a bool value and calls the |callback| with it.
213 void StatusCallbackToResponseCallback(
214 const base::Callback<void(bool)>& callback,
215 base::File::Error result) {
216 callback.Run(result == base::File::FILE_OK);
219 // Calls a response callback (on the UI thread) with a file content hash
220 // computed on the IO thread.
221 void ComputeChecksumRespondOnUIThread(
222 const base::Callback<void(const std::string&)>& callback,
223 const std::string& hash) {
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
225 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
226 base::Bind(callback, hash));
229 // Calls a response callback on the UI thread.
230 void GetFileMetadataRespondOnUIThread(
231 const storage::FileSystemOperation::GetMetadataCallback& callback,
232 base::File::Error result,
233 const base::File::Info& file_info) {
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
235 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
236 base::Bind(callback, result, file_info));
239 } // namespace
241 void FileManagerPrivateRequestFileSystemFunction::DidFail(
242 base::File::Error error_code) {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
245 SetError(base::StringPrintf("File error %d", static_cast<int>(error_code)));
246 SendResponse(false);
249 bool
250 FileManagerPrivateRequestFileSystemFunction::SetupFileSystemAccessPermissions(
251 scoped_refptr<storage::FileSystemContext> file_system_context,
252 int child_id,
253 Profile* profile,
254 scoped_refptr<const extensions::Extension> extension) {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
257 if (!extension.get())
258 return false;
260 storage::ExternalFileSystemBackend* backend =
261 file_system_context->external_backend();
262 if (!backend)
263 return false;
265 // Grant full access to File API from this component extension.
266 backend->GrantFullAccessToExtension(extension_->id());
268 // Grant R/W file permissions to the renderer hosting component
269 // extension for all paths exposed by our local file system backend.
270 std::vector<base::FilePath> root_dirs = backend->GetRootDirectories();
271 for (size_t i = 0; i < root_dirs.size(); ++i) {
272 ChildProcessSecurityPolicy::GetInstance()->GrantCreateReadWriteFile(
273 child_id, root_dirs[i]);
276 // Grant R/W permissions to profile-specific directories (Drive, Downloads)
277 // from other profiles. Those directories may not be mounted at this moment
278 // yet, so we need to do this separately from the above loop over
279 // GetRootDirectories().
280 const std::vector<Profile*>& profiles =
281 g_browser_process->profile_manager()->GetLoadedProfiles();
282 for (size_t i = 0; i < profiles.size(); ++i) {
283 if (!profiles[i]->IsOffTheRecord()) {
284 file_manager::util::SetupProfileFileAccessPermissions(child_id,
285 profiles[i]);
289 // Grant permission to request externalfile scheme. The permission is needed
290 // to start drag for external file URL.
291 ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
292 child_id, content::kExternalFileScheme);
294 return true;
297 bool FileManagerPrivateRequestFileSystemFunction::RunAsync() {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
299 using extensions::api::file_manager_private::RequestFileSystem::Params;
300 const scoped_ptr<Params> params(Params::Create(*args_));
301 EXTENSION_FUNCTION_VALIDATE(params);
303 if (!dispatcher() || !render_view_host() || !render_view_host()->GetProcess())
304 return false;
306 set_log_on_completion(true);
308 using file_manager::VolumeManager;
309 using file_manager::VolumeInfo;
310 VolumeManager* const volume_manager = VolumeManager::Get(GetProfile());
311 if (!volume_manager)
312 return false;
314 VolumeInfo volume_info;
315 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info)) {
316 DidFail(base::File::FILE_ERROR_NOT_FOUND);
317 return false;
320 scoped_refptr<storage::FileSystemContext> file_system_context =
321 file_manager::util::GetFileSystemContextForRenderViewHost(
322 GetProfile(), render_view_host());
324 // Set up file permission access.
325 const int child_id = render_view_host()->GetProcess()->GetID();
326 if (!SetupFileSystemAccessPermissions(
327 file_system_context, child_id, GetProfile(), extension())) {
328 DidFail(base::File::FILE_ERROR_SECURITY);
329 return false;
332 FileDefinition file_definition;
333 if (!file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
334 GetProfile(),
335 extension_id(),
336 volume_info.mount_path,
337 &file_definition.virtual_path)) {
338 DidFail(base::File::FILE_ERROR_INVALID_OPERATION);
339 return false;
341 file_definition.is_directory = true;
343 file_manager::util::ConvertFileDefinitionToEntryDefinition(
344 GetProfile(),
345 extension_id(),
346 file_definition,
347 base::Bind(
348 &FileManagerPrivateRequestFileSystemFunction::OnEntryDefinition,
349 this));
350 return true;
353 void FileManagerPrivateRequestFileSystemFunction::OnEntryDefinition(
354 const EntryDefinition& entry_definition) {
355 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
357 if (entry_definition.error != base::File::FILE_OK) {
358 DidFail(entry_definition.error);
359 return;
362 if (!entry_definition.is_directory) {
363 DidFail(base::File::FILE_ERROR_NOT_A_DIRECTORY);
364 return;
367 base::DictionaryValue* dict = new base::DictionaryValue();
368 SetResult(dict);
369 dict->SetString("name", entry_definition.file_system_name);
370 dict->SetString("root_url", entry_definition.file_system_root_url);
371 dict->SetInteger("error", drive::FILE_ERROR_OK);
372 SendResponse(true);
375 void FileWatchFunctionBase::Respond(bool success) {
376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
378 SetResult(new base::FundamentalValue(success));
379 SendResponse(success);
382 bool FileWatchFunctionBase::RunAsync() {
383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
385 if (!render_view_host() || !render_view_host()->GetProcess())
386 return false;
388 // First param is url of a file to watch.
389 std::string url;
390 if (!args_->GetString(0, &url) || url.empty())
391 return false;
393 scoped_refptr<storage::FileSystemContext> file_system_context =
394 file_manager::util::GetFileSystemContextForRenderViewHost(
395 GetProfile(), render_view_host());
397 const FileSystemURL file_system_url =
398 file_system_context->CrackURL(GURL(url));
399 if (file_system_url.path().empty()) {
400 Respond(false);
401 return true;
404 PerformFileWatchOperation(file_system_context, file_system_url,
405 extension_id());
406 return true;
409 void FileManagerPrivateAddFileWatchFunction::PerformFileWatchOperation(
410 scoped_refptr<storage::FileSystemContext> file_system_context,
411 const storage::FileSystemURL& file_system_url,
412 const std::string& extension_id) {
413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
415 file_manager::EventRouter* const event_router =
416 file_manager::EventRouterFactory::GetForProfile(GetProfile());
418 storage::WatcherManager* const watcher_manager =
419 file_system_context->GetWatcherManager(file_system_url.type());
420 if (watcher_manager) {
421 watcher_manager->AddWatcher(
422 file_system_url, false /* recursive */,
423 base::Bind(
424 &StatusCallbackToResponseCallback,
425 base::Bind(&FileManagerPrivateAddFileWatchFunction::Respond, this)),
426 base::Bind(&file_manager::EventRouter::OnWatcherManagerNotification,
427 event_router->GetWeakPtr(), file_system_url, extension_id));
428 return;
431 // Obsolete. Fallback code if storage::WatcherManager is not implemented.
432 event_router->AddFileWatch(
433 file_system_url.path(), file_system_url.virtual_path(), extension_id,
434 base::Bind(&FileManagerPrivateAddFileWatchFunction::Respond, this));
437 void FileManagerPrivateRemoveFileWatchFunction::PerformFileWatchOperation(
438 scoped_refptr<storage::FileSystemContext> file_system_context,
439 const storage::FileSystemURL& file_system_url,
440 const std::string& extension_id) {
441 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
443 file_manager::EventRouter* const event_router =
444 file_manager::EventRouterFactory::GetForProfile(GetProfile());
446 storage::WatcherManager* const watcher_manager =
447 file_system_context->GetWatcherManager(file_system_url.type());
448 if (watcher_manager) {
449 watcher_manager->RemoveWatcher(
450 file_system_url, false /* recursive */,
451 base::Bind(&StatusCallbackToResponseCallback,
452 base::Bind(&FileWatchFunctionBase::Respond, this)));
453 return;
456 // Obsolete. Fallback code if storage::WatcherManager is not implemented.
457 event_router->RemoveFileWatch(file_system_url.path(), extension_id);
458 Respond(true);
461 bool FileManagerPrivateGetSizeStatsFunction::RunAsync() {
462 using extensions::api::file_manager_private::GetSizeStats::Params;
463 const scoped_ptr<Params> params(Params::Create(*args_));
464 EXTENSION_FUNCTION_VALIDATE(params);
466 using file_manager::VolumeManager;
467 using file_manager::VolumeInfo;
468 VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
469 if (!volume_manager)
470 return false;
472 VolumeInfo volume_info;
473 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info))
474 return false;
476 if (volume_info.type == file_manager::VOLUME_TYPE_GOOGLE_DRIVE) {
477 drive::FileSystemInterface* file_system =
478 drive::util::GetFileSystemByProfile(GetProfile());
479 if (!file_system) {
480 // |file_system| is NULL if Drive is disabled.
481 // If stats couldn't be gotten for drive, result should be left
482 // undefined. See comments in GetDriveAvailableSpaceCallback().
483 SendResponse(true);
484 return true;
487 file_system->GetAvailableSpace(
488 base::Bind(&FileManagerPrivateGetSizeStatsFunction::
489 GetDriveAvailableSpaceCallback,
490 this));
491 } else {
492 uint64* total_size = new uint64(0);
493 uint64* remaining_size = new uint64(0);
494 BrowserThread::PostBlockingPoolTaskAndReply(
495 FROM_HERE,
496 base::Bind(&GetSizeStatsOnBlockingPool,
497 volume_info.mount_path.value(),
498 total_size,
499 remaining_size),
500 base::Bind(&FileManagerPrivateGetSizeStatsFunction::
501 GetSizeStatsCallback,
502 this,
503 base::Owned(total_size),
504 base::Owned(remaining_size)));
506 return true;
509 void FileManagerPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback(
510 drive::FileError error,
511 int64 bytes_total,
512 int64 bytes_used) {
513 if (error == drive::FILE_ERROR_OK) {
514 const uint64 bytes_total_unsigned = bytes_total;
515 const uint64 bytes_remaining_unsigned = bytes_total - bytes_used;
516 GetSizeStatsCallback(&bytes_total_unsigned,
517 &bytes_remaining_unsigned);
518 } else {
519 // If stats couldn't be gotten for drive, result should be left undefined.
520 SendResponse(true);
524 void FileManagerPrivateGetSizeStatsFunction::GetSizeStatsCallback(
525 const uint64* total_size,
526 const uint64* remaining_size) {
527 base::DictionaryValue* sizes = new base::DictionaryValue();
528 SetResult(sizes);
530 sizes->SetDouble("totalSize", static_cast<double>(*total_size));
531 sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size));
533 SendResponse(true);
536 bool FileManagerPrivateValidatePathNameLengthFunction::RunAsync() {
537 using extensions::api::file_manager_private::ValidatePathNameLength::Params;
538 const scoped_ptr<Params> params(Params::Create(*args_));
539 EXTENSION_FUNCTION_VALIDATE(params);
541 scoped_refptr<storage::FileSystemContext> file_system_context =
542 file_manager::util::GetFileSystemContextForRenderViewHost(
543 GetProfile(), render_view_host());
545 storage::FileSystemURL filesystem_url(
546 file_system_context->CrackURL(GURL(params->parent_directory_url)));
547 if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url))
548 return false;
550 // No explicit limit on the length of Drive file names.
551 if (filesystem_url.type() == storage::kFileSystemTypeDrive) {
552 SetResult(new base::FundamentalValue(true));
553 SendResponse(true);
554 return true;
557 base::PostTaskAndReplyWithResult(
558 BrowserThread::GetBlockingPool(),
559 FROM_HERE,
560 base::Bind(&GetFileNameMaxLengthOnBlockingPool,
561 filesystem_url.path().AsUTF8Unsafe()),
562 base::Bind(&FileManagerPrivateValidatePathNameLengthFunction::
563 OnFilePathLimitRetrieved,
564 this, params->name.size()));
565 return true;
568 void FileManagerPrivateValidatePathNameLengthFunction::OnFilePathLimitRetrieved(
569 size_t current_length,
570 size_t max_length) {
571 SetResult(new base::FundamentalValue(current_length <= max_length));
572 SendResponse(true);
575 bool FileManagerPrivateFormatVolumeFunction::RunAsync() {
576 using extensions::api::file_manager_private::FormatVolume::Params;
577 const scoped_ptr<Params> params(Params::Create(*args_));
578 EXTENSION_FUNCTION_VALIDATE(params);
580 using file_manager::VolumeManager;
581 using file_manager::VolumeInfo;
582 VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
583 if (!volume_manager)
584 return false;
586 VolumeInfo volume_info;
587 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info))
588 return false;
590 DiskMountManager::GetInstance()->FormatMountedDevice(
591 volume_info.mount_path.AsUTF8Unsafe());
592 SendResponse(true);
593 return true;
596 // Obtains file size of URL.
597 void GetFileMetadataOnIOThread(
598 scoped_refptr<storage::FileSystemContext> file_system_context,
599 const FileSystemURL& url,
600 const storage::FileSystemOperation::GetMetadataCallback& callback) {
601 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
602 file_system_context->operation_runner()->GetMetadata(
603 url, base::Bind(&GetFileMetadataRespondOnUIThread, callback));
606 // Checks if the available space of the |path| is enough for required |bytes|.
607 bool CheckLocalDiskSpaceOnIOThread(const base::FilePath& path, int64 bytes) {
608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
609 return bytes <= base::SysInfo::AmountOfFreeDiskSpace(path) -
610 cryptohome::kMinFreeSpaceInBytes;
613 bool FileManagerPrivateStartCopyFunction::RunAsync() {
614 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
616 using extensions::api::file_manager_private::StartCopy::Params;
617 const scoped_ptr<Params> params(Params::Create(*args_));
618 EXTENSION_FUNCTION_VALIDATE(params);
620 if (params->source_url.empty() || params->parent.empty() ||
621 params->new_name.empty()) {
622 // Error code in format of DOMError.name.
623 SetError("EncodingError");
624 return false;
627 scoped_refptr<storage::FileSystemContext> file_system_context =
628 file_manager::util::GetFileSystemContextForRenderViewHost(
629 GetProfile(), render_view_host());
631 // |parent| may have a trailing slash if it is a root directory.
632 std::string destination_url_string = params->parent;
633 if (destination_url_string[destination_url_string.size() - 1] != '/')
634 destination_url_string += '/';
635 destination_url_string += net::EscapePath(params->new_name);
637 source_url_ = file_system_context->CrackURL(GURL(params->source_url));
638 destination_url_ =
639 file_system_context->CrackURL(GURL(destination_url_string));
641 if (!source_url_.is_valid() || !destination_url_.is_valid()) {
642 // Error code in format of DOMError.name.
643 SetError("EncodingError");
644 return false;
647 // Check if the destination directory is downloads. If so, secure available
648 // spece by freeing drive caches.
649 if (destination_url_.filesystem_id() ==
650 file_manager::util::GetDownloadsMountPointName(GetProfile())) {
651 return BrowserThread::PostTask(
652 BrowserThread::IO, FROM_HERE,
653 base::Bind(
654 &GetFileMetadataOnIOThread, file_system_context, source_url_,
655 base::Bind(
656 &FileManagerPrivateStartCopyFunction::RunAfterGetFileMetadata,
657 this)));
660 return BrowserThread::PostTask(
661 BrowserThread::UI, FROM_HERE,
662 base::Bind(&FileManagerPrivateStartCopyFunction::RunAfterFreeDiskSpace,
663 this, true));
666 void FileManagerPrivateStartCopyFunction::RunAfterGetFileMetadata(
667 base::File::Error result,
668 const base::File::Info& file_info) {
669 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
671 if (result != base::File::FILE_OK) {
672 SetError("NotFoundError");
673 SendResponse(false);
674 return;
677 drive::FileSystemInterface* const drive_file_system =
678 drive::util::GetFileSystemByProfile(GetProfile());
679 if (drive_file_system) {
680 drive_file_system->FreeDiskSpaceIfNeededFor(
681 file_info.size,
682 base::Bind(&FileManagerPrivateStartCopyFunction::RunAfterFreeDiskSpace,
683 this));
684 } else {
685 const bool result = BrowserThread::PostTaskAndReplyWithResult(
686 BrowserThread::IO, FROM_HERE,
687 base::Bind(
688 &CheckLocalDiskSpaceOnIOThread,
689 file_manager::util::GetDownloadsFolderForProfile(GetProfile()),
690 file_info.size),
691 base::Bind(&FileManagerPrivateStartCopyFunction::RunAfterFreeDiskSpace,
692 this));
693 if (!result)
694 SendResponse(false);
698 void FileManagerPrivateStartCopyFunction::RunAfterFreeDiskSpace(
699 bool available) {
700 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
702 if (!available) {
703 SetError("QuotaExceededError");
704 SendResponse(false);
705 return;
708 scoped_refptr<storage::FileSystemContext> file_system_context =
709 file_manager::util::GetFileSystemContextForRenderViewHost(
710 GetProfile(), render_view_host());
711 const bool result = BrowserThread::PostTaskAndReplyWithResult(
712 BrowserThread::IO, FROM_HERE,
713 base::Bind(&StartCopyOnIOThread, GetProfile(), file_system_context,
714 source_url_, destination_url_),
715 base::Bind(&FileManagerPrivateStartCopyFunction::RunAfterStartCopy,
716 this));
717 if (!result)
718 SendResponse(false);
721 void FileManagerPrivateStartCopyFunction::RunAfterStartCopy(
722 int operation_id) {
723 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
725 SetResult(new base::FundamentalValue(operation_id));
726 SendResponse(true);
729 bool FileManagerPrivateCancelCopyFunction::RunAsync() {
730 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
732 using extensions::api::file_manager_private::CancelCopy::Params;
733 const scoped_ptr<Params> params(Params::Create(*args_));
734 EXTENSION_FUNCTION_VALIDATE(params);
736 scoped_refptr<storage::FileSystemContext> file_system_context =
737 file_manager::util::GetFileSystemContextForRenderViewHost(
738 GetProfile(), render_view_host());
740 // We don't much take care about the result of cancellation.
741 BrowserThread::PostTask(
742 BrowserThread::IO,
743 FROM_HERE,
744 base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id));
745 SendResponse(true);
746 return true;
749 bool FileManagerPrivateInternalResolveIsolatedEntriesFunction::RunAsync() {
750 using extensions::api::file_manager_private_internal::ResolveIsolatedEntries::
751 Params;
752 const scoped_ptr<Params> params(Params::Create(*args_));
753 EXTENSION_FUNCTION_VALIDATE(params);
755 scoped_refptr<storage::FileSystemContext> file_system_context =
756 file_manager::util::GetFileSystemContextForRenderViewHost(
757 GetProfile(), render_view_host());
758 DCHECK(file_system_context.get());
760 const storage::ExternalFileSystemBackend* external_backend =
761 file_system_context->external_backend();
762 DCHECK(external_backend);
764 file_manager::util::FileDefinitionList file_definition_list;
765 for (size_t i = 0; i < params->urls.size(); ++i) {
766 FileSystemURL fileSystemUrl =
767 file_system_context->CrackURL(GURL(params->urls[i]));
768 DCHECK(external_backend->CanHandleType(fileSystemUrl.type()));
770 FileDefinition file_definition;
771 const bool result =
772 file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
773 GetProfile(),
774 extension_->id(),
775 fileSystemUrl.path(),
776 &file_definition.virtual_path);
777 if (!result)
778 continue;
779 // The API only supports isolated files.
780 file_definition.is_directory = false;
781 file_definition_list.push_back(file_definition);
784 file_manager::util::ConvertFileDefinitionListToEntryDefinitionList(
785 GetProfile(),
786 extension_->id(),
787 file_definition_list, // Safe, since copied internally.
788 base::Bind(
789 &FileManagerPrivateInternalResolveIsolatedEntriesFunction::
790 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList,
791 this));
792 return true;
795 void FileManagerPrivateInternalResolveIsolatedEntriesFunction::
796 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList(scoped_ptr<
797 file_manager::util::EntryDefinitionList> entry_definition_list) {
798 using extensions::api::file_manager_private_internal::EntryDescription;
799 std::vector<linked_ptr<EntryDescription> > entries;
801 for (size_t i = 0; i < entry_definition_list->size(); ++i) {
802 if (entry_definition_list->at(i).error != base::File::FILE_OK)
803 continue;
804 linked_ptr<EntryDescription> entry(new EntryDescription);
805 entry->file_system_name = entry_definition_list->at(i).file_system_name;
806 entry->file_system_root = entry_definition_list->at(i).file_system_root_url;
807 entry->file_full_path =
808 "/" + entry_definition_list->at(i).full_path.AsUTF8Unsafe();
809 entry->file_is_directory = entry_definition_list->at(i).is_directory;
810 entries.push_back(entry);
813 results_ = extensions::api::file_manager_private_internal::
814 ResolveIsolatedEntries::Results::Create(entries);
815 SendResponse(true);
818 FileManagerPrivateComputeChecksumFunction::
819 FileManagerPrivateComputeChecksumFunction()
820 : digester_(new drive::util::FileStreamMd5Digester()) {
823 FileManagerPrivateComputeChecksumFunction::
824 ~FileManagerPrivateComputeChecksumFunction() {
827 bool FileManagerPrivateComputeChecksumFunction::RunAsync() {
828 using extensions::api::file_manager_private::ComputeChecksum::Params;
829 using drive::util::FileStreamMd5Digester;
830 const scoped_ptr<Params> params(Params::Create(*args_));
831 EXTENSION_FUNCTION_VALIDATE(params);
833 if (params->file_url.empty()) {
834 SetError("File URL must be provided");
835 return false;
838 scoped_refptr<storage::FileSystemContext> file_system_context =
839 file_manager::util::GetFileSystemContextForRenderViewHost(
840 GetProfile(), render_view_host());
842 FileSystemURL file_url(file_system_context->CrackURL(GURL(params->file_url)));
843 if (!file_url.is_valid()) {
844 SetError("File URL was invalid");
845 return false;
848 scoped_ptr<storage::FileStreamReader> reader =
849 file_system_context->CreateFileStreamReader(
850 file_url, 0, storage::kMaximumLength, base::Time());
852 FileStreamMd5Digester::ResultCallback result_callback = base::Bind(
853 &ComputeChecksumRespondOnUIThread,
854 base::Bind(&FileManagerPrivateComputeChecksumFunction::Respond, this));
855 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
856 base::Bind(&FileStreamMd5Digester::GetMd5Digest,
857 base::Unretained(digester_.get()),
858 base::Passed(&reader), result_callback));
860 return true;
863 void FileManagerPrivateComputeChecksumFunction::Respond(
864 const std::string& hash) {
865 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
866 SetResult(new base::StringValue(hash));
867 SendResponse(true);
870 bool FileManagerPrivateSearchFilesByHashesFunction::RunAsync() {
871 using api::file_manager_private::SearchFilesByHashes::Params;
872 const scoped_ptr<Params> params(Params::Create(*args_));
873 EXTENSION_FUNCTION_VALIDATE(params);
875 // TODO(hirono): Check the volume ID and fail the function for volumes other
876 // than Drive.
878 drive::EventLogger* const logger =
879 file_manager::util::GetLogger(GetProfile());
880 if (logger) {
881 logger->Log(logging::LOG_INFO,
882 "%s[%d] called. (volume id: %s, number of hashes: %zd)", name(),
883 request_id(), params->volume_id.c_str(),
884 params->hash_list.size());
886 set_log_on_completion(true);
888 drive::FileSystemInterface* const file_system =
889 drive::util::GetFileSystemByProfile(GetProfile());
890 if (!file_system) {
891 // |file_system| is NULL if Drive is disabled.
892 return false;
895 std::set<std::string> hashes(params->hash_list.begin(),
896 params->hash_list.end());
897 file_system->SearchByHashes(
898 hashes,
899 base::Bind(
900 &FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes,
901 this, hashes));
902 return true;
905 void FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes(
906 const std::set<std::string>& hashes,
907 drive::FileError error,
908 const std::vector<drive::HashAndFilePath>& search_results) {
909 if (error != drive::FileError::FILE_ERROR_OK) {
910 SendResponse(false);
911 return;
914 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
915 for (const auto& hash : hashes) {
916 result->SetWithoutPathExpansion(hash,
917 make_scoped_ptr(new base::ListValue()));
920 for (const auto& hashAndPath : search_results) {
921 DCHECK(result->HasKey(hashAndPath.hash));
922 base::ListValue* list;
923 result->GetListWithoutPathExpansion(hashAndPath.hash, &list);
924 list->AppendString(
925 file_manager::util::ConvertDrivePathToFileSystemUrl(
926 GetProfile(), hashAndPath.path, extension_id()).spec());
928 SetResult(result.release());
929 SendResponse(true);
932 ExtensionFunction::ResponseAction
933 FileManagerPrivateIsUMAEnabledFunction::Run() {
934 return RespondNow(OneArgument(new base::FundamentalValue(
935 ChromeMetricsServiceAccessor::IsMetricsReportingEnabled())));
938 FileManagerPrivateSetEntryTagFunction::FileManagerPrivateSetEntryTagFunction()
939 : chrome_details_(this) {
942 ExtensionFunction::ResponseAction FileManagerPrivateSetEntryTagFunction::Run() {
943 using extensions::api::file_manager_private::SetEntryTag::Params;
944 const scoped_ptr<Params> params(Params::Create(*args_));
945 EXTENSION_FUNCTION_VALIDATE(params);
947 const base::FilePath local_path = file_manager::util::GetLocalPathFromURL(
948 render_view_host(), chrome_details_.GetProfile(),
949 GURL(params->entry_url));
950 const base::FilePath drive_path = drive::util::ExtractDrivePath(local_path);
951 if (drive_path.empty())
952 return RespondNow(Error("Only Drive files and directories are supported."));
954 drive::FileSystemInterface* const file_system =
955 drive::util::GetFileSystemByProfile(chrome_details_.GetProfile());
956 // |file_system| is NULL if Drive is disabled.
957 if (!file_system)
958 return RespondNow(Error("Drive is disabled."));
960 google_apis::drive::Property::Visibility visibility;
961 switch (params->visibility) {
962 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PRIVATE:
963 visibility = google_apis::drive::Property::VISIBILITY_PRIVATE;
964 break;
965 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PUBLIC:
966 visibility = google_apis::drive::Property::VISIBILITY_PUBLIC;
967 break;
968 default:
969 NOTREACHED();
970 return RespondNow(Error("Invalid visibility."));
971 break;
974 file_system->SetProperty(
975 drive_path, visibility, params->key, params->value,
976 base::Bind(
977 &FileManagerPrivateSetEntryTagFunction::OnSetEntryPropertyCompleted,
978 this));
979 return RespondLater();
982 void FileManagerPrivateSetEntryTagFunction::OnSetEntryPropertyCompleted(
983 drive::FileError result) {
984 Respond(result == drive::FILE_ERROR_OK ? NoArguments()
985 : Error("Failed to set a tag."));
988 } // namespace extensions