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_mount.h"
9 #include "base/files/file_util.h"
10 #include "base/format_macros.h"
11 #include "chrome/browser/chromeos/drive/file_system_interface.h"
12 #include "chrome/browser/chromeos/drive/file_system_util.h"
13 #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
14 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
15 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
16 #include "chrome/browser/drive/event_logger.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/extensions/api/file_manager_private.h"
19 #include "chromeos/disks/disk_mount_manager.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "google_apis/drive/task_util.h"
22 #include "ui/shell_dialogs/selected_file_info.h"
24 using chromeos::disks::DiskMountManager;
25 using content::BrowserThread;
26 namespace file_manager_private = extensions::api::file_manager_private;
28 namespace extensions {
32 // Does chmod o+r for the given path to ensure the file is readable from avfs.
33 void EnsureReadableFilePermissionOnBlockingPool(
34 const base::FilePath& path,
35 const base::Callback<void(drive::FileError, const base::FilePath&)>&
38 if (!base::GetPosixFilePermissions(path, &mode) ||
39 !base::SetPosixFilePermissions(path, mode | S_IROTH)) {
40 callback.Run(drive::FILE_ERROR_ACCESS_DENIED, base::FilePath());
43 callback.Run(drive::FILE_ERROR_OK, path);
48 bool FileManagerPrivateAddMountFunction::RunAsync() {
49 using file_manager_private::AddMount::Params;
50 const scoped_ptr<Params> params(Params::Create(*args_));
51 EXTENSION_FUNCTION_VALIDATE(params);
53 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
55 logger->Log(logging::LOG_INFO,
56 "%s[%d] called. (source: '%s')",
59 params->source.empty() ? "(none)" : params->source.c_str());
61 set_log_on_completion(true);
63 const base::FilePath path = file_manager::util::GetLocalPathFromURL(
64 render_view_host(), GetProfile(), GURL(params->source));
69 // Check if the source path is under Drive cache directory.
70 if (drive::util::IsUnderDriveMountPoint(path)) {
71 drive::FileSystemInterface* file_system =
72 drive::util::GetFileSystemByProfile(GetProfile());
76 // Ensure that the cache file exists.
77 const base::FilePath drive_path = drive::util::ExtractDrivePath(path);
80 base::Bind(&FileManagerPrivateAddMountFunction::RunAfterGetDriveFile,
84 file_manager::VolumeManager* volume_manager =
85 file_manager::VolumeManager::Get(GetProfile());
86 DCHECK(volume_manager);
88 bool is_under_downloads = false;
89 const std::vector<file_manager::VolumeInfo> volumes =
90 volume_manager->GetVolumeInfoList();
91 for (size_t i = 0; i < volumes.size(); ++i) {
92 if (volumes[i].type == file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY &&
93 volumes[i].mount_path.IsParent(path)) {
94 is_under_downloads = true;
99 if (is_under_downloads) {
100 // For files under downloads, change the file permission and make it
101 // readable from avfs/fuse if needed.
102 BrowserThread::PostBlockingPoolTask(
104 base::Bind(&EnsureReadableFilePermissionOnBlockingPool,
106 google_apis::CreateRelayCallback(
107 base::Bind(&FileManagerPrivateAddMountFunction::
108 RunAfterMarkCacheFileAsMounted,
112 RunAfterMarkCacheFileAsMounted(
113 path.BaseName(), drive::FILE_ERROR_OK, path);
119 void FileManagerPrivateAddMountFunction::RunAfterGetDriveFile(
120 const base::FilePath& drive_path,
121 drive::FileError error,
122 const base::FilePath& cache_path,
123 scoped_ptr<drive::ResourceEntry> entry) {
124 DCHECK_CURRENTLY_ON(BrowserThread::UI);
126 if (error != drive::FILE_ERROR_OK) {
131 drive::FileSystemInterface* const file_system =
132 drive::util::GetFileSystemByProfile(GetProfile());
138 file_system->MarkCacheFileAsMounted(
141 &FileManagerPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted,
143 drive_path.BaseName()));
146 void FileManagerPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted(
147 const base::FilePath& display_name,
148 drive::FileError error,
149 const base::FilePath& file_path) {
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
152 if (error != drive::FILE_ERROR_OK) {
157 // Pass back the actual source path of the mount point.
158 SetResult(new base::StringValue(file_path.AsUTF8Unsafe()));
161 // MountPath() takes a std::string.
162 DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance();
163 disk_mount_manager->MountPath(
164 file_path.AsUTF8Unsafe(),
165 base::FilePath(display_name.Extension()).AsUTF8Unsafe(),
166 display_name.AsUTF8Unsafe(),
167 chromeos::MOUNT_TYPE_ARCHIVE);
170 bool FileManagerPrivateRemoveMountFunction::RunAsync() {
171 using file_manager_private::RemoveMount::Params;
172 const scoped_ptr<Params> params(Params::Create(*args_));
173 EXTENSION_FUNCTION_VALIDATE(params);
175 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
177 logger->Log(logging::LOG_INFO,
178 "%s[%d] called. (volume_id: '%s')",
181 params->volume_id.c_str());
183 set_log_on_completion(true);
185 using file_manager::VolumeManager;
186 using file_manager::VolumeInfo;
187 VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
188 DCHECK(volume_manager);
190 VolumeInfo volume_info;
191 if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info))
194 // TODO(tbarzic): Send response when callback is received, it would make more
195 // sense than remembering issued unmount requests in file manager and showing
196 // errors for them when MountCompleted event is received.
197 switch (volume_info.type) {
198 case file_manager::VOLUME_TYPE_REMOVABLE_DISK_PARTITION:
199 case file_manager::VOLUME_TYPE_MOUNTED_ARCHIVE_FILE: {
200 DiskMountManager::GetInstance()->UnmountPath(
201 volume_info.mount_path.value(),
202 chromeos::UNMOUNT_OPTIONS_NONE,
203 DiskMountManager::UnmountPathCallback());
206 case file_manager::VOLUME_TYPE_PROVIDED: {
207 chromeos::file_system_provider::Service* service =
208 chromeos::file_system_provider::Service::Get(GetProfile());
210 // TODO(mtomasz): Pass a more detailed error than just a bool.
211 if (!service->RequestUnmount(volume_info.extension_id,
212 volume_info.file_system_id)) {
218 // Requested unmounting a device which is not unmountable.
226 bool FileManagerPrivateGetVolumeMetadataListFunction::RunAsync() {
227 if (args_->GetSize())
230 const std::vector<file_manager::VolumeInfo>& volume_info_list =
231 file_manager::VolumeManager::Get(GetProfile())->GetVolumeInfoList();
233 std::string log_string;
234 std::vector<linked_ptr<file_manager_private::VolumeMetadata> > result;
235 for (size_t i = 0; i < volume_info_list.size(); ++i) {
236 linked_ptr<file_manager_private::VolumeMetadata> volume_metadata(
237 new file_manager_private::VolumeMetadata);
238 file_manager::util::VolumeInfoToVolumeMetadata(
239 GetProfile(), volume_info_list[i], volume_metadata.get());
240 result.push_back(volume_metadata);
241 if (!log_string.empty())
243 log_string += volume_info_list[i].mount_path.AsUTF8Unsafe();
246 drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
248 logger->Log(logging::LOG_INFO,
249 "%s[%d] succeeded. (results: '[%s]', %" PRIuS " mount points)",
250 name().c_str(), request_id(), log_string.c_str(),
255 file_manager_private::GetVolumeMetadataList::Results::Create(result);
260 } // namespace extensions