Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / browser / chromeos / extensions / file_manager / private_api_file_system.cc
blobb990642ea5b3c89fa242e17fea0fbb40f85552ba
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 drive::FileSystemInterface* const file_system =
483 drive::util::GetFileSystemByProfile(GetProfile());
485 if (!is_download || !file_system) {
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 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,
500 int64 bytes_total,
501 int64 bytes_used) {
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);
508 } else {
509 // If stats couldn't be gotten for drive, result should be left undefined.
510 SendResponse(true);
514 void FileManagerPrivateGetSizeStatsFunction::OnGetMtpAvailableSpace(
515 const MtpStorageInfo& mtp_storage_info,
516 const bool error) {
517 if (error) {
518 // If stats couldn't be gotten from MTP volume, result should be left
519 // undefined same as we do for Drive.
520 SendResponse(true);
521 return;
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();
533 SetResult(sizes);
535 sizes->SetDouble("totalSize", static_cast<double>(*total_size));
536 sizes->SetDouble("remainingSize", static_cast<double>(*remaining_size));
538 SendResponse(true);
541 bool FileManagerPrivateInternalValidatePathNameLengthFunction::RunAsync() {
542 using extensions::api::file_manager_private_internal::ValidatePathNameLength::
543 Params;
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))
554 return false;
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));
559 SendResponse(true);
560 return 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()));
570 return true;
573 void FileManagerPrivateInternalValidatePathNameLengthFunction::
574 OnFilePathLimitRetrieved(size_t current_length, size_t max_length) {
575 SetResult(new base::FundamentalValue(current_length <= max_length));
576 SendResponse(true);
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());
587 if (!volume_manager)
588 return false;
590 base::WeakPtr<Volume> volume =
591 volume_manager->FindVolumeById(params->volume_id);
592 if (!volume)
593 return false;
595 DiskMountManager::GetInstance()->FormatMountedDevice(
596 volume->mount_path().AsUTF8Unsafe());
597 SendResponse(true);
598 return true;
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");
629 return false;
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));
643 destination_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");
649 return false;
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,
661 this)));
664 return BrowserThread::PostTask(
665 BrowserThread::UI, FROM_HERE,
666 base::Bind(
667 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace,
668 this, true));
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");
678 SendResponse(false);
679 return;
682 drive::FileSystemInterface* const drive_file_system =
683 drive::util::GetFileSystemByProfile(GetProfile());
684 if (drive_file_system) {
685 drive_file_system->FreeDiskSpaceIfNeededFor(
686 file_info.size,
687 base::Bind(
688 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace,
689 this));
690 } else {
691 const bool result = BrowserThread::PostTaskAndReplyWithResult(
692 BrowserThread::IO, FROM_HERE,
693 base::Bind(
694 &CheckLocalDiskSpaceOnIOThread,
695 file_manager::util::GetDownloadsFolderForProfile(GetProfile()),
696 file_info.size),
697 base::Bind(
698 &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace,
699 this));
700 if (!result)
701 SendResponse(false);
705 void FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace(
706 bool available) {
707 DCHECK_CURRENTLY_ON(BrowserThread::UI);
709 if (!available) {
710 SetError("QuotaExceededError");
711 SendResponse(false);
712 return;
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_),
722 base::Bind(
723 &FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy,
724 this));
725 if (!result)
726 SendResponse(false);
729 void FileManagerPrivateInternalStartCopyFunction::RunAfterStartCopy(
730 int operation_id) {
731 DCHECK_CURRENTLY_ON(BrowserThread::UI);
733 SetResult(new base::FundamentalValue(operation_id));
734 SendResponse(true);
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(
750 BrowserThread::IO,
751 FROM_HERE,
752 base::Bind(&CancelCopyOnIOThread, file_system_context, params->copy_id));
753 SendResponse(true);
754 return true;
757 bool FileManagerPrivateInternalResolveIsolatedEntriesFunction::RunAsync() {
758 using extensions::api::file_manager_private_internal::ResolveIsolatedEntries::
759 Params;
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;
778 const bool result =
779 file_manager::util::ConvertAbsoluteFilePathToRelativeFileSystemPath(
780 GetProfile(), extension_->id(), file_system_url.path(),
781 &file_definition.virtual_path);
782 if (!result)
783 continue;
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(
791 GetProfile(),
792 extension_->id(),
793 file_definition_list, // Safe, since copied internally.
794 base::Bind(
795 &FileManagerPrivateInternalResolveIsolatedEntriesFunction::
796 RunAsyncAfterConvertFileDefinitionListToEntryDefinitionList,
797 this));
798 return true;
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)
809 continue;
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);
821 SendResponse(true);
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");
841 return false;
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");
852 return false;
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,
862 this));
863 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
864 base::Bind(&FileStreamMd5Digester::GetMd5Digest,
865 base::Unretained(digester_.get()),
866 base::Passed(&reader), result_callback));
868 return true;
871 void FileManagerPrivateInternalComputeChecksumFunction::Respond(
872 const std::string& hash) {
873 DCHECK_CURRENTLY_ON(BrowserThread::UI);
874 SetResult(new base::StringValue(hash));
875 SendResponse(true);
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
884 // than Drive.
886 drive::EventLogger* const logger =
887 file_manager::util::GetLogger(GetProfile());
888 if (logger) {
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());
898 if (!file_system) {
899 // |file_system| is NULL if Drive is disabled.
900 return false;
903 std::set<std::string> hashes(params->hash_list.begin(),
904 params->hash_list.end());
905 file_system->SearchByHashes(
906 hashes,
907 base::Bind(
908 &FileManagerPrivateSearchFilesByHashesFunction::OnSearchByHashes,
909 this, hashes));
910 return true;
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) {
918 SendResponse(false);
919 return;
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);
932 list->AppendString(
933 file_manager::util::ConvertDrivePathToFileSystemUrl(
934 GetProfile(), hashAndPath.path, extension_id()).spec());
936 SetResult(result.release());
937 SendResponse(true);
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.
965 if (!file_system)
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;
972 break;
973 case extensions::api::file_manager_private::ENTRY_TAG_VISIBILITY_PUBLIC:
974 visibility = google_apis::drive::Property::VISIBILITY_PUBLIC;
975 break;
976 default:
977 NOTREACHED();
978 return RespondNow(Error("Invalid visibility."));
979 break;
982 file_system->SetProperty(
983 drive_path, visibility, params->key, params->value,
984 base::Bind(&FileManagerPrivateInternalSetEntryTagFunction::
985 OnSetEntryPropertyCompleted,
986 this));
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