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_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/file_stream_md5_digester.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/event_logger.h"
37 #include "components/drive/file_system_interface.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 // Used for OnCalculateEvictableCacheSize.
81 typedef base::Callback
<void(const uint64_t* total_size
,
82 const uint64_t* remaining_space
)>
85 // Calculates the real remaining size of Download volume and pass it to
86 // GetSizeStatsCallback.
87 void OnCalculateEvictableCacheSize(const GetSizeStatsCallback
& callback
,
89 uint64_t remaining_size
,
90 uint64_t evictable_cache_size
) {
91 // For calculating real remaining size of Download volume
92 // - Adds evictable cache size since the space is available if they are
94 // - Subtracts minimum free space of cryptohome since the space is not
95 // available for file manager.
96 const uint64_t real_remaining_size
=
97 std::max(static_cast<int64_t>(remaining_size
+ evictable_cache_size
) -
98 cryptohome::kMinFreeSpaceInBytes
,
100 callback
.Run(&total_size
, &real_remaining_size
);
103 // Retrieves the maximum file name length of the file system of |path|.
104 // Returns 0 if it could not be queried.
105 size_t GetFileNameMaxLengthOnBlockingPool(const std::string
& path
) {
106 struct statvfs stat
= {};
107 if (HANDLE_EINTR(statvfs(path
.c_str(), &stat
)) != 0) {
108 // The filesystem seems not supporting statvfs(). Assume it to be a commonly
109 // used bound 255, and log the failure.
110 LOG(ERROR
) << "Cannot statvfs() the name length limit for: " << path
;
113 return stat
.f_namemax
;
116 // Returns EventRouter for the |profile_id| if available.
117 file_manager::EventRouter
* GetEventRouterByProfileId(void* profile_id
) {
118 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
120 // |profile_id| needs to be checked with ProfileManager::IsValidProfile
122 Profile
* profile
= reinterpret_cast<Profile
*>(profile_id
);
123 if (!g_browser_process
->profile_manager()->IsValidProfile(profile
))
126 return file_manager::EventRouterFactory::GetForProfile(profile
);
129 // Notifies the copy progress to extensions via event router.
130 void NotifyCopyProgress(
132 storage::FileSystemOperationRunner::OperationID operation_id
,
133 storage::FileSystemOperation::CopyProgressType type
,
134 const FileSystemURL
& source_url
,
135 const FileSystemURL
& destination_url
,
137 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
139 file_manager::EventRouter
* event_router
=
140 GetEventRouterByProfileId(profile_id
);
142 event_router
->OnCopyProgress(
144 source_url
.ToGURL(), destination_url
.ToGURL(), size
);
148 // Callback invoked periodically on progress update of Copy().
151 storage::FileSystemOperationRunner::OperationID
* operation_id
,
152 storage::FileSystemOperation::CopyProgressType type
,
153 const FileSystemURL
& source_url
,
154 const FileSystemURL
& destination_url
,
156 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
158 BrowserThread::PostTask(
159 BrowserThread::UI
, FROM_HERE
,
160 base::Bind(&NotifyCopyProgress
,
161 profile_id
, *operation_id
, type
,
162 source_url
, destination_url
, size
));
165 // Notifies the copy completion to extensions via event router.
166 void NotifyCopyCompletion(
168 storage::FileSystemOperationRunner::OperationID operation_id
,
169 const FileSystemURL
& source_url
,
170 const FileSystemURL
& destination_url
,
171 base::File::Error error
) {
172 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
174 file_manager::EventRouter
* event_router
=
175 GetEventRouterByProfileId(profile_id
);
177 event_router
->OnCopyCompleted(
179 source_url
.ToGURL(), destination_url
.ToGURL(), error
);
182 // Callback invoked upon completion of Copy() (regardless of succeeded or
184 void OnCopyCompleted(
186 storage::FileSystemOperationRunner::OperationID
* operation_id
,
187 const FileSystemURL
& source_url
,
188 const FileSystemURL
& destination_url
,
189 base::File::Error error
) {
190 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
192 BrowserThread::PostTask(
193 BrowserThread::UI
, FROM_HERE
,
194 base::Bind(&NotifyCopyCompletion
,
195 profile_id
, *operation_id
,
196 source_url
, destination_url
, error
));
199 // Starts the copy operation via FileSystemOperationRunner.
200 storage::FileSystemOperationRunner::OperationID
StartCopyOnIOThread(
202 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
203 const FileSystemURL
& source_url
,
204 const FileSystemURL
& destination_url
) {
205 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
207 // Note: |operation_id| is owned by the callback for
208 // FileSystemOperationRunner::Copy(). It is always called in the next message
209 // loop or later, so at least during this invocation it should alive.
211 // TODO(yawano): change ERROR_BEHAVIOR_ABORT to ERROR_BEHAVIOR_SKIP after
212 // error messages of individual operations become appear in the Files.app
214 storage::FileSystemOperationRunner::OperationID
* operation_id
=
215 new storage::FileSystemOperationRunner::OperationID
;
216 *operation_id
= file_system_context
->operation_runner()->Copy(
217 source_url
, destination_url
,
218 storage::FileSystemOperation::OPTION_PRESERVE_LAST_MODIFIED
,
219 storage::FileSystemOperation::ERROR_BEHAVIOR_ABORT
,
220 base::Bind(&OnCopyProgress
, profile_id
, base::Unretained(operation_id
)),
221 base::Bind(&OnCopyCompleted
, profile_id
, base::Owned(operation_id
),
222 source_url
, destination_url
));
223 return *operation_id
;
226 void OnCopyCancelled(base::File::Error error
) {
227 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
229 // We just ignore the status if the copy is actually cancelled or not,
230 // because failing cancellation means the operation is not running now.
231 DLOG_IF(WARNING
, error
!= base::File::FILE_OK
)
232 << "Failed to cancel copy: " << error
;
235 // Cancels the running copy operation identified by |operation_id|.
236 void CancelCopyOnIOThread(
237 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
238 storage::FileSystemOperationRunner::OperationID operation_id
) {
239 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
241 file_system_context
->operation_runner()->Cancel(
242 operation_id
, base::Bind(&OnCopyCancelled
));
245 // Converts a status code to a bool value and calls the |callback| with it.
246 void StatusCallbackToResponseCallback(
247 const base::Callback
<void(bool)>& callback
,
248 base::File::Error result
) {
249 callback
.Run(result
== base::File::FILE_OK
);
252 // Calls a response callback (on the UI thread) with a file content hash
253 // computed on the IO thread.
254 void ComputeChecksumRespondOnUIThread(
255 const base::Callback
<void(const std::string
&)>& callback
,
256 const std::string
& hash
) {
257 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
258 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
259 base::Bind(callback
, hash
));
262 // Calls a response callback on the UI thread.
263 void GetFileMetadataRespondOnUIThread(
264 const storage::FileSystemOperation::GetMetadataCallback
& callback
,
265 base::File::Error result
,
266 const base::File::Info
& file_info
) {
267 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
268 BrowserThread::PostTask(BrowserThread::UI
, FROM_HERE
,
269 base::Bind(callback
, result
, file_info
));
274 ExtensionFunction::ResponseAction
275 FileManagerPrivateEnableExternalFileSchemeFunction::Run() {
276 ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
277 render_frame_host()->GetProcess()->GetID(), content::kExternalFileScheme
);
278 return RespondNow(NoArguments());
281 FileManagerPrivateGrantAccessFunction::FileManagerPrivateGrantAccessFunction()
282 : chrome_details_(this) {
285 ExtensionFunction::ResponseAction
FileManagerPrivateGrantAccessFunction::Run() {
286 using extensions::api::file_manager_private::GrantAccess::Params
;
287 const scoped_ptr
<Params
> params(Params::Create(*args_
));
288 EXTENSION_FUNCTION_VALIDATE(params
);
290 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
291 file_manager::util::GetFileSystemContextForRenderFrameHost(
292 chrome_details_
.GetProfile(), render_frame_host());
294 storage::ExternalFileSystemBackend
* const backend
=
295 file_system_context
->external_backend();
298 const std::vector
<Profile
*>& profiles
=
299 g_browser_process
->profile_manager()->GetLoadedProfiles();
300 for (const auto& profile
: profiles
) {
301 if (profile
->IsOffTheRecord())
303 const GURL site
= util::GetSiteForExtensionId(extension_id(), profile
);
304 storage::FileSystemContext
* const context
=
305 content::BrowserContext::GetStoragePartitionForSite(profile
, site
)
306 ->GetFileSystemContext();
307 for (const auto& url
: params
->entry_urls
) {
308 const storage::FileSystemURL file_system_url
=
309 context
->CrackURL(GURL(url
));
310 // Grant permissions only to valid urls backed by the external file system
312 if (!file_system_url
.is_valid() ||
313 file_system_url
.mount_type() != storage::kFileSystemTypeExternal
) {
316 backend
->GrantFileAccessToExtension(extension_
->id(),
317 file_system_url
.virtual_path());
318 content::ChildProcessSecurityPolicy::GetInstance()
319 ->GrantCreateReadWriteFile(render_frame_host()->GetProcess()->GetID(),
320 file_system_url
.path());
323 return RespondNow(NoArguments());
326 void FileWatchFunctionBase::Respond(bool success
) {
327 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
329 SetResult(new base::FundamentalValue(success
));
330 SendResponse(success
);
333 bool FileWatchFunctionBase::RunAsync() {
334 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
336 if (!render_frame_host() || !render_frame_host()->GetProcess())
339 // First param is url of a file to watch.
341 if (!args_
->GetString(0, &url
) || url
.empty())
344 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
345 file_manager::util::GetFileSystemContextForRenderFrameHost(
346 GetProfile(), render_frame_host());
348 const FileSystemURL file_system_url
=
349 file_system_context
->CrackURL(GURL(url
));
350 if (file_system_url
.path().empty()) {
355 PerformFileWatchOperation(file_system_context
, file_system_url
,
360 void FileManagerPrivateInternalAddFileWatchFunction::PerformFileWatchOperation(
361 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
362 const storage::FileSystemURL
& file_system_url
,
363 const std::string
& extension_id
) {
364 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
366 file_manager::EventRouter
* const event_router
=
367 file_manager::EventRouterFactory::GetForProfile(GetProfile());
369 storage::WatcherManager
* const watcher_manager
=
370 file_system_context
->GetWatcherManager(file_system_url
.type());
371 if (watcher_manager
) {
372 watcher_manager
->AddWatcher(
373 file_system_url
, false /* recursive */,
375 &StatusCallbackToResponseCallback
,
376 base::Bind(&FileManagerPrivateInternalAddFileWatchFunction::Respond
,
378 base::Bind(&file_manager::EventRouter::OnWatcherManagerNotification
,
379 event_router
->GetWeakPtr(), file_system_url
, extension_id
));
383 // Obsolete. Fallback code if storage::WatcherManager is not implemented.
384 event_router
->AddFileWatch(
385 file_system_url
.path(), file_system_url
.virtual_path(), extension_id
,
386 base::Bind(&FileManagerPrivateInternalAddFileWatchFunction::Respond
,
390 void FileManagerPrivateInternalRemoveFileWatchFunction::
391 PerformFileWatchOperation(
392 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
393 const storage::FileSystemURL
& file_system_url
,
394 const std::string
& extension_id
) {
395 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
397 file_manager::EventRouter
* const event_router
=
398 file_manager::EventRouterFactory::GetForProfile(GetProfile());
400 storage::WatcherManager
* const watcher_manager
=
401 file_system_context
->GetWatcherManager(file_system_url
.type());
402 if (watcher_manager
) {
403 watcher_manager
->RemoveWatcher(
404 file_system_url
, false /* recursive */,
405 base::Bind(&StatusCallbackToResponseCallback
,
406 base::Bind(&FileWatchFunctionBase::Respond
, this)));
410 // Obsolete. Fallback code if storage::WatcherManager is not implemented.
411 event_router
->RemoveFileWatch(file_system_url
.path(), extension_id
);
415 bool FileManagerPrivateGetSizeStatsFunction::RunAsync() {
416 using extensions::api::file_manager_private::GetSizeStats::Params
;
417 const scoped_ptr
<Params
> params(Params::Create(*args_
));
418 EXTENSION_FUNCTION_VALIDATE(params
);
420 using file_manager::VolumeManager
;
421 using file_manager::Volume
;
422 VolumeManager
* const volume_manager
= VolumeManager::Get(GetProfile());
426 base::WeakPtr
<Volume
> volume
=
427 volume_manager
->FindVolumeById(params
->volume_id
);
431 if (volume
->type() == file_manager::VOLUME_TYPE_GOOGLE_DRIVE
) {
432 drive::FileSystemInterface
* file_system
=
433 drive::util::GetFileSystemByProfile(GetProfile());
435 // |file_system| is NULL if Drive is disabled.
436 // If stats couldn't be gotten for drive, result should be left
437 // undefined. See comments in GetDriveAvailableSpaceCallback().
442 file_system
->GetAvailableSpace(base::Bind(
443 &FileManagerPrivateGetSizeStatsFunction::OnGetDriveAvailableSpace
,
445 } else if (volume
->type() == file_manager::VOLUME_TYPE_MTP
) {
446 // Resolve storage_name.
447 storage_monitor::StorageMonitor
* storage_monitor
=
448 storage_monitor::StorageMonitor::GetInstance();
449 storage_monitor::StorageInfo info
;
450 storage_monitor
->GetStorageInfoForPath(volume
->mount_path(), &info
);
451 std::string storage_name
;
452 base::RemoveChars(info
.location(), kRootPath
, &storage_name
);
453 DCHECK(!storage_name
.empty());
455 // Get MTP StorageInfo.
456 device::MediaTransferProtocolManager
* manager
=
457 storage_monitor
->media_transfer_protocol_manager();
458 manager
->GetStorageInfoFromDevice(
461 &FileManagerPrivateGetSizeStatsFunction::OnGetMtpAvailableSpace
,
464 uint64_t* total_size
= new uint64_t(0);
465 uint64_t* remaining_size
= new uint64_t(0);
466 BrowserThread::PostBlockingPoolTaskAndReply(
468 base::Bind(&GetSizeStatsOnBlockingPool
, volume
->mount_path().value(),
469 total_size
, remaining_size
),
471 &FileManagerPrivateGetSizeStatsFunction::OnGetLocalSpace
, this,
472 base::Owned(total_size
), base::Owned(remaining_size
),
473 volume
->type() == file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY
));
478 void FileManagerPrivateGetSizeStatsFunction::OnGetLocalSpace(
479 uint64_t* total_size
,
480 uint64_t* remaining_size
,
482 Profile
* const profile
= GetProfile();
484 if (!is_download
|| profile
->IsGuestSession() ||
485 !drive::util::IsDriveEnabledForProfile(profile
)) {
486 OnGetSizeStats(total_size
, remaining_size
);
490 // We need to add evictable cache size to the remaining size of Downloads
491 // volume if drive is available.
492 drive::FileSystemInterface
* file_system
=
493 drive::util::GetFileSystemByProfile(profile
);
495 file_system
->CalculateEvictableCacheSize(base::Bind(
496 &OnCalculateEvictableCacheSize
,
497 base::Bind(&FileManagerPrivateGetSizeStatsFunction::OnGetSizeStats
, this),
498 *total_size
, *remaining_size
));
501 void FileManagerPrivateGetSizeStatsFunction::OnGetDriveAvailableSpace(
502 drive::FileError error
,
505 if (error
== drive::FILE_ERROR_OK
) {
506 const uint64 bytes_total_unsigned
= bytes_total
;
507 // bytes_used can be larger than bytes_total (over quota).
508 const uint64 bytes_remaining_unsigned
=
509 std::max(bytes_total
- bytes_used
, int64(0));
510 OnGetSizeStats(&bytes_total_unsigned
, &bytes_remaining_unsigned
);
512 // If stats couldn't be gotten for drive, result should be left undefined.
517 void FileManagerPrivateGetSizeStatsFunction::OnGetMtpAvailableSpace(
518 const MtpStorageInfo
& mtp_storage_info
,
521 // If stats couldn't be gotten from MTP volume, result should be left
522 // undefined same as we do for Drive.
527 const uint64 max_capacity
= mtp_storage_info
.max_capacity();
528 const uint64 free_space_in_bytes
= mtp_storage_info
.free_space_in_bytes();
529 OnGetSizeStats(&max_capacity
, &free_space_in_bytes
);
532 void FileManagerPrivateGetSizeStatsFunction::OnGetSizeStats(
533 const uint64
* total_size
,
534 const uint64
* remaining_size
) {
535 base::DictionaryValue
* sizes
= new base::DictionaryValue();
538 sizes
->SetDouble("totalSize", static_cast<double>(*total_size
));
539 sizes
->SetDouble("remainingSize", static_cast<double>(*remaining_size
));
544 bool FileManagerPrivateInternalValidatePathNameLengthFunction::RunAsync() {
545 using extensions::api::file_manager_private_internal::ValidatePathNameLength::
547 const scoped_ptr
<Params
> params(Params::Create(*args_
));
548 EXTENSION_FUNCTION_VALIDATE(params
);
550 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
551 file_manager::util::GetFileSystemContextForRenderFrameHost(
552 GetProfile(), render_frame_host());
554 const storage::FileSystemURL
file_system_url(
555 file_system_context
->CrackURL(GURL(params
->parent_url
)));
556 if (!chromeos::FileSystemBackend::CanHandleURL(file_system_url
))
559 // No explicit limit on the length of Drive file names.
560 if (file_system_url
.type() == storage::kFileSystemTypeDrive
) {
561 SetResult(new base::FundamentalValue(true));
566 base::PostTaskAndReplyWithResult(
567 BrowserThread::GetBlockingPool(), FROM_HERE
,
568 base::Bind(&GetFileNameMaxLengthOnBlockingPool
,
569 file_system_url
.path().AsUTF8Unsafe()),
570 base::Bind(&FileManagerPrivateInternalValidatePathNameLengthFunction::
571 OnFilePathLimitRetrieved
,
572 this, params
->name
.size()));
576 void FileManagerPrivateInternalValidatePathNameLengthFunction::
577 OnFilePathLimitRetrieved(size_t current_length
, size_t max_length
) {
578 SetResult(new base::FundamentalValue(current_length
<= max_length
));
582 bool FileManagerPrivateFormatVolumeFunction::RunAsync() {
583 using extensions::api::file_manager_private::FormatVolume::Params
;
584 const scoped_ptr
<Params
> params(Params::Create(*args_
));
585 EXTENSION_FUNCTION_VALIDATE(params
);
587 using file_manager::VolumeManager
;
588 using file_manager::Volume
;
589 VolumeManager
* const volume_manager
= VolumeManager::Get(GetProfile());
593 base::WeakPtr
<Volume
> volume
=
594 volume_manager
->FindVolumeById(params
->volume_id
);
598 DiskMountManager::GetInstance()->FormatMountedDevice(
599 volume
->mount_path().AsUTF8Unsafe());
604 // Obtains file size of URL.
605 void GetFileMetadataOnIOThread(
606 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
607 const FileSystemURL
& url
,
608 const storage::FileSystemOperation::GetMetadataCallback
& callback
) {
609 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
610 file_system_context
->operation_runner()->GetMetadata(
611 url
, base::Bind(&GetFileMetadataRespondOnUIThread
, callback
));
614 // Checks if the available space of the |path| is enough for required |bytes|.
615 bool CheckLocalDiskSpaceOnIOThread(const base::FilePath
& path
, int64 bytes
) {
616 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
617 return bytes
<= base::SysInfo::AmountOfFreeDiskSpace(path
) -
618 cryptohome::kMinFreeSpaceInBytes
;
621 bool FileManagerPrivateInternalStartCopyFunction::RunAsync() {
622 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
624 using extensions::api::file_manager_private_internal::StartCopy::Params
;
625 const scoped_ptr
<Params
> params(Params::Create(*args_
));
626 EXTENSION_FUNCTION_VALIDATE(params
);
628 if (params
->url
.empty() || params
->parent_url
.empty() ||
629 params
->new_name
.empty()) {
630 // Error code in format of DOMError.name.
631 SetError("EncodingError");
635 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
636 file_manager::util::GetFileSystemContextForRenderFrameHost(
637 GetProfile(), render_frame_host());
639 // |parent| may have a trailing slash if it is a root directory.
640 std::string destination_url_string
= params
->parent_url
;
641 if (destination_url_string
[destination_url_string
.size() - 1] != '/')
642 destination_url_string
+= '/';
643 destination_url_string
+= net::EscapePath(params
->new_name
);
645 source_url_
= file_system_context
->CrackURL(GURL(params
->url
));
647 file_system_context
->CrackURL(GURL(destination_url_string
));
649 if (!source_url_
.is_valid() || !destination_url_
.is_valid()) {
650 // Error code in format of DOMError.name.
651 SetError("EncodingError");
655 // Check if the destination directory is downloads. If so, secure available
656 // spece by freeing drive caches.
657 if (destination_url_
.filesystem_id() ==
658 file_manager::util::GetDownloadsMountPointName(GetProfile())) {
659 return BrowserThread::PostTask(
660 BrowserThread::IO
, FROM_HERE
,
661 base::Bind(&GetFileMetadataOnIOThread
, file_system_context
, source_url_
,
662 base::Bind(&FileManagerPrivateInternalStartCopyFunction::
663 RunAfterGetFileMetadata
,
667 return BrowserThread::PostTask(
668 BrowserThread::UI
, FROM_HERE
,
670 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace
,
674 void FileManagerPrivateInternalStartCopyFunction::RunAfterGetFileMetadata(
675 base::File::Error result
,
676 const base::File::Info
& file_info
) {
677 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
679 if (result
!= base::File::FILE_OK
) {
680 SetError("NotFoundError");
685 drive::FileSystemInterface
* const drive_file_system
=
686 drive::util::GetFileSystemByProfile(GetProfile());
687 if (drive_file_system
) {
688 drive_file_system
->FreeDiskSpaceIfNeededFor(
691 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace
,
694 const bool result
= BrowserThread::PostTaskAndReplyWithResult(
695 BrowserThread::IO
, FROM_HERE
,
697 &CheckLocalDiskSpaceOnIOThread
,
698 file_manager::util::GetDownloadsFolderForProfile(GetProfile()),
701 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace
,
708 void FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace(
710 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
713 SetError("QuotaExceededError");
718 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
719 file_manager::util::GetFileSystemContextForRenderFrameHost(
720 GetProfile(), render_frame_host());
721 const bool result
= BrowserThread::PostTaskAndReplyWithResult(
722 BrowserThread::IO
, FROM_HERE
,
723 base::Bind(&StartCopyOnIOThread
, GetProfile(), file_system_context
,
724 source_url_
, destination_url_
),
726 &FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy
,
732 void FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy(
734 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
736 SetResult(new base::FundamentalValue(operation_id
));
740 bool FileManagerPrivateCancelCopyFunction::RunAsync() {
741 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
743 using extensions::api::file_manager_private::CancelCopy::Params
;
744 const scoped_ptr
<Params
> params(Params::Create(*args_
));
745 EXTENSION_FUNCTION_VALIDATE(params
);
747 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
748 file_manager::util::GetFileSystemContextForRenderFrameHost(
749 GetProfile(), render_frame_host());
751 // We don't much take care about the result of cancellation.
752 BrowserThread::PostTask(
755 base::Bind(&CancelCopyOnIOThread
, file_system_context
, params
->copy_id
));
760 bool FileManagerPrivateInternalResolveIsolatedEntriesFunction::RunAsync() {
761 using extensions::api::file_manager_private_internal::ResolveIsolatedEntries::
763 const scoped_ptr
<Params
> params(Params::Create(*args_
));
764 EXTENSION_FUNCTION_VALIDATE(params
);
766 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
767 file_manager::util::GetFileSystemContextForRenderFrameHost(
768 GetProfile(), render_frame_host());
769 DCHECK(file_system_context
.get());
771 const storage::ExternalFileSystemBackend
* external_backend
=
772 file_system_context
->external_backend();
773 DCHECK(external_backend
);
775 file_manager::util::FileDefinitionList file_definition_list
;
776 for (size_t i
= 0; i
< params
->urls
.size(); ++i
) {
777 const FileSystemURL file_system_url
=
778 file_system_context
->CrackURL(GURL(params
->urls
[i
]));
779 DCHECK(external_backend
->CanHandleType(file_system_url
.type()));
780 FileDefinition file_definition
;
782 file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
783 GetProfile(), extension_
->id(), file_system_url
.path(),
784 &file_definition
.virtual_path
);
787 // The API only supports isolated files. It still works for directories,
788 // as the value is ignored for existing entries.
789 file_definition
.is_directory
= false;
790 file_definition_list
.push_back(file_definition
);
793 file_manager::util::ConvertFileDefinitionListToEntryDefinitionList(
796 file_definition_list
, // Safe, since copied internally.
798 &FileManagerPrivateInternalResolveIsolatedEntriesFunction::
799 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList
,
804 void FileManagerPrivateInternalResolveIsolatedEntriesFunction::
805 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList(scoped_ptr
<
806 file_manager::util::EntryDefinitionList
> entry_definition_list
) {
807 using extensions::api::file_manager_private_internal::EntryDescription
;
808 std::vector
<linked_ptr
<EntryDescription
> > entries
;
810 for (size_t i
= 0; i
< entry_definition_list
->size(); ++i
) {
811 if (entry_definition_list
->at(i
).error
!= base::File::FILE_OK
)
813 linked_ptr
<EntryDescription
> entry(new EntryDescription
);
814 entry
->file_system_name
= entry_definition_list
->at(i
).file_system_name
;
815 entry
->file_system_root
= entry_definition_list
->at(i
).file_system_root_url
;
816 entry
->file_full_path
=
817 "/" + entry_definition_list
->at(i
).full_path
.AsUTF8Unsafe();
818 entry
->file_is_directory
= entry_definition_list
->at(i
).is_directory
;
819 entries
.push_back(entry
);
822 results_
= extensions::api::file_manager_private_internal::
823 ResolveIsolatedEntries::Results::Create(entries
);
827 FileManagerPrivateInternalComputeChecksumFunction::
828 FileManagerPrivateInternalComputeChecksumFunction()
829 : digester_(new drive::util::FileStreamMd5Digester()) {
832 FileManagerPrivateInternalComputeChecksumFunction::
833 ~FileManagerPrivateInternalComputeChecksumFunction() {
836 bool FileManagerPrivateInternalComputeChecksumFunction::RunAsync() {
837 using extensions::api::file_manager_private_internal::ComputeChecksum::Params
;
838 using drive::util::FileStreamMd5Digester
;
839 const scoped_ptr
<Params
> params(Params::Create(*args_
));
840 EXTENSION_FUNCTION_VALIDATE(params
);
842 if (params
->url
.empty()) {
843 SetError("File URL must be provided");
847 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
848 file_manager::util::GetFileSystemContextForRenderFrameHost(
849 GetProfile(), render_frame_host());
851 FileSystemURL
file_system_url(
852 file_system_context
->CrackURL(GURL(params
->url
)));
853 if (!file_system_url
.is_valid()) {
854 SetError("File URL was invalid");
858 scoped_ptr
<storage::FileStreamReader
> reader
=
859 file_system_context
->CreateFileStreamReader(
860 file_system_url
, 0, storage::kMaximumLength
, base::Time());
862 FileStreamMd5Digester::ResultCallback result_callback
= base::Bind(
863 &ComputeChecksumRespondOnUIThread
,
864 base::Bind(&FileManagerPrivateInternalComputeChecksumFunction::Respond
,
866 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
867 base::Bind(&FileStreamMd5Digester::GetMd5Digest
,
868 base::Unretained(digester_
.get()),
869 base::Passed(&reader
), result_callback
));
874 void FileManagerPrivateInternalComputeChecksumFunction::Respond(
875 const std::string
& hash
) {
876 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
877 SetResult(new base::StringValue(hash
));
881 bool FileManagerPrivateSearchFilesByHashesFunction::RunAsync() {
882 using api::file_manager_private::SearchFilesByHashes::Params
;
883 const scoped_ptr
<Params
> params(Params::Create(*args_
));
884 EXTENSION_FUNCTION_VALIDATE(params
);
886 // TODO(hirono): Check the volume ID and fail the function for volumes other
889 drive::EventLogger
* const logger
=
890 file_manager::util::GetLogger(GetProfile());
892 logger
->Log(logging::LOG_INFO
,
893 "%s[%d] called. (volume id: %s, number of hashes: %zd)", name(),
894 request_id(), params
->volume_id
.c_str(),
895 params
->hash_list
.size());
897 set_log_on_completion(true);
899 drive::FileSystemInterface
* const file_system
=
900 drive::util::GetFileSystemByProfile(GetProfile());
902 // |file_system| is NULL if Drive is disabled.
906 std::set
<std::string
> hashes(params
->hash_list
.begin(),
907 params
->hash_list
.end());
908 file_system
->SearchByHashes(
911 &FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes
,
916 void FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes(
917 const std::set
<std::string
>& hashes
,
918 drive::FileError error
,
919 const std::vector
<drive::HashAndFilePath
>& search_results
) {
920 if (error
!= drive::FileError::FILE_ERROR_OK
) {
925 scoped_ptr
<base::DictionaryValue
> result(new base::DictionaryValue());
926 for (const auto& hash
: hashes
) {
927 result
->SetWithoutPathExpansion(hash
,
928 make_scoped_ptr(new base::ListValue()));
931 for (const auto& hashAndPath
: search_results
) {
932 DCHECK(result
->HasKey(hashAndPath
.hash
));
933 base::ListValue
* list
;
934 result
->GetListWithoutPathExpansion(hashAndPath
.hash
, &list
);
936 file_manager::util::ConvertDrivePathToFileSystemUrl(
937 GetProfile(), hashAndPath
.path
, extension_id()).spec());
939 SetResult(result
.release());
943 ExtensionFunction::ResponseAction
944 FileManagerPrivateIsUMAEnabledFunction::Run() {
945 return RespondNow(OneArgument(new base::FundamentalValue(
946 ChromeMetricsServiceAccessor::IsMetricsReportingEnabled())));
949 FileManagerPrivateInternalSetEntryTagFunction::
950 FileManagerPrivateInternalSetEntryTagFunction()
951 : chrome_details_(this) {}
953 ExtensionFunction::ResponseAction
954 FileManagerPrivateInternalSetEntryTagFunction::Run() {
955 using extensions::api::file_manager_private_internal::SetEntryTag::Params
;
956 const scoped_ptr
<Params
> params(Params::Create(*args_
));
957 EXTENSION_FUNCTION_VALIDATE(params
);
959 const base::FilePath local_path
= file_manager::util::GetLocalPathFromURL(
960 render_frame_host(), chrome_details_
.GetProfile(), GURL(params
->url
));
961 const base::FilePath drive_path
= drive::util::ExtractDrivePath(local_path
);
962 if (drive_path
.empty())
963 return RespondNow(Error("Only Drive files and directories are supported."));
965 drive::FileSystemInterface
* const file_system
=
966 drive::util::GetFileSystemByProfile(chrome_details_
.GetProfile());
967 // |file_system| is NULL if Drive is disabled.
969 return RespondNow(Error("Drive is disabled."));
971 google_apis::drive::Property::Visibility visibility
;
972 switch (params
->visibility
) {
973 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PRIVATE
:
974 visibility
= google_apis::drive::Property::VISIBILITY_PRIVATE
;
976 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PUBLIC
:
977 visibility
= google_apis::drive::Property::VISIBILITY_PUBLIC
;
981 return RespondNow(Error("Invalid visibility."));
985 file_system
->SetProperty(
986 drive_path
, visibility
, params
->key
, params
->value
,
987 base::Bind(&FileManagerPrivateInternalSetEntryTagFunction::
988 OnSetEntryPropertyCompleted
,
990 return RespondLater();
993 void FileManagerPrivateInternalSetEntryTagFunction::OnSetEntryPropertyCompleted(
994 drive::FileError result
) {
995 Respond(result
== drive::FILE_ERROR_OK
? NoArguments()
996 : Error("Failed to set a tag."));
999 } // namespace extensions