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 drive::FileSystemInterface
* const file_system
=
483 drive::util::GetFileSystemByProfile(GetProfile());
485 if (!is_download
|| !file_system
) {
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 file_system
->CalculateEvictableCacheSize(base::Bind(
493 &OnCalculateEvictableCacheSize
,
494 base::Bind(&FileManagerPrivateGetSizeStatsFunction::OnGetSizeStats
, this),
495 *total_size
, *remaining_size
));
498 void FileManagerPrivateGetSizeStatsFunction::OnGetDriveAvailableSpace(
499 drive::FileError error
,
502 if (error
== drive::FILE_ERROR_OK
) {
503 const uint64 bytes_total_unsigned
= bytes_total
;
504 // bytes_used can be larger than bytes_total (over quota).
505 const uint64 bytes_remaining_unsigned
=
506 std::max(bytes_total
- bytes_used
, int64(0));
507 OnGetSizeStats(&bytes_total_unsigned
, &bytes_remaining_unsigned
);
509 // If stats couldn't be gotten for drive, result should be left undefined.
514 void FileManagerPrivateGetSizeStatsFunction::OnGetMtpAvailableSpace(
515 const MtpStorageInfo
& mtp_storage_info
,
518 // If stats couldn't be gotten from MTP volume, result should be left
519 // undefined same as we do for Drive.
524 const uint64 max_capacity
= mtp_storage_info
.max_capacity();
525 const uint64 free_space_in_bytes
= mtp_storage_info
.free_space_in_bytes();
526 OnGetSizeStats(&max_capacity
, &free_space_in_bytes
);
529 void FileManagerPrivateGetSizeStatsFunction::OnGetSizeStats(
530 const uint64
* total_size
,
531 const uint64
* remaining_size
) {
532 base::DictionaryValue
* sizes
= new base::DictionaryValue();
535 sizes
->SetDouble("totalSize", static_cast<double>(*total_size
));
536 sizes
->SetDouble("remainingSize", static_cast<double>(*remaining_size
));
541 bool FileManagerPrivateInternalValidatePathNameLengthFunction::RunAsync() {
542 using extensions::api::file_manager_private_internal::ValidatePathNameLength::
544 const scoped_ptr
<Params
> params(Params::Create(*args_
));
545 EXTENSION_FUNCTION_VALIDATE(params
);
547 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
548 file_manager::util::GetFileSystemContextForRenderFrameHost(
549 GetProfile(), render_frame_host());
551 const storage::FileSystemURL
file_system_url(
552 file_system_context
->CrackURL(GURL(params
->parent_url
)));
553 if (!chromeos::FileSystemBackend::CanHandleURL(file_system_url
))
556 // No explicit limit on the length of Drive file names.
557 if (file_system_url
.type() == storage::kFileSystemTypeDrive
) {
558 SetResult(new base::FundamentalValue(true));
563 base::PostTaskAndReplyWithResult(
564 BrowserThread::GetBlockingPool(), FROM_HERE
,
565 base::Bind(&GetFileNameMaxLengthOnBlockingPool
,
566 file_system_url
.path().AsUTF8Unsafe()),
567 base::Bind(&FileManagerPrivateInternalValidatePathNameLengthFunction::
568 OnFilePathLimitRetrieved
,
569 this, params
->name
.size()));
573 void FileManagerPrivateInternalValidatePathNameLengthFunction::
574 OnFilePathLimitRetrieved(size_t current_length
, size_t max_length
) {
575 SetResult(new base::FundamentalValue(current_length
<= max_length
));
579 bool FileManagerPrivateFormatVolumeFunction::RunAsync() {
580 using extensions::api::file_manager_private::FormatVolume::Params
;
581 const scoped_ptr
<Params
> params(Params::Create(*args_
));
582 EXTENSION_FUNCTION_VALIDATE(params
);
584 using file_manager::VolumeManager
;
585 using file_manager::Volume
;
586 VolumeManager
* const volume_manager
= VolumeManager::Get(GetProfile());
590 base::WeakPtr
<Volume
> volume
=
591 volume_manager
->FindVolumeById(params
->volume_id
);
595 DiskMountManager::GetInstance()->FormatMountedDevice(
596 volume
->mount_path().AsUTF8Unsafe());
601 // Obtains file size of URL.
602 void GetFileMetadataOnIOThread(
603 scoped_refptr
<storage::FileSystemContext
> file_system_context
,
604 const FileSystemURL
& url
,
605 const storage::FileSystemOperation::GetMetadataCallback
& callback
) {
606 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
607 file_system_context
->operation_runner()->GetMetadata(
608 url
, base::Bind(&GetFileMetadataRespondOnUIThread
, callback
));
611 // Checks if the available space of the |path| is enough for required |bytes|.
612 bool CheckLocalDiskSpaceOnIOThread(const base::FilePath
& path
, int64 bytes
) {
613 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
614 return bytes
<= base::SysInfo::AmountOfFreeDiskSpace(path
) -
615 cryptohome::kMinFreeSpaceInBytes
;
618 bool FileManagerPrivateInternalStartCopyFunction::RunAsync() {
619 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
621 using extensions::api::file_manager_private_internal::StartCopy::Params
;
622 const scoped_ptr
<Params
> params(Params::Create(*args_
));
623 EXTENSION_FUNCTION_VALIDATE(params
);
625 if (params
->url
.empty() || params
->parent_url
.empty() ||
626 params
->new_name
.empty()) {
627 // Error code in format of DOMError.name.
628 SetError("EncodingError");
632 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
633 file_manager::util::GetFileSystemContextForRenderFrameHost(
634 GetProfile(), render_frame_host());
636 // |parent| may have a trailing slash if it is a root directory.
637 std::string destination_url_string
= params
->parent_url
;
638 if (destination_url_string
[destination_url_string
.size() - 1] != '/')
639 destination_url_string
+= '/';
640 destination_url_string
+= net::EscapePath(params
->new_name
);
642 source_url_
= file_system_context
->CrackURL(GURL(params
->url
));
644 file_system_context
->CrackURL(GURL(destination_url_string
));
646 if (!source_url_
.is_valid() || !destination_url_
.is_valid()) {
647 // Error code in format of DOMError.name.
648 SetError("EncodingError");
652 // Check if the destination directory is downloads. If so, secure available
653 // spece by freeing drive caches.
654 if (destination_url_
.filesystem_id() ==
655 file_manager::util::GetDownloadsMountPointName(GetProfile())) {
656 return BrowserThread::PostTask(
657 BrowserThread::IO
, FROM_HERE
,
658 base::Bind(&GetFileMetadataOnIOThread
, file_system_context
, source_url_
,
659 base::Bind(&FileManagerPrivateInternalStartCopyFunction::
660 RunAfterGetFileMetadata
,
664 return BrowserThread::PostTask(
665 BrowserThread::UI
, FROM_HERE
,
667 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace
,
671 void FileManagerPrivateInternalStartCopyFunction::RunAfterGetFileMetadata(
672 base::File::Error result
,
673 const base::File::Info
& file_info
) {
674 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
676 if (result
!= base::File::FILE_OK
) {
677 SetError("NotFoundError");
682 drive::FileSystemInterface
* const drive_file_system
=
683 drive::util::GetFileSystemByProfile(GetProfile());
684 if (drive_file_system
) {
685 drive_file_system
->FreeDiskSpaceIfNeededFor(
688 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace
,
691 const bool result
= BrowserThread::PostTaskAndReplyWithResult(
692 BrowserThread::IO
, FROM_HERE
,
694 &CheckLocalDiskSpaceOnIOThread
,
695 file_manager::util::GetDownloadsFolderForProfile(GetProfile()),
698 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace
,
705 void FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace(
707 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
710 SetError("QuotaExceededError");
715 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
716 file_manager::util::GetFileSystemContextForRenderFrameHost(
717 GetProfile(), render_frame_host());
718 const bool result
= BrowserThread::PostTaskAndReplyWithResult(
719 BrowserThread::IO
, FROM_HERE
,
720 base::Bind(&StartCopyOnIOThread
, GetProfile(), file_system_context
,
721 source_url_
, destination_url_
),
723 &FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy
,
729 void FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy(
731 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
733 SetResult(new base::FundamentalValue(operation_id
));
737 bool FileManagerPrivateCancelCopyFunction::RunAsync() {
738 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
740 using extensions::api::file_manager_private::CancelCopy::Params
;
741 const scoped_ptr
<Params
> params(Params::Create(*args_
));
742 EXTENSION_FUNCTION_VALIDATE(params
);
744 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
745 file_manager::util::GetFileSystemContextForRenderFrameHost(
746 GetProfile(), render_frame_host());
748 // We don't much take care about the result of cancellation.
749 BrowserThread::PostTask(
752 base::Bind(&CancelCopyOnIOThread
, file_system_context
, params
->copy_id
));
757 bool FileManagerPrivateInternalResolveIsolatedEntriesFunction::RunAsync() {
758 using extensions::api::file_manager_private_internal::ResolveIsolatedEntries::
760 const scoped_ptr
<Params
> params(Params::Create(*args_
));
761 EXTENSION_FUNCTION_VALIDATE(params
);
763 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
764 file_manager::util::GetFileSystemContextForRenderFrameHost(
765 GetProfile(), render_frame_host());
766 DCHECK(file_system_context
.get());
768 const storage::ExternalFileSystemBackend
* external_backend
=
769 file_system_context
->external_backend();
770 DCHECK(external_backend
);
772 file_manager::util::FileDefinitionList file_definition_list
;
773 for (size_t i
= 0; i
< params
->urls
.size(); ++i
) {
774 const FileSystemURL file_system_url
=
775 file_system_context
->CrackURL(GURL(params
->urls
[i
]));
776 DCHECK(external_backend
->CanHandleType(file_system_url
.type()));
777 FileDefinition file_definition
;
779 file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
780 GetProfile(), extension_
->id(), file_system_url
.path(),
781 &file_definition
.virtual_path
);
784 // The API only supports isolated files. It still works for directories,
785 // as the value is ignored for existing entries.
786 file_definition
.is_directory
= false;
787 file_definition_list
.push_back(file_definition
);
790 file_manager::util::ConvertFileDefinitionListToEntryDefinitionList(
793 file_definition_list
, // Safe, since copied internally.
795 &FileManagerPrivateInternalResolveIsolatedEntriesFunction::
796 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList
,
801 void FileManagerPrivateInternalResolveIsolatedEntriesFunction::
802 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList(scoped_ptr
<
803 file_manager::util::EntryDefinitionList
> entry_definition_list
) {
804 using extensions::api::file_manager_private_internal::EntryDescription
;
805 std::vector
<linked_ptr
<EntryDescription
> > entries
;
807 for (size_t i
= 0; i
< entry_definition_list
->size(); ++i
) {
808 if (entry_definition_list
->at(i
).error
!= base::File::FILE_OK
)
810 linked_ptr
<EntryDescription
> entry(new EntryDescription
);
811 entry
->file_system_name
= entry_definition_list
->at(i
).file_system_name
;
812 entry
->file_system_root
= entry_definition_list
->at(i
).file_system_root_url
;
813 entry
->file_full_path
=
814 "/" + entry_definition_list
->at(i
).full_path
.AsUTF8Unsafe();
815 entry
->file_is_directory
= entry_definition_list
->at(i
).is_directory
;
816 entries
.push_back(entry
);
819 results_
= extensions::api::file_manager_private_internal::
820 ResolveIsolatedEntries::Results::Create(entries
);
824 FileManagerPrivateInternalComputeChecksumFunction::
825 FileManagerPrivateInternalComputeChecksumFunction()
826 : digester_(new drive::util::FileStreamMd5Digester()) {
829 FileManagerPrivateInternalComputeChecksumFunction::
830 ~FileManagerPrivateInternalComputeChecksumFunction() {
833 bool FileManagerPrivateInternalComputeChecksumFunction::RunAsync() {
834 using extensions::api::file_manager_private_internal::ComputeChecksum::Params
;
835 using drive::util::FileStreamMd5Digester
;
836 const scoped_ptr
<Params
> params(Params::Create(*args_
));
837 EXTENSION_FUNCTION_VALIDATE(params
);
839 if (params
->url
.empty()) {
840 SetError("File URL must be provided");
844 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
845 file_manager::util::GetFileSystemContextForRenderFrameHost(
846 GetProfile(), render_frame_host());
848 FileSystemURL
file_system_url(
849 file_system_context
->CrackURL(GURL(params
->url
)));
850 if (!file_system_url
.is_valid()) {
851 SetError("File URL was invalid");
855 scoped_ptr
<storage::FileStreamReader
> reader
=
856 file_system_context
->CreateFileStreamReader(
857 file_system_url
, 0, storage::kMaximumLength
, base::Time());
859 FileStreamMd5Digester::ResultCallback result_callback
= base::Bind(
860 &ComputeChecksumRespondOnUIThread
,
861 base::Bind(&FileManagerPrivateInternalComputeChecksumFunction::Respond
,
863 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
864 base::Bind(&FileStreamMd5Digester::GetMd5Digest
,
865 base::Unretained(digester_
.get()),
866 base::Passed(&reader
), result_callback
));
871 void FileManagerPrivateInternalComputeChecksumFunction::Respond(
872 const std::string
& hash
) {
873 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
874 SetResult(new base::StringValue(hash
));
878 bool FileManagerPrivateSearchFilesByHashesFunction::RunAsync() {
879 using api::file_manager_private::SearchFilesByHashes::Params
;
880 const scoped_ptr
<Params
> params(Params::Create(*args_
));
881 EXTENSION_FUNCTION_VALIDATE(params
);
883 // TODO(hirono): Check the volume ID and fail the function for volumes other
886 drive::EventLogger
* const logger
=
887 file_manager::util::GetLogger(GetProfile());
889 logger
->Log(logging::LOG_INFO
,
890 "%s[%d] called. (volume id: %s, number of hashes: %zd)", name(),
891 request_id(), params
->volume_id
.c_str(),
892 params
->hash_list
.size());
894 set_log_on_completion(true);
896 drive::FileSystemInterface
* const file_system
=
897 drive::util::GetFileSystemByProfile(GetProfile());
899 // |file_system| is NULL if Drive is disabled.
903 std::set
<std::string
> hashes(params
->hash_list
.begin(),
904 params
->hash_list
.end());
905 file_system
->SearchByHashes(
908 &FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes
,
913 void FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes(
914 const std::set
<std::string
>& hashes
,
915 drive::FileError error
,
916 const std::vector
<drive::HashAndFilePath
>& search_results
) {
917 if (error
!= drive::FileError::FILE_ERROR_OK
) {
922 scoped_ptr
<base::DictionaryValue
> result(new base::DictionaryValue());
923 for (const auto& hash
: hashes
) {
924 result
->SetWithoutPathExpansion(hash
,
925 make_scoped_ptr(new base::ListValue()));
928 for (const auto& hashAndPath
: search_results
) {
929 DCHECK(result
->HasKey(hashAndPath
.hash
));
930 base::ListValue
* list
;
931 result
->GetListWithoutPathExpansion(hashAndPath
.hash
, &list
);
933 file_manager::util::ConvertDrivePathToFileSystemUrl(
934 GetProfile(), hashAndPath
.path
, extension_id()).spec());
936 SetResult(result
.release());
940 ExtensionFunction::ResponseAction
941 FileManagerPrivateIsUMAEnabledFunction::Run() {
942 return RespondNow(OneArgument(new base::FundamentalValue(
943 ChromeMetricsServiceAccessor::IsMetricsReportingEnabled())));
946 FileManagerPrivateInternalSetEntryTagFunction::
947 FileManagerPrivateInternalSetEntryTagFunction()
948 : chrome_details_(this) {}
950 ExtensionFunction::ResponseAction
951 FileManagerPrivateInternalSetEntryTagFunction::Run() {
952 using extensions::api::file_manager_private_internal::SetEntryTag::Params
;
953 const scoped_ptr
<Params
> params(Params::Create(*args_
));
954 EXTENSION_FUNCTION_VALIDATE(params
);
956 const base::FilePath local_path
= file_manager::util::GetLocalPathFromURL(
957 render_frame_host(), chrome_details_
.GetProfile(), GURL(params
->url
));
958 const base::FilePath drive_path
= drive::util::ExtractDrivePath(local_path
);
959 if (drive_path
.empty())
960 return RespondNow(Error("Only Drive files and directories are supported."));
962 drive::FileSystemInterface
* const file_system
=
963 drive::util::GetFileSystemByProfile(chrome_details_
.GetProfile());
964 // |file_system| is NULL if Drive is disabled.
966 return RespondNow(Error("Drive is disabled."));
968 google_apis::drive::Property::Visibility visibility
;
969 switch (params
->visibility
) {
970 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PRIVATE
:
971 visibility
= google_apis::drive::Property::VISIBILITY_PRIVATE
;
973 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PUBLIC
:
974 visibility
= google_apis::drive::Property::VISIBILITY_PUBLIC
;
978 return RespondNow(Error("Invalid visibility."));
982 file_system
->SetProperty(
983 drive_path
, visibility
, params
->key
, params
->value
,
984 base::Bind(&FileManagerPrivateInternalSetEntryTagFunction::
985 OnSetEntryPropertyCompleted
,
987 return RespondLater();
990 void FileManagerPrivateInternalSetEntryTagFunction::OnSetEntryPropertyCompleted(
991 drive::FileError result
) {
992 Respond(result
== drive::FILE_ERROR_OK
? NoArguments()
993 : Error("Failed to set a tag."));
996 } // namespace extensions