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/memory/weak_ptr.h"
11 #include "base/posix/eintr_wrapper.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/sys_info.h"
16 #include "base/task_runner_util.h"
17 #include "base/threading/sequenced_worker_pool.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chromeos/drive/file_system_interface.h"
20 #include "chrome/browser/chromeos/drive/file_system_util.h"
21 #include "chrome/browser/chromeos/extensions/file_manager/event_router.h"
22 #include "chrome/browser/chromeos/extensions/file_manager/event_router_factory.h"
23 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
24 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
25 #include "chrome/browser/chromeos/file_manager/path_util.h"
26 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
27 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
28 #include "chrome/browser/extensions/extension_util.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 "components/drive/drive.pb.h"
36 #include "components/drive/drive_api_util.h"
37 #include "components/drive/event_logger.h"
38 #include "components/storage_monitor/storage_info.h"
39 #include "components/storage_monitor/storage_monitor.h"
40 #include "content/public/browser/child_process_security_policy.h"
41 #include "content/public/browser/render_frame_host.h"
42 #include "content/public/browser/render_process_host.h"
43 #include "content/public/browser/storage_partition.h"
44 #include "content/public/common/url_constants.h"
45 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
46 #include "net/base/escape.h"
47 #include "storage/browser/fileapi/file_stream_reader.h"
48 #include "storage/browser/fileapi/file_system_context.h"
49 #include "storage/browser/fileapi/file_system_file_util.h"
50 #include "storage/browser/fileapi/file_system_operation_context.h"
51 #include "storage/browser/fileapi/file_system_operation_runner.h"
52 #include "storage/common/fileapi/file_system_info.h"
53 #include "storage/common/fileapi/file_system_types.h"
54 #include "storage/common/fileapi/file_system_util.h"
55 #include "third_party/cros_system_api/constants/cryptohome.h"
57 using chromeos::disks::DiskMountManager
;
58 using content::BrowserThread
;
59 using content::ChildProcessSecurityPolicy
;
60 using file_manager::util::EntryDefinition
;
61 using file_manager::util::FileDefinition
;
62 using storage::FileSystemURL
;
64 namespace extensions
{
67 const char kRootPath
[] = "/";
69 // Retrieves total and remaining available size on |mount_path|.
70 void GetSizeStatsOnBlockingPool(const std::string
& mount_path
,
72 uint64
* remaining_size
) {
73 struct statvfs stat
= {}; // Zero-clear
74 if (HANDLE_EINTR(statvfs(mount_path
.c_str(), &stat
)) == 0) {
75 *total_size
= static_cast<uint64
>(stat
.f_blocks
) * stat
.f_frsize
;
76 *remaining_size
= static_cast<uint64
>(stat
.f_bavail
) * stat
.f_frsize
;
80 // Retrieves the maximum file name length of the file system of |path|.
81 // Returns 0 if it could not be queried.
82 size_t GetFileNameMaxLengthOnBlockingPool(const std::string
& path
) {
83 struct statvfs stat
= {};
84 if (HANDLE_EINTR(statvfs(path
.c_str(), &stat
)) != 0) {
85 // The filesystem seems not supporting statvfs(). Assume it to be a commonly
86 // used bound 255, and log the failure.
87 LOG(ERROR
) << "Cannot statvfs() the name length limit for: " << path
;
90 return stat
.f_namemax
;
93 // Returns EventRouter for the |profile_id| if available.
94 file_manager::EventRouter
* GetEventRouterByProfileId(void* profile_id
) {
95 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
97 // |profile_id| needs to be checked with ProfileManager::IsValidProfile
99 Profile
* profile
= reinterpret_cast<Profile
*>(profile_id
);
100 if (!g_browser_process
->profile_manager()->IsValidProfile(profile
))
103 return file_manager::EventRouterFactory::GetForProfile(profile
);
106 // Notifies the copy progress to extensions via event router.
107 void NotifyCopyProgress(
109 storage::FileSystemOperationRunner::OperationID operation_id
,
110 storage::FileSystemOperation::CopyProgressType type
,
111 const FileSystemURL
& source_url
,
112 const FileSystemURL
& destination_url
,
114 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
116 file_manager::EventRouter
* event_router
=
117 GetEventRouterByProfileId(profile_id
);
119 event_router
->OnCopyProgress(
121 source_url
.ToGURL(), destination_url
.ToGURL(), size
);
125 // Callback invoked periodically on progress update of Copy().
128 storage::FileSystemOperationRunner::OperationID
* operation_id
,
129 storage::FileSystemOperation::CopyProgressType type
,
130 const FileSystemURL
& source_url
,
131 const FileSystemURL
& destination_url
,
133 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
135 BrowserThread::PostTask(
136 BrowserThread::UI
, FROM_HERE
,
137 base::Bind(&NotifyCopyProgress
,
138 profile_id
, *operation_id
, type
,
139 source_url
, destination_url
, size
));
142 // Notifies the copy completion to extensions via event router.
143 void NotifyCopyCompletion(
145 storage::FileSystemOperationRunner::OperationID operation_id
,
146 const FileSystemURL
& source_url
,
147 const FileSystemURL
& destination_url
,
148 base::File::Error error
) {
149 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
151 file_manager::EventRouter
* event_router
=
152 GetEventRouterByProfileId(profile_id
);
154 event_router
->OnCopyCompleted(
156 source_url
.ToGURL(), destination_url
.ToGURL(), error
);
159 // Callback invoked upon completion of Copy() (regardless of succeeded or
161 void OnCopyCompleted(
163 storage::FileSystemOperationRunner::OperationID
* operation_id
,
164 const FileSystemURL
& source_url
,
165 const FileSystemURL
& destination_url
,
166 base::File::Error error
) {
167 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
169 BrowserThread::PostTask(
170 BrowserThread::UI
, FROM_HERE
,
171 base::Bind(&NotifyCopyCompletion
,
172 profile_id
, *operation_id
,
173 source_url
, destination_url
, error
));
176 // Starts the copy operation via FileSystemOperationRunner.
177 storage::FileSystemOperationRunner::OperationID
StartCopyOnIOThread(
179 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
180 const FileSystemURL
& source_url
,
181 const FileSystemURL
& destination_url
) {
182 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
184 // Note: |operation_id| is owned by the callback for
185 // FileSystemOperationRunner::Copy(). It is always called in the next message
186 // loop or later, so at least during this invocation it should alive.
188 // TODO(yawano): change ERROR_BEHAVIOR_ABORT to ERROR_BEHAVIOR_SKIP after
189 // error messages of individual operations become appear in the Files.app
191 storage::FileSystemOperationRunner::OperationID
* operation_id
=
192 new storage::FileSystemOperationRunner::OperationID
;
193 *operation_id
= file_system_context
->operation_runner()->Copy(
194 source_url
, destination_url
,
195 storage::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED
,
196 storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT
,
197 base::Bind(&OnCopyProgress
, profile_id
, base::Unretained(operation_id
)),
198 base::Bind(&OnCopyCompleted
, profile_id
, base::Owned(operation_id
),
199 source_url
, destination_url
));
200 return *operation_id
;
203 void OnCopyCancelled(base::File::Error error
) {
204 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
206 // We just ignore the status if the copy is actually cancelled or not,
207 // because failing cancellation means the operation is not running now.
208 DLOG_IF(WARNING
, error
!= base::File::FILE_OK
)
209 << "Failed to cancel copy: " << error
;
212 // Cancels the running copy operation identified by |operation_id|.
213 void CancelCopyOnIOThread(
214 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
215 storage::FileSystemOperationRunner::OperationID operation_id
) {
216 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
218 file_system_context
->operation_runner()->Cancel(
219 operation_id
, base::Bind(&OnCopyCancelled
));
222 // Converts a status code to a bool value and calls the |callback| with it.
223 void StatusCallbackToResponseCallback(
224 const base::Callback
<void(bool)>& callback
,
225 base::File::Error result
) {
226 callback
.Run(result
== base::File::FILE_OK
);
229 // Calls a response callback (on the UI thread) with a file content hash
230 // computed on the IO thread.
231 void ComputeChecksumRespondOnUIThread(
232 const base::Callback
<void(const std::string
&)>& callback
,
233 const std::string
& hash
) {
234 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
235 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
236 base::Bind(callback
, hash
));
239 // Calls a response callback on the UI thread.
240 void GetFileMetadataRespondOnUIThread(
241 const storage::FileSystemOperation::GetMetadataCallback
& callback
,
242 base::File::Error result
,
243 const base::File::Info
& file_info
) {
244 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
245 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
246 base::Bind(callback
, result
, file_info
));
251 ExtensionFunction::ResponseAction
252 FileManagerPrivateEnableExternalFileSchemeFunction::Run() {
253 ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
254 render_frame_host()->GetProcess()->GetID(), content::kExternalFileScheme
);
255 return RespondNow(NoArguments());
258 FileManagerPrivateGrantAccessFunction::FileManagerPrivateGrantAccessFunction()
259 : chrome_details_(this) {
262 ExtensionFunction::ResponseAction
FileManagerPrivateGrantAccessFunction::Run() {
263 using extensions::api::file_manager_private::GrantAccess::Params
;
264 const scoped_ptr
<Params
> params(Params::Create(*args_
));
265 EXTENSION_FUNCTION_VALIDATE(params
);
267 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
268 file_manager::util::GetFileSystemContextForRenderFrameHost(
269 chrome_details_
.GetProfile(), render_frame_host());
271 storage::ExternalFileSystemBackend
* const backend
=
272 file_system_context
->external_backend();
275 const std::vector
<Profile
*>& profiles
=
276 g_browser_process
->profile_manager()->GetLoadedProfiles();
277 for (const auto& profile
: profiles
) {
278 if (profile
->IsOffTheRecord())
280 const GURL site
= util::GetSiteForExtensionId(extension_id(), profile
);
281 storage::FileSystemContext
* const context
=
282 content::BrowserContext::GetStoragePartitionForSite(profile
, site
)
283 ->GetFileSystemContext();
284 for (const auto& url
: params
->entry_urls
) {
285 const storage::FileSystemURL file_system_url
=
286 context
->CrackURL(GURL(url
));
287 // Grant permissions only to valid urls backed by the external file system
289 if (!file_system_url
.is_valid() ||
290 file_system_url
.mount_type() != storage::kFileSystemTypeExternal
) {
293 backend
->GrantFileAccessToExtension(extension_
->id(),
294 file_system_url
.virtual_path());
295 content::ChildProcessSecurityPolicy::GetInstance()
296 ->GrantCreateReadWriteFile(render_frame_host()->GetProcess()->GetID(),
297 file_system_url
.path());
300 return RespondNow(NoArguments());
303 void FileWatchFunctionBase::Respond(bool success
) {
304 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
306 SetResult(new base::FundamentalValue(success
));
307 SendResponse(success
);
310 bool FileWatchFunctionBase::RunAsync() {
311 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
313 if (!render_frame_host() || !render_frame_host()->GetProcess())
316 // First param is url of a file to watch.
318 if (!args_
->GetString(0, &url
) || url
.empty())
321 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
322 file_manager::util::GetFileSystemContextForRenderFrameHost(
323 GetProfile(), render_frame_host());
325 const FileSystemURL file_system_url
=
326 file_system_context
->CrackURL(GURL(url
));
327 if (file_system_url
.path().empty()) {
332 PerformFileWatchOperation(file_system_context
, file_system_url
,
337 void FileManagerPrivateInternalAddFileWatchFunction::PerformFileWatchOperation(
338 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
339 const storage::FileSystemURL
& file_system_url
,
340 const std::string
& extension_id
) {
341 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
343 file_manager::EventRouter
* const event_router
=
344 file_manager::EventRouterFactory::GetForProfile(GetProfile());
346 storage::WatcherManager
* const watcher_manager
=
347 file_system_context
->GetWatcherManager(file_system_url
.type());
348 if (watcher_manager
) {
349 watcher_manager
->AddWatcher(
350 file_system_url
, false /* recursive */,
352 &StatusCallbackToResponseCallback
,
353 base::Bind(&FileManagerPrivateInternalAddFileWatchFunction::Respond
,
355 base::Bind(&file_manager::EventRouter::OnWatcherManagerNotification
,
356 event_router
->GetWeakPtr(), file_system_url
, extension_id
));
360 // Obsolete. Fallback code if storage::WatcherManager is not implemented.
361 event_router
->AddFileWatch(
362 file_system_url
.path(), file_system_url
.virtual_path(), extension_id
,
363 base::Bind(&FileManagerPrivateInternalAddFileWatchFunction::Respond
,
367 void FileManagerPrivateInternalRemoveFileWatchFunction::
368 PerformFileWatchOperation(
369 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
370 const storage::FileSystemURL
& file_system_url
,
371 const std::string
& extension_id
) {
372 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
374 file_manager::EventRouter
* const event_router
=
375 file_manager::EventRouterFactory::GetForProfile(GetProfile());
377 storage::WatcherManager
* const watcher_manager
=
378 file_system_context
->GetWatcherManager(file_system_url
.type());
379 if (watcher_manager
) {
380 watcher_manager
->RemoveWatcher(
381 file_system_url
, false /* recursive */,
382 base::Bind(&StatusCallbackToResponseCallback
,
383 base::Bind(&FileWatchFunctionBase::Respond
, this)));
387 // Obsolete. Fallback code if storage::WatcherManager is not implemented.
388 event_router
->RemoveFileWatch(file_system_url
.path(), extension_id
);
392 bool FileManagerPrivateGetSizeStatsFunction::RunAsync() {
393 using extensions::api::file_manager_private::GetSizeStats::Params
;
394 const scoped_ptr
<Params
> params(Params::Create(*args_
));
395 EXTENSION_FUNCTION_VALIDATE(params
);
397 using file_manager::VolumeManager
;
398 using file_manager::Volume
;
399 VolumeManager
* const volume_manager
= VolumeManager::Get(GetProfile());
403 base::WeakPtr
<Volume
> volume
=
404 volume_manager
->FindVolumeById(params
->volume_id
);
408 if (volume
->type() == file_manager::VOLUME_TYPE_GOOGLE_DRIVE
) {
409 drive::FileSystemInterface
* file_system
=
410 drive::util::GetFileSystemByProfile(GetProfile());
412 // |file_system| is NULL if Drive is disabled.
413 // If stats couldn't be gotten for drive, result should be left
414 // undefined. See comments in GetDriveAvailableSpaceCallback().
419 file_system
->GetAvailableSpace(
420 base::Bind(&FileManagerPrivateGetSizeStatsFunction::
421 GetDriveAvailableSpaceCallback
,
423 } else if (volume
->type() == file_manager::VOLUME_TYPE_MTP
) {
424 // Resolve storage_name.
425 storage_monitor::StorageMonitor
* storage_monitor
=
426 storage_monitor::StorageMonitor::GetInstance();
427 storage_monitor::StorageInfo info
;
428 storage_monitor
->GetStorageInfoForPath(volume
->mount_path(), &info
);
429 std::string storage_name
;
430 base::RemoveChars(info
.location(), kRootPath
, &storage_name
);
431 DCHECK(!storage_name
.empty());
433 // Get MTP StorageInfo.
434 device::MediaTransferProtocolManager
* manager
=
435 storage_monitor
->media_transfer_protocol_manager();
436 manager
->GetStorageInfoFromDevice(
437 storage_name
, base::Bind(&FileManagerPrivateGetSizeStatsFunction::
438 GetMtpAvailableSpaceCallback
,
441 uint64
* total_size
= new uint64(0);
442 uint64
* remaining_size
= new uint64(0);
443 BrowserThread::PostBlockingPoolTaskAndReply(
445 base::Bind(&GetSizeStatsOnBlockingPool
, volume
->mount_path().value(),
446 total_size
, remaining_size
),
448 &FileManagerPrivateGetSizeStatsFunction::GetSizeStatsCallback
, this,
449 base::Owned(total_size
), base::Owned(remaining_size
)));
454 void FileManagerPrivateGetSizeStatsFunction::GetDriveAvailableSpaceCallback(
455 drive::FileError error
,
458 if (error
== drive::FILE_ERROR_OK
) {
459 const uint64 bytes_total_unsigned
= bytes_total
;
460 // bytes_used can be larger than bytes_total (over quota).
461 const uint64 bytes_remaining_unsigned
=
462 std::max(bytes_total
- bytes_used
, int64(0));
463 GetSizeStatsCallback(&bytes_total_unsigned
,
464 &bytes_remaining_unsigned
);
466 // If stats couldn't be gotten for drive, result should be left undefined.
471 void FileManagerPrivateGetSizeStatsFunction::GetMtpAvailableSpaceCallback(
472 const MtpStorageInfo
& mtp_storage_info
,
475 // If stats couldn't be gotten from MTP volume, result should be left
476 // undefined same as we do for Drive.
481 const uint64 max_capacity
= mtp_storage_info
.max_capacity();
482 const uint64 free_space_in_bytes
= mtp_storage_info
.free_space_in_bytes();
483 GetSizeStatsCallback(&max_capacity
, &free_space_in_bytes
);
486 void FileManagerPrivateGetSizeStatsFunction::GetSizeStatsCallback(
487 const uint64
* total_size
,
488 const uint64
* remaining_size
) {
489 base::DictionaryValue
* sizes
= new base::DictionaryValue();
492 sizes
->SetDouble("totalSize", static_cast<double>(*total_size
));
493 sizes
->SetDouble("remainingSize", static_cast<double>(*remaining_size
));
498 bool FileManagerPrivateInternalValidatePathNameLengthFunction::RunAsync() {
499 using extensions::api::file_manager_private_internal::ValidatePathNameLength::
501 const scoped_ptr
<Params
> params(Params::Create(*args_
));
502 EXTENSION_FUNCTION_VALIDATE(params
);
504 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
505 file_manager::util::GetFileSystemContextForRenderFrameHost(
506 GetProfile(), render_frame_host());
508 const storage::FileSystemURL
file_system_url(
509 file_system_context
->CrackURL(GURL(params
->parent_url
)));
510 if (!chromeos::FileSystemBackend::CanHandleURL(file_system_url
))
513 // No explicit limit on the length of Drive file names.
514 if (file_system_url
.type() == storage::kFileSystemTypeDrive
) {
515 SetResult(new base::FundamentalValue(true));
520 base::PostTaskAndReplyWithResult(
521 BrowserThread::GetBlockingPool(), FROM_HERE
,
522 base::Bind(&GetFileNameMaxLengthOnBlockingPool
,
523 file_system_url
.path().AsUTF8Unsafe()),
524 base::Bind(&FileManagerPrivateInternalValidatePathNameLengthFunction::
525 OnFilePathLimitRetrieved
,
526 this, params
->name
.size()));
530 void FileManagerPrivateInternalValidatePathNameLengthFunction::
531 OnFilePathLimitRetrieved(size_t current_length
, size_t max_length
) {
532 SetResult(new base::FundamentalValue(current_length
<= max_length
));
536 bool FileManagerPrivateFormatVolumeFunction::RunAsync() {
537 using extensions::api::file_manager_private::FormatVolume::Params
;
538 const scoped_ptr
<Params
> params(Params::Create(*args_
));
539 EXTENSION_FUNCTION_VALIDATE(params
);
541 using file_manager::VolumeManager
;
542 using file_manager::Volume
;
543 VolumeManager
* const volume_manager
= VolumeManager::Get(GetProfile());
547 base::WeakPtr
<Volume
> volume
=
548 volume_manager
->FindVolumeById(params
->volume_id
);
552 DiskMountManager::GetInstance()->FormatMountedDevice(
553 volume
->mount_path().AsUTF8Unsafe());
558 // Obtains file size of URL.
559 void GetFileMetadataOnIOThread(
560 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
561 const FileSystemURL
& url
,
562 const storage::FileSystemOperation::GetMetadataCallback
& callback
) {
563 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
564 file_system_context
->operation_runner()->GetMetadata(
565 url
, base::Bind(&GetFileMetadataRespondOnUIThread
, callback
));
568 // Checks if the available space of the |path| is enough for required |bytes|.
569 bool CheckLocalDiskSpaceOnIOThread(const base::FilePath
& path
, int64 bytes
) {
570 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
571 return bytes
<= base::SysInfo::AmountOfFreeDiskSpace(path
) -
572 cryptohome::kMinFreeSpaceInBytes
;
575 bool FileManagerPrivateInternalStartCopyFunction::RunAsync() {
576 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
578 using extensions::api::file_manager_private_internal::StartCopy::Params
;
579 const scoped_ptr
<Params
> params(Params::Create(*args_
));
580 EXTENSION_FUNCTION_VALIDATE(params
);
582 if (params
->url
.empty() || params
->parent_url
.empty() ||
583 params
->new_name
.empty()) {
584 // Error code in format of DOMError.name.
585 SetError("EncodingError");
589 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
590 file_manager::util::GetFileSystemContextForRenderFrameHost(
591 GetProfile(), render_frame_host());
593 // |parent| may have a trailing slash if it is a root directory.
594 std::string destination_url_string
= params
->parent_url
;
595 if (destination_url_string
[destination_url_string
.size() - 1] != '/')
596 destination_url_string
+= '/';
597 destination_url_string
+= net::EscapePath(params
->new_name
);
599 source_url_
= file_system_context
->CrackURL(GURL(params
->url
));
601 file_system_context
->CrackURL(GURL(destination_url_string
));
603 if (!source_url_
.is_valid() || !destination_url_
.is_valid()) {
604 // Error code in format of DOMError.name.
605 SetError("EncodingError");
609 // Check if the destination directory is downloads. If so, secure available
610 // spece by freeing drive caches.
611 if (destination_url_
.filesystem_id() ==
612 file_manager::util::GetDownloadsMountPointName(GetProfile())) {
613 return BrowserThread::PostTask(
614 BrowserThread::IO
, FROM_HERE
,
615 base::Bind(&GetFileMetadataOnIOThread
, file_system_context
, source_url_
,
616 base::Bind(&FileManagerPrivateInternalStartCopyFunction::
617 RunAfterGetFileMetadata
,
621 return BrowserThread::PostTask(
622 BrowserThread::UI
, FROM_HERE
,
624 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace
,
628 void FileManagerPrivateInternalStartCopyFunction::RunAfterGetFileMetadata(
629 base::File::Error result
,
630 const base::File::Info
& file_info
) {
631 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
633 if (result
!= base::File::FILE_OK
) {
634 SetError("NotFoundError");
639 drive::FileSystemInterface
* const drive_file_system
=
640 drive::util::GetFileSystemByProfile(GetProfile());
641 if (drive_file_system
) {
642 drive_file_system
->FreeDiskSpaceIfNeededFor(
645 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace
,
648 const bool result
= BrowserThread::PostTaskAndReplyWithResult(
649 BrowserThread::IO
, FROM_HERE
,
651 &CheckLocalDiskSpaceOnIOThread
,
652 file_manager::util::GetDownloadsFolderForProfile(GetProfile()),
655 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace
,
662 void FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace(
664 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
667 SetError("QuotaExceededError");
672 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
673 file_manager::util::GetFileSystemContextForRenderFrameHost(
674 GetProfile(), render_frame_host());
675 const bool result
= BrowserThread::PostTaskAndReplyWithResult(
676 BrowserThread::IO
, FROM_HERE
,
677 base::Bind(&StartCopyOnIOThread
, GetProfile(), file_system_context
,
678 source_url_
, destination_url_
),
680 &FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy
,
686 void FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy(
688 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
690 SetResult(new base::FundamentalValue(operation_id
));
694 bool FileManagerPrivateCancelCopyFunction::RunAsync() {
695 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
697 using extensions::api::file_manager_private::CancelCopy::Params
;
698 const scoped_ptr
<Params
> params(Params::Create(*args_
));
699 EXTENSION_FUNCTION_VALIDATE(params
);
701 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
702 file_manager::util::GetFileSystemContextForRenderFrameHost(
703 GetProfile(), render_frame_host());
705 // We don't much take care about the result of cancellation.
706 BrowserThread::PostTask(
709 base::Bind(&CancelCopyOnIOThread
, file_system_context
, params
->copy_id
));
714 bool FileManagerPrivateInternalResolveIsolatedEntriesFunction::RunAsync() {
715 using extensions::api::file_manager_private_internal::ResolveIsolatedEntries::
717 const scoped_ptr
<Params
> params(Params::Create(*args_
));
718 EXTENSION_FUNCTION_VALIDATE(params
);
720 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
721 file_manager::util::GetFileSystemContextForRenderFrameHost(
722 GetProfile(), render_frame_host());
723 DCHECK(file_system_context
.get());
725 const storage::ExternalFileSystemBackend
* external_backend
=
726 file_system_context
->external_backend();
727 DCHECK(external_backend
);
729 file_manager::util::FileDefinitionList file_definition_list
;
730 for (size_t i
= 0; i
< params
->urls
.size(); ++i
) {
731 const FileSystemURL file_system_url
=
732 file_system_context
->CrackURL(GURL(params
->urls
[i
]));
733 DCHECK(external_backend
->CanHandleType(file_system_url
.type()));
734 FileDefinition file_definition
;
736 file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
737 GetProfile(), extension_
->id(), file_system_url
.path(),
738 &file_definition
.virtual_path
);
741 // The API only supports isolated files. It still works for directories,
742 // as the value is ignored for existing entries.
743 file_definition
.is_directory
= false;
744 file_definition_list
.push_back(file_definition
);
747 file_manager::util::ConvertFileDefinitionListToEntryDefinitionList(
750 file_definition_list
, // Safe, since copied internally.
752 &FileManagerPrivateInternalResolveIsolatedEntriesFunction::
753 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList
,
758 void FileManagerPrivateInternalResolveIsolatedEntriesFunction::
759 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList(scoped_ptr
<
760 file_manager::util::EntryDefinitionList
> entry_definition_list
) {
761 using extensions::api::file_manager_private_internal::EntryDescription
;
762 std::vector
<linked_ptr
<EntryDescription
> > entries
;
764 for (size_t i
= 0; i
< entry_definition_list
->size(); ++i
) {
765 if (entry_definition_list
->at(i
).error
!= base::File::FILE_OK
)
767 linked_ptr
<EntryDescription
> entry(new EntryDescription
);
768 entry
->file_system_name
= entry_definition_list
->at(i
).file_system_name
;
769 entry
->file_system_root
= entry_definition_list
->at(i
).file_system_root_url
;
770 entry
->file_full_path
=
771 "/" + entry_definition_list
->at(i
).full_path
.AsUTF8Unsafe();
772 entry
->file_is_directory
= entry_definition_list
->at(i
).is_directory
;
773 entries
.push_back(entry
);
776 results_
= extensions::api::file_manager_private_internal::
777 ResolveIsolatedEntries::Results::Create(entries
);
781 FileManagerPrivateInternalComputeChecksumFunction::
782 FileManagerPrivateInternalComputeChecksumFunction()
783 : digester_(new drive::util::FileStreamMd5Digester()) {
786 FileManagerPrivateInternalComputeChecksumFunction::
787 ~FileManagerPrivateInternalComputeChecksumFunction() {
790 bool FileManagerPrivateInternalComputeChecksumFunction::RunAsync() {
791 using extensions::api::file_manager_private_internal::ComputeChecksum::Params
;
792 using drive::util::FileStreamMd5Digester
;
793 const scoped_ptr
<Params
> params(Params::Create(*args_
));
794 EXTENSION_FUNCTION_VALIDATE(params
);
796 if (params
->url
.empty()) {
797 SetError("File URL must be provided");
801 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
802 file_manager::util::GetFileSystemContextForRenderFrameHost(
803 GetProfile(), render_frame_host());
805 FileSystemURL
file_system_url(
806 file_system_context
->CrackURL(GURL(params
->url
)));
807 if (!file_system_url
.is_valid()) {
808 SetError("File URL was invalid");
812 scoped_ptr
<storage::FileStreamReader
> reader
=
813 file_system_context
->CreateFileStreamReader(
814 file_system_url
, 0, storage::kMaximumLength
, base::Time());
816 FileStreamMd5Digester::ResultCallback result_callback
= base::Bind(
817 &ComputeChecksumRespondOnUIThread
,
818 base::Bind(&FileManagerPrivateInternalComputeChecksumFunction::Respond
,
820 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
821 base::Bind(&FileStreamMd5Digester::GetMd5Digest
,
822 base::Unretained(digester_
.get()),
823 base::Passed(&reader
), result_callback
));
828 void FileManagerPrivateInternalComputeChecksumFunction::Respond(
829 const std::string
& hash
) {
830 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
831 SetResult(new base::StringValue(hash
));
835 bool FileManagerPrivateSearchFilesByHashesFunction::RunAsync() {
836 using api::file_manager_private::SearchFilesByHashes::Params
;
837 const scoped_ptr
<Params
> params(Params::Create(*args_
));
838 EXTENSION_FUNCTION_VALIDATE(params
);
840 // TODO(hirono): Check the volume ID and fail the function for volumes other
843 drive::EventLogger
* const logger
=
844 file_manager::util::GetLogger(GetProfile());
846 logger
->Log(logging::LOG_INFO
,
847 "%s[%d] called. (volume id: %s, number of hashes: %zd)", name(),
848 request_id(), params
->volume_id
.c_str(),
849 params
->hash_list
.size());
851 set_log_on_completion(true);
853 drive::FileSystemInterface
* const file_system
=
854 drive::util::GetFileSystemByProfile(GetProfile());
856 // |file_system| is NULL if Drive is disabled.
860 std::set
<std::string
> hashes(params
->hash_list
.begin(),
861 params
->hash_list
.end());
862 file_system
->SearchByHashes(
865 &FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes
,
870 void FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes(
871 const std::set
<std::string
>& hashes
,
872 drive::FileError error
,
873 const std::vector
<drive::HashAndFilePath
>& search_results
) {
874 if (error
!= drive::FileError::FILE_ERROR_OK
) {
879 scoped_ptr
<base::DictionaryValue
> result(new base::DictionaryValue());
880 for (const auto& hash
: hashes
) {
881 result
->SetWithoutPathExpansion(hash
,
882 make_scoped_ptr(new base::ListValue()));
885 for (const auto& hashAndPath
: search_results
) {
886 DCHECK(result
->HasKey(hashAndPath
.hash
));
887 base::ListValue
* list
;
888 result
->GetListWithoutPathExpansion(hashAndPath
.hash
, &list
);
890 file_manager::util::ConvertDrivePathToFileSystemUrl(
891 GetProfile(), hashAndPath
.path
, extension_id()).spec());
893 SetResult(result
.release());
897 ExtensionFunction::ResponseAction
898 FileManagerPrivateIsUMAEnabledFunction::Run() {
899 return RespondNow(OneArgument(new base::FundamentalValue(
900 ChromeMetricsServiceAccessor::IsMetricsReportingEnabled())));
903 FileManagerPrivateInternalSetEntryTagFunction::
904 FileManagerPrivateInternalSetEntryTagFunction()
905 : chrome_details_(this) {}
907 ExtensionFunction::ResponseAction
908 FileManagerPrivateInternalSetEntryTagFunction::Run() {
909 using extensions::api::file_manager_private_internal::SetEntryTag::Params
;
910 const scoped_ptr
<Params
> params(Params::Create(*args_
));
911 EXTENSION_FUNCTION_VALIDATE(params
);
913 const base::FilePath local_path
= file_manager::util::GetLocalPathFromURL(
914 render_frame_host(), chrome_details_
.GetProfile(), GURL(params
->url
));
915 const base::FilePath drive_path
= drive::util::ExtractDrivePath(local_path
);
916 if (drive_path
.empty())
917 return RespondNow(Error("Only Drive files and directories are supported."));
919 drive::FileSystemInterface
* const file_system
=
920 drive::util::GetFileSystemByProfile(chrome_details_
.GetProfile());
921 // |file_system| is NULL if Drive is disabled.
923 return RespondNow(Error("Drive is disabled."));
925 google_apis::drive::Property::Visibility visibility
;
926 switch (params
->visibility
) {
927 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PRIVATE
:
928 visibility
= google_apis::drive::Property::VISIBILITY_PRIVATE
;
930 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PUBLIC
:
931 visibility
= google_apis::drive::Property::VISIBILITY_PUBLIC
;
935 return RespondNow(Error("Invalid visibility."));
939 file_system
->SetProperty(
940 drive_path
, visibility
, params
->key
, params
->value
,
941 base::Bind(&FileManagerPrivateInternalSetEntryTagFunction::
942 OnSetEntryPropertyCompleted
,
944 return RespondLater();
947 void FileManagerPrivateInternalSetEntryTagFunction::OnSetEntryPropertyCompleted(
948 drive::FileError result
) {
949 Respond(result
== drive::FILE_ERROR_OK
? NoArguments()
950 : Error("Failed to set a tag."));
953 } // namespace extensions