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