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
, "%s[%d] called. (source: '%s')", name(),
57 params
->source
.empty() ? "(none)" : params
->source
.c_str());
59 set_log_on_completion(true);
61 const base::FilePath path
= file_manager::util::GetLocalPathFromURL(
62 render_view_host(), GetProfile(), GURL(params
->source
));
67 // Check if the source path is under Drive cache directory.
68 if (drive::util::IsUnderDriveMountPoint(path
)) {
69 drive::FileSystemInterface
* file_system
=
70 drive::util::GetFileSystemByProfile(GetProfile());
74 // Ensure that the cache file exists.
75 const base::FilePath drive_path
= drive::util::ExtractDrivePath(path
);
78 base::Bind(&FileManagerPrivateAddMountFunction::RunAfterGetDriveFile
,
82 file_manager::VolumeManager
* volume_manager
=
83 file_manager::VolumeManager::Get(GetProfile());
84 DCHECK(volume_manager
);
86 bool is_under_downloads
= false;
87 const std::vector
<file_manager::VolumeInfo
> volumes
=
88 volume_manager
->GetVolumeInfoList();
89 for (size_t i
= 0; i
< volumes
.size(); ++i
) {
90 if (volumes
[i
].type
== file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY
&&
91 volumes
[i
].mount_path
.IsParent(path
)) {
92 is_under_downloads
= true;
97 if (is_under_downloads
) {
98 // For files under downloads, change the file permission and make it
99 // readable from avfs/fuse if needed.
100 BrowserThread::PostBlockingPoolTask(
102 base::Bind(&EnsureReadableFilePermissionOnBlockingPool
,
104 google_apis::CreateRelayCallback(
105 base::Bind(&FileManagerPrivateAddMountFunction::
106 RunAfterMarkCacheFileAsMounted
,
110 RunAfterMarkCacheFileAsMounted(
111 path
.BaseName(), drive::FILE_ERROR_OK
, path
);
117 void FileManagerPrivateAddMountFunction::RunAfterGetDriveFile(
118 const base::FilePath
& drive_path
,
119 drive::FileError error
,
120 const base::FilePath
& cache_path
,
121 scoped_ptr
<drive::ResourceEntry
> entry
) {
122 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
124 if (error
!= drive::FILE_ERROR_OK
) {
129 drive::FileSystemInterface
* const file_system
=
130 drive::util::GetFileSystemByProfile(GetProfile());
136 file_system
->MarkCacheFileAsMounted(
139 &FileManagerPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted
,
141 drive_path
.BaseName()));
144 void FileManagerPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted(
145 const base::FilePath
& display_name
,
146 drive::FileError error
,
147 const base::FilePath
& file_path
) {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
150 if (error
!= drive::FILE_ERROR_OK
) {
155 // Pass back the actual source path of the mount point.
156 SetResult(new base::StringValue(file_path
.AsUTF8Unsafe()));
159 // MountPath() takes a std::string.
160 DiskMountManager
* disk_mount_manager
= DiskMountManager::GetInstance();
161 disk_mount_manager
->MountPath(
162 file_path
.AsUTF8Unsafe(),
163 base::FilePath(display_name
.Extension()).AsUTF8Unsafe(),
164 display_name
.AsUTF8Unsafe(),
165 chromeos::MOUNT_TYPE_ARCHIVE
);
168 bool FileManagerPrivateRemoveMountFunction::RunAsync() {
169 using file_manager_private::RemoveMount::Params
;
170 const scoped_ptr
<Params
> params(Params::Create(*args_
));
171 EXTENSION_FUNCTION_VALIDATE(params
);
173 drive::EventLogger
* logger
= file_manager::util::GetLogger(GetProfile());
175 logger
->Log(logging::LOG_INFO
, "%s[%d] called. (volume_id: '%s')", name(),
176 request_id(), params
->volume_id
.c_str());
178 set_log_on_completion(true);
180 using file_manager::VolumeManager
;
181 using file_manager::VolumeInfo
;
182 VolumeManager
* volume_manager
= VolumeManager::Get(GetProfile());
183 DCHECK(volume_manager
);
185 VolumeInfo volume_info
;
186 if (!volume_manager
->FindVolumeInfoById(params
->volume_id
, &volume_info
))
189 // TODO(tbarzic): Send response when callback is received, it would make more
190 // sense than remembering issued unmount requests in file manager and showing
191 // errors for them when MountCompleted event is received.
192 switch (volume_info
.type
) {
193 case file_manager::VOLUME_TYPE_REMOVABLE_DISK_PARTITION
:
194 case file_manager::VOLUME_TYPE_MOUNTED_ARCHIVE_FILE
: {
195 DiskMountManager::GetInstance()->UnmountPath(
196 volume_info
.mount_path
.value(),
197 chromeos::UNMOUNT_OPTIONS_NONE
,
198 DiskMountManager::UnmountPathCallback());
201 case file_manager::VOLUME_TYPE_PROVIDED
: {
202 chromeos::file_system_provider::Service
* service
=
203 chromeos::file_system_provider::Service::Get(GetProfile());
205 // TODO(mtomasz): Pass a more detailed error than just a bool.
206 if (!service
->RequestUnmount(volume_info
.extension_id
,
207 volume_info
.file_system_id
)) {
213 // Requested unmounting a device which is not unmountable.
221 bool FileManagerPrivateGetVolumeMetadataListFunction::RunAsync() {
222 if (args_
->GetSize())
225 const std::vector
<file_manager::VolumeInfo
>& volume_info_list
=
226 file_manager::VolumeManager::Get(GetProfile())->GetVolumeInfoList();
228 std::string log_string
;
229 std::vector
<linked_ptr
<file_manager_private::VolumeMetadata
> > result
;
230 for (size_t i
= 0; i
< volume_info_list
.size(); ++i
) {
231 linked_ptr
<file_manager_private::VolumeMetadata
> volume_metadata(
232 new file_manager_private::VolumeMetadata
);
233 file_manager::util::VolumeInfoToVolumeMetadata(
234 GetProfile(), volume_info_list
[i
], volume_metadata
.get());
235 result
.push_back(volume_metadata
);
236 if (!log_string
.empty())
238 log_string
+= volume_info_list
[i
].mount_path
.AsUTF8Unsafe();
241 drive::EventLogger
* logger
= file_manager::util::GetLogger(GetProfile());
243 logger
->Log(logging::LOG_INFO
,
244 "%s[%d] succeeded. (results: '[%s]', %" PRIuS
" mount points)",
245 name(), request_id(), log_string
.c_str(), result
.size());
249 file_manager_private::GetVolumeMetadataList::Results::Create(result
);
254 } // namespace extensions