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 "base/memory/weak_ptr.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/profiles/profile.h"
17 #include "chrome/common/extensions/api/file_manager_private.h"
18 #include "chromeos/disks/disk_mount_manager.h"
19 #include "components/drive/event_logger.h"
20 #include "components/drive/file_system_interface.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "google_apis/drive/task_util.h"
23 #include "ui/shell_dialogs/selected_file_info.h"
25 using chromeos::disks::DiskMountManager
;
26 using content::BrowserThread
;
27 namespace file_manager_private
= extensions::api::file_manager_private
;
29 namespace extensions
{
33 // Does chmod o+r for the given path to ensure the file is readable from avfs.
34 void EnsureReadableFilePermissionOnBlockingPool(
35 const base::FilePath
& path
,
36 const base::Callback
<void(drive::FileError
, const base::FilePath
&)>&
39 if (!base::GetPosixFilePermissions(path
, &mode
) ||
40 !base::SetPosixFilePermissions(path
, mode
| S_IROTH
)) {
41 callback
.Run(drive::FILE_ERROR_ACCESS_DENIED
, base::FilePath());
44 callback
.Run(drive::FILE_ERROR_OK
, path
);
49 bool FileManagerPrivateAddMountFunction::RunAsync() {
50 using file_manager_private::AddMount::Params
;
51 const scoped_ptr
<Params
> params(Params::Create(*args_
));
52 EXTENSION_FUNCTION_VALIDATE(params
);
54 drive::EventLogger
* logger
= file_manager::util::GetLogger(GetProfile());
56 logger
->Log(logging::LOG_INFO
, "%s[%d] called. (source: '%s')", name(),
58 params
->source
.empty() ? "(none)" : params
->source
.c_str());
60 set_log_on_completion(true);
62 const base::FilePath path
= file_manager::util::GetLocalPathFromURL(
63 render_frame_host(), GetProfile(), GURL(params
->source
));
68 // Check if the source path is under Drive cache directory.
69 if (drive::util::IsUnderDriveMountPoint(path
)) {
70 drive::FileSystemInterface
* file_system
=
71 drive::util::GetFileSystemByProfile(GetProfile());
75 // Ensure that the cache file exists.
76 const base::FilePath drive_path
= drive::util::ExtractDrivePath(path
);
79 base::Bind(&FileManagerPrivateAddMountFunction::RunAfterGetDriveFile
,
83 file_manager::VolumeManager
* volume_manager
=
84 file_manager::VolumeManager::Get(GetProfile());
85 DCHECK(volume_manager
);
87 bool is_under_downloads
= false;
88 const std::vector
<base::WeakPtr
<file_manager::Volume
>> volumes
=
89 volume_manager
->GetVolumeList();
90 for (const auto& volume
: volumes
) {
91 if (volume
->type() == file_manager::VOLUME_TYPE_DOWNLOADS_DIRECTORY
&&
92 volume
->mount_path().IsParent(path
)) {
93 is_under_downloads
= true;
98 if (is_under_downloads
) {
99 // For files under downloads, change the file permission and make it
100 // readable from avfs/fuse if needed.
101 BrowserThread::PostBlockingPoolTask(
103 base::Bind(&EnsureReadableFilePermissionOnBlockingPool
,
105 google_apis::CreateRelayCallback(
106 base::Bind(&FileManagerPrivateAddMountFunction::
107 RunAfterMarkCacheFileAsMounted
,
111 RunAfterMarkCacheFileAsMounted(
112 path
.BaseName(), drive::FILE_ERROR_OK
, path
);
118 void FileManagerPrivateAddMountFunction::RunAfterGetDriveFile(
119 const base::FilePath
& drive_path
,
120 drive::FileError error
,
121 const base::FilePath
& cache_path
,
122 scoped_ptr
<drive::ResourceEntry
> entry
) {
123 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
125 if (error
!= drive::FILE_ERROR_OK
) {
130 drive::FileSystemInterface
* const file_system
=
131 drive::util::GetFileSystemByProfile(GetProfile());
137 file_system
->MarkCacheFileAsMounted(
140 &FileManagerPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted
,
142 drive_path
.BaseName()));
145 void FileManagerPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted(
146 const base::FilePath
& display_name
,
147 drive::FileError error
,
148 const base::FilePath
& file_path
) {
149 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
151 if (error
!= drive::FILE_ERROR_OK
) {
156 // Pass back the actual source path of the mount point.
157 SetResult(new base::StringValue(file_path
.AsUTF8Unsafe()));
160 // MountPath() takes a std::string.
161 DiskMountManager
* disk_mount_manager
= DiskMountManager::GetInstance();
162 disk_mount_manager
->MountPath(
163 file_path
.AsUTF8Unsafe(),
164 base::FilePath(display_name
.Extension()).AsUTF8Unsafe(),
165 display_name
.AsUTF8Unsafe(),
166 chromeos::MOUNT_TYPE_ARCHIVE
);
169 bool FileManagerPrivateRemoveMountFunction::RunAsync() {
170 using file_manager_private::RemoveMount::Params
;
171 const scoped_ptr
<Params
> params(Params::Create(*args_
));
172 EXTENSION_FUNCTION_VALIDATE(params
);
174 drive::EventLogger
* logger
= file_manager::util::GetLogger(GetProfile());
176 logger
->Log(logging::LOG_INFO
, "%s[%d] called. (volume_id: '%s')", name(),
177 request_id(), params
->volume_id
.c_str());
179 set_log_on_completion(true);
181 using file_manager::VolumeManager
;
182 using file_manager::Volume
;
183 VolumeManager
* const volume_manager
= VolumeManager::Get(GetProfile());
184 DCHECK(volume_manager
);
186 base::WeakPtr
<Volume
> volume
=
187 volume_manager
->FindVolumeById(params
->volume_id
);
191 // TODO(tbarzic): Send response when callback is received, it would make more
192 // sense than remembering issued unmount requests in file manager and showing
193 // errors for them when MountCompleted event is received.
194 switch (volume
->type()) {
195 case file_manager::VOLUME_TYPE_REMOVABLE_DISK_PARTITION
:
196 case file_manager::VOLUME_TYPE_MOUNTED_ARCHIVE_FILE
: {
197 DiskMountManager::GetInstance()->UnmountPath(
198 volume
->mount_path().value(), chromeos::UNMOUNT_OPTIONS_NONE
,
199 DiskMountManager::UnmountPathCallback());
202 case file_manager::VOLUME_TYPE_PROVIDED
: {
203 chromeos::file_system_provider::Service
* service
=
204 chromeos::file_system_provider::Service::Get(GetProfile());
206 // TODO(mtomasz): Pass a more detailed error than just a bool.
207 if (!service
->RequestUnmount(volume
->extension_id(),
208 volume
->file_system_id())) {
214 // Requested unmounting a device which is not unmountable.
222 bool FileManagerPrivateGetVolumeMetadataListFunction::RunAsync() {
223 if (args_
->GetSize())
226 const std::vector
<base::WeakPtr
<file_manager::Volume
>>& volume_list
=
227 file_manager::VolumeManager::Get(GetProfile())->GetVolumeList();
229 std::string log_string
;
230 std::vector
<linked_ptr
<file_manager_private::VolumeMetadata
> > result
;
231 for (const auto& volume
: volume_list
) {
232 linked_ptr
<file_manager_private::VolumeMetadata
> volume_metadata(
233 new file_manager_private::VolumeMetadata
);
234 file_manager::util::VolumeToVolumeMetadata(GetProfile(), *volume
.get(),
235 volume_metadata
.get());
236 result
.push_back(volume_metadata
);
237 if (!log_string
.empty())
239 log_string
+= volume
->mount_path().AsUTF8Unsafe();
242 drive::EventLogger
* logger
= file_manager::util::GetLogger(GetProfile());
244 logger
->Log(logging::LOG_INFO
,
245 "%s[%d] succeeded. (results: '[%s]', %" PRIuS
" mount points)",
246 name(), request_id(), log_string
.c_str(), result
.size());
250 file_manager_private::GetVolumeMetadataList::Results::Create(result
);
255 } // namespace extensions