Files.app: do not try to get evictable drive cache size if not available
[chromium-blink-merge.git] / chrome / browser / chromeos / extensions / file_manager / private_api_file_system.cc
blob3cc0ba3f00513173fea06247bc48593a82cd5256
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h"
7 #include <sys/statvfs.h>
8 #include <set>
10 #include "base/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 {
65 namespace {
67 const char kRootPath[] = "/";
69 // Retrieves total and remaining available size on |mount_path|.
70 void GetSizeStatsOnBlockingPool(const std::string& mount_path,
71 uint64* total_size,
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)>
83 GetSizeStatsCallback;
85 // Calculates the real remaining size of Download volume and pass it to
86 // GetSizeStatsCallback.
87 void OnCalculateEvictableCacheSize(const GetSizeStatsCallback& callback,
88 uint64_t total_size,
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
93 // evicted.
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,
99 int64_t(0));
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;
111 return 255;
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
121 // before using it.
122 Profile* profile = reinterpret_cast<Profile*>(profile_id);
123 if (!g_browser_process->profile_manager()->IsValidProfile(profile))
124 return NULL;
126 return file_manager::EventRouterFactory::GetForProfile(profile);
129 // Notifies the copy progress to extensions via event router.
130 void NotifyCopyProgress(
131 void* profile_id,
132 storage::FileSystemOperationRunner::OperationID operation_id,
133 storage::FileSystemOperation::CopyProgressType type,
134 const FileSystemURL& source_url,
135 const FileSystemURL& destination_url,
136 int64 size) {
137 DCHECK_CURRENTLY_ON(BrowserThread::UI);
139 file_manager::EventRouter* event_router =
140 GetEventRouterByProfileId(profile_id);
141 if (event_router) {
142 event_router->OnCopyProgress(
143 operation_id, type,
144 source_url.ToGURL(), destination_url.ToGURL(), size);
148 // Callback invoked periodically on progress update of Copy().
149 void OnCopyProgress(
150 void* profile_id,
151 storage::FileSystemOperationRunner::OperationID* operation_id,
152 storage::FileSystemOperation::CopyProgressType type,
153 const FileSystemURL& source_url,
154 const FileSystemURL& destination_url,
155 int64 size) {
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(
167 void* profile_id,
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);
176 if (event_router)
177 event_router->OnCopyCompleted(
178 operation_id,
179 source_url.ToGURL(), destination_url.ToGURL(), error);
182 // Callback invoked upon completion of Copy() (regardless of succeeded or
183 // failed).
184 void OnCopyCompleted(
185 void* profile_id,
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(
201 void* profile_id,
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
213 // UI.
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));
272 } // namespace
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();
296 DCHECK(backend);
298 const std::vector<Profile*>& profiles =
299 g_browser_process->profile_manager()->GetLoadedProfiles();
300 for (const auto& profile : profiles) {
301 if (profile->IsOffTheRecord())
302 continue;
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
311 // backend.
312 if (!file_system_url.is_valid() ||
313 file_system_url.mount_type() != storage::kFileSystemTypeExternal) {
314 continue;
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())
337 return false;
339 // First param is url of a file to watch.
340 std::string url;
341 if (!args_->GetString(0, &url) || url.empty())
342 return false;
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()) {
351 Respond(false);
352 return true;
355 PerformFileWatchOperation(file_system_context, file_system_url,
356 extension_id());
357 return true;
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 */,
374 base::Bind(
375 &StatusCallbackToResponseCallback,
376 base::Bind(&FileManagerPrivateInternalAddFileWatchFunction::Respond,
377 this)),
378 base::Bind(&file_manager::EventRouter::OnWatcherManagerNotification,
379 event_router->GetWeakPtr(), file_system_url, extension_id));
380 return;
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,
387 this));
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)));
407 return;
410 // Obsolete. Fallback code if storage::WatcherManager is not implemented.
411 event_router->RemoveFileWatch(file_system_url.path(), extension_id);
412 Respond(true);
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());
423 if (!volume_manager)
424 return false;
426 base::WeakPtr<Volume> volume =
427 volume_manager->FindVolumeById(params->volume_id);
428 if (!volume.get())
429 return false;
431 if (volume->type() == file_manager::VOLUME_TYPE_GOOGLE_DRIVE) {
432 drive::FileSystemInterface* file_system =
433 drive::util::GetFileSystemByProfile(GetProfile());
434 if (!file_system) {
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().
438 SendResponse(true);
439 return true;
442 file_system->GetAvailableSpace(base::Bind(
443 &FileManagerPrivateGetSizeStatsFunction::OnGetDriveAvailableSpace,
444 this));
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(
459 storage_name,
460 base::Bind(
461 &FileManagerPrivateGetSizeStatsFunction::OnGetMtpAvailableSpace,
462 this));
463 } else {
464 uint64_t* total_size = new uint64_t(0);
465 uint64_t* remaining_size = new uint64_t(0);
466 BrowserThread::PostBlockingPoolTaskAndReply(
467 FROM_HERE,
468 base::Bind(&GetSizeStatsOnBlockingPool, volume->mount_path().value(),
469 total_size, remaining_size),
470 base::Bind(
471 &FileManagerPrivateGetSizeStatsFunction::OnGetLocalSpace, this,
472 base::Owned(total_size), base::Owned(remaining_size),
473 volume->type() == file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY));
475 return true;
478 void FileManagerPrivateGetSizeStatsFunction::OnGetLocalSpace(
479 uint64_t* total_size,
480 uint64_t* remaining_size,
481 bool is_download) {
482 Profile* const profile = GetProfile();
484 if (!is_download || profile->IsGuestSession() ||
485 !drive::util::IsDriveEnabledForProfile(profile)) {
486 OnGetSizeStats(total_size, remaining_size);
487 return;
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,
503 int64 bytes_total,
504 int64 bytes_used) {
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);
511 } else {
512 // If stats couldn't be gotten for drive, result should be left undefined.
513 SendResponse(true);
517 void FileManagerPrivateGetSizeStatsFunction::OnGetMtpAvailableSpace(
518 const MtpStorageInfo& mtp_storage_info,
519 const bool error) {
520 if (error) {
521 // If stats couldn't be gotten from MTP volume, result should be left
522 // undefined same as we do for Drive.
523 SendResponse(true);
524 return;
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();
536 SetResult(sizes);
538 sizes->SetDouble("totalSize", static_cast<double>(*total_size));
539 sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size));
541 SendResponse(true);
544 bool FileManagerPrivateInternalValidatePathNameLengthFunction::RunAsync() {
545 using extensions::api::file_manager_private_internal::ValidatePathNameLength::
546 Params;
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))
557 return false;
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));
562 SendResponse(true);
563 return 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()));
573 return true;
576 void FileManagerPrivateInternalValidatePathNameLengthFunction::
577 OnFilePathLimitRetrieved(size_t current_length, size_t max_length) {
578 SetResult(new base::FundamentalValue(current_length <= max_length));
579 SendResponse(true);
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());
590 if (!volume_manager)
591 return false;
593 base::WeakPtr<Volume> volume =
594 volume_manager->FindVolumeById(params->volume_id);
595 if (!volume)
596 return false;
598 DiskMountManager::GetInstance()->FormatMountedDevice(
599 volume->mount_path().AsUTF8Unsafe());
600 SendResponse(true);
601 return true;
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");
632 return false;
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));
646 destination_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");
652 return false;
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,
664 this)));
667 return BrowserThread::PostTask(
668 BrowserThread::UI, FROM_HERE,
669 base::Bind(
670 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace,
671 this, true));
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");
681 SendResponse(false);
682 return;
685 drive::FileSystemInterface* const drive_file_system =
686 drive::util::GetFileSystemByProfile(GetProfile());
687 if (drive_file_system) {
688 drive_file_system->FreeDiskSpaceIfNeededFor(
689 file_info.size,
690 base::Bind(
691 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace,
692 this));
693 } else {
694 const bool result = BrowserThread::PostTaskAndReplyWithResult(
695 BrowserThread::IO, FROM_HERE,
696 base::Bind(
697 &CheckLocalDiskSpaceOnIOThread,
698 file_manager::util::GetDownloadsFolderForProfile(GetProfile()),
699 file_info.size),
700 base::Bind(
701 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace,
702 this));
703 if (!result)
704 SendResponse(false);
708 void FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace(
709 bool available) {
710 DCHECK_CURRENTLY_ON(BrowserThread::UI);
712 if (!available) {
713 SetError("QuotaExceededError");
714 SendResponse(false);
715 return;
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_),
725 base::Bind(
726 &FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy,
727 this));
728 if (!result)
729 SendResponse(false);
732 void FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy(
733 int operation_id) {
734 DCHECK_CURRENTLY_ON(BrowserThread::UI);
736 SetResult(new base::FundamentalValue(operation_id));
737 SendResponse(true);
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(
753 BrowserThread::IO,
754 FROM_HERE,
755 base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id));
756 SendResponse(true);
757 return true;
760 bool FileManagerPrivateInternalResolveIsolatedEntriesFunction::RunAsync() {
761 using extensions::api::file_manager_private_internal::ResolveIsolatedEntries::
762 Params;
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;
781 const bool result =
782 file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
783 GetProfile(), extension_->id(), file_system_url.path(),
784 &file_definition.virtual_path);
785 if (!result)
786 continue;
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(
794 GetProfile(),
795 extension_->id(),
796 file_definition_list, // Safe, since copied internally.
797 base::Bind(
798 &FileManagerPrivateInternalResolveIsolatedEntriesFunction::
799 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList,
800 this));
801 return true;
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)
812 continue;
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);
824 SendResponse(true);
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");
844 return false;
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");
855 return false;
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,
865 this));
866 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
867 base::Bind(&FileStreamMd5Digester::GetMd5Digest,
868 base::Unretained(digester_.get()),
869 base::Passed(&reader), result_callback));
871 return true;
874 void FileManagerPrivateInternalComputeChecksumFunction::Respond(
875 const std::string& hash) {
876 DCHECK_CURRENTLY_ON(BrowserThread::UI);
877 SetResult(new base::StringValue(hash));
878 SendResponse(true);
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
887 // than Drive.
889 drive::EventLogger* const logger =
890 file_manager::util::GetLogger(GetProfile());
891 if (logger) {
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());
901 if (!file_system) {
902 // |file_system| is NULL if Drive is disabled.
903 return false;
906 std::set<std::string> hashes(params->hash_list.begin(),
907 params->hash_list.end());
908 file_system->SearchByHashes(
909 hashes,
910 base::Bind(
911 &FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes,
912 this, hashes));
913 return true;
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) {
921 SendResponse(false);
922 return;
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);
935 list->AppendString(
936 file_manager::util::ConvertDrivePathToFileSystemUrl(
937 GetProfile(), hashAndPath.path, extension_id()).spec());
939 SetResult(result.release());
940 SendResponse(true);
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.
968 if (!file_system)
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;
975 break;
976 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PUBLIC:
977 visibility = google_apis::drive::Property::VISIBILITY_PUBLIC;
978 break;
979 default:
980 NOTREACHED();
981 return RespondNow(Error("Invalid visibility."));
982 break;
985 file_system->SetProperty(
986 drive_path, visibility, params->key, params->value,
987 base::Bind(&FileManagerPrivateInternalSetEntryTagFunction::
988 OnSetEntryPropertyCompleted,
989 this));
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