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>
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
{
60 // Retrieves total and remaining available size on |mount_path|.
61 void GetSizeStatsOnBlockingPool(const std::string
& mount_path
,
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
;
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
90 Profile
* profile
= reinterpret_cast<Profile
*>(profile_id
);
91 if (!g_browser_process
->profile_manager()->IsValidProfile(profile
))
94 return file_manager::EventRouterFactory::GetForProfile(profile
);
97 // Notifies the copy progress to extensions via event router.
98 void NotifyCopyProgress(
100 storage::FileSystemOperationRunner::OperationID operation_id
,
101 storage::FileSystemOperation::CopyProgressType type
,
102 const FileSystemURL
& source_url
,
103 const FileSystemURL
& destination_url
,
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
107 file_manager::EventRouter
* event_router
=
108 GetEventRouterByProfileId(profile_id
);
110 event_router
->OnCopyProgress(
112 source_url
.ToGURL(), destination_url
.ToGURL(), size
);
116 // Callback invoked periodically on progress update of Copy().
119 storage::FileSystemOperationRunner::OperationID
* operation_id
,
120 storage::FileSystemOperation::CopyProgressType type
,
121 const FileSystemURL
& source_url
,
122 const FileSystemURL
& destination_url
,
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(
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
);
145 event_router
->OnCopyCompleted(
147 source_url
.ToGURL(), destination_url
.ToGURL(), error
);
150 // Callback invoked upon completion of Copy() (regardless of succeeded or
152 void OnCopyCompleted(
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(
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(
183 storage::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED
,
184 base::Bind(&OnCopyProgress
, profile_id
, base::Unretained(operation_id
)),
185 base::Bind(&OnCopyCompleted
,
187 base::Owned(operation_id
),
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
));
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
)));
250 FileManagerPrivateRequestFileSystemFunction::SetupFileSystemAccessPermissions(
251 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
254 scoped_refptr
<const extensions::Extension
> extension
) {
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
257 if (!extension
.get())
260 storage::ExternalFileSystemBackend
* backend
=
261 file_system_context
->external_backend();
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
,
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
);
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())
306 set_log_on_completion(true);
308 using file_manager::VolumeManager
;
309 using file_manager::VolumeInfo
;
310 VolumeManager
* const volume_manager
= VolumeManager::Get(GetProfile());
314 VolumeInfo volume_info
;
315 if (!volume_manager
->FindVolumeInfoById(params
->volume_id
, &volume_info
)) {
316 DidFail(base::File::FILE_ERROR_NOT_FOUND
);
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
);
332 FileDefinition file_definition
;
333 if (!file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
336 volume_info
.mount_path
,
337 &file_definition
.virtual_path
)) {
338 DidFail(base::File::FILE_ERROR_INVALID_OPERATION
);
341 file_definition
.is_directory
= true;
343 file_manager::util::ConvertFileDefinitionToEntryDefinition(
348 &FileManagerPrivateRequestFileSystemFunction::OnEntryDefinition
,
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
);
362 if (!entry_definition
.is_directory
) {
363 DidFail(base::File::FILE_ERROR_NOT_A_DIRECTORY
);
367 base::DictionaryValue
* dict
= new base::DictionaryValue();
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
);
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())
388 // First param is url of a file to watch.
390 if (!args_
->GetString(0, &url
) || url
.empty())
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()) {
404 PerformFileWatchOperation(file_system_context
, file_system_url
,
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 */,
424 &StatusCallbackToResponseCallback
,
425 base::Bind(&FileManagerPrivateAddFileWatchFunction::Respond
, this)),
426 base::Bind(&file_manager::EventRouter::OnWatcherManagerNotification
,
427 event_router
->GetWeakPtr(), file_system_url
, extension_id
));
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)));
456 // Obsolete. Fallback code if storage::WatcherManager is not implemented.
457 event_router
->RemoveFileWatch(file_system_url
.path(), extension_id
);
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());
472 VolumeInfo volume_info
;
473 if (!volume_manager
->FindVolumeInfoById(params
->volume_id
, &volume_info
))
476 if (volume_info
.type
== file_manager::VOLUME_TYPE_GOOGLE_DRIVE
) {
477 drive::FileSystemInterface
* file_system
=
478 drive::util::GetFileSystemByProfile(GetProfile());
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().
487 file_system
->GetAvailableSpace(
488 base::Bind(&FileManagerPrivateGetSizeStatsFunction::
489 GetDriveAvailableSpaceCallback
,
492 uint64
* total_size
= new uint64(0);
493 uint64
* remaining_size
= new uint64(0);
494 BrowserThread::PostBlockingPoolTaskAndReply(
496 base::Bind(&GetSizeStatsOnBlockingPool
,
497 volume_info
.mount_path
.value(),
500 base::Bind(&FileManagerPrivateGetSizeStatsFunction::
501 GetSizeStatsCallback
,
503 base::Owned(total_size
),
504 base::Owned(remaining_size
)));
509 void FileManagerPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback(
510 drive::FileError error
,
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
);
519 // If stats couldn't be gotten for drive, result should be left undefined.
524 void FileManagerPrivateGetSizeStatsFunction::GetSizeStatsCallback(
525 const uint64
* total_size
,
526 const uint64
* remaining_size
) {
527 base::DictionaryValue
* sizes
= new base::DictionaryValue();
530 sizes
->SetDouble("totalSize", static_cast<double>(*total_size
));
531 sizes
->SetDouble("remainingSize", static_cast<double>(*remaining_size
));
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
))
550 // No explicit limit on the length of Drive file names.
551 if (filesystem_url
.type() == storage::kFileSystemTypeDrive
) {
552 SetResult(new base::FundamentalValue(true));
557 base::PostTaskAndReplyWithResult(
558 BrowserThread::GetBlockingPool(),
560 base::Bind(&GetFileNameMaxLengthOnBlockingPool
,
561 filesystem_url
.path().AsUTF8Unsafe()),
562 base::Bind(&FileManagerPrivateValidatePathNameLengthFunction::
563 OnFilePathLimitRetrieved
,
564 this, params
->name
.size()));
568 void FileManagerPrivateValidatePathNameLengthFunction::OnFilePathLimitRetrieved(
569 size_t current_length
,
571 SetResult(new base::FundamentalValue(current_length
<= max_length
));
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());
586 VolumeInfo volume_info
;
587 if (!volume_manager
->FindVolumeInfoById(params
->volume_id
, &volume_info
))
590 DiskMountManager::GetInstance()->FormatMountedDevice(
591 volume_info
.mount_path
.AsUTF8Unsafe());
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");
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
));
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");
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
,
654 &GetFileMetadataOnIOThread
, file_system_context
, source_url_
,
656 &FileManagerPrivateStartCopyFunction::RunAfterGetFileMetadata
,
660 return BrowserThread::PostTask(
661 BrowserThread::UI
, FROM_HERE
,
662 base::Bind(&FileManagerPrivateStartCopyFunction::RunAfterFreeDiskSpace
,
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");
677 drive::FileSystemInterface
* const drive_file_system
=
678 drive::util::GetFileSystemByProfile(GetProfile());
679 if (drive_file_system
) {
680 drive_file_system
->FreeDiskSpaceIfNeededFor(
682 base::Bind(&FileManagerPrivateStartCopyFunction::RunAfterFreeDiskSpace
,
685 const bool result
= BrowserThread::PostTaskAndReplyWithResult(
686 BrowserThread::IO
, FROM_HERE
,
688 &CheckLocalDiskSpaceOnIOThread
,
689 file_manager::util::GetDownloadsFolderForProfile(GetProfile()),
691 base::Bind(&FileManagerPrivateStartCopyFunction::RunAfterFreeDiskSpace
,
698 void FileManagerPrivateStartCopyFunction::RunAfterFreeDiskSpace(
700 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
703 SetError("QuotaExceededError");
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
,
721 void FileManagerPrivateStartCopyFunction::RunAfterStartCopy(
723 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
725 SetResult(new base::FundamentalValue(operation_id
));
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(
744 base::Bind(&CancelCopyOnIOThread
, file_system_context
, params
->copy_id
));
749 bool FileManagerPrivateInternalResolveIsolatedEntriesFunction::RunAsync() {
750 using extensions::api::file_manager_private_internal::ResolveIsolatedEntries::
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
;
772 file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
775 fileSystemUrl
.path(),
776 &file_definition
.virtual_path
);
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(
787 file_definition_list
, // Safe, since copied internally.
789 &FileManagerPrivateInternalResolveIsolatedEntriesFunction::
790 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList
,
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
)
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
);
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");
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");
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
));
863 void FileManagerPrivateComputeChecksumFunction::Respond(
864 const std::string
& hash
) {
865 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
866 SetResult(new base::StringValue(hash
));
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
878 drive::EventLogger
* const logger
=
879 file_manager::util::GetLogger(GetProfile());
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());
891 // |file_system| is NULL if Drive is disabled.
895 std::set
<std::string
> hashes(params
->hash_list
.begin(),
896 params
->hash_list
.end());
897 file_system
->SearchByHashes(
900 &FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes
,
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
) {
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
);
925 file_manager::util::ConvertDrivePathToFileSystemUrl(
926 GetProfile(), hashAndPath
.path
, extension_id()).spec());
928 SetResult(result
.release());
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.
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
;
965 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PUBLIC
:
966 visibility
= google_apis::drive::Property::VISIBILITY_PUBLIC
;
970 return RespondNow(Error("Invalid visibility."));
974 file_system
->SetProperty(
975 drive_path
, visibility
, params
->key
, params
->value
,
977 &FileManagerPrivateSetEntryTagFunction::OnSetEntryPropertyCompleted
,
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