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_util.h"
9 #include "base/files/file_path.h"
10 #include "base/message_loop/message_loop.h"
11 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
12 #include "chrome/browser/chromeos/drive/file_errors.h"
13 #include "chrome/browser/chromeos/drive/file_system_interface.h"
14 #include "chrome/browser/chromeos/drive/file_system_util.h"
15 #include "chrome/browser/chromeos/file_manager/app_id.h"
16 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
17 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
18 #include "chrome/browser/chromeos/file_manager/path_util.h"
19 #include "chrome/browser/chromeos/file_manager/snapshot_manager.h"
20 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
21 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/common/extensions/api/file_manager_private.h"
24 #include "components/drive/drive.pb.h"
25 #include "content/public/browser/child_process_security_policy.h"
26 #include "storage/browser/fileapi/file_system_context.h"
27 #include "storage/browser/fileapi/file_system_url.h"
28 #include "ui/shell_dialogs/selected_file_info.h"
30 namespace file_manager_private
= extensions::api::file_manager_private
;
32 namespace file_manager
{
36 // The struct is used for GetSelectedFileInfo().
37 struct GetSelectedFileInfoParams
{
38 GetSelectedFileInfoLocalPathOption local_path_option
;
39 GetSelectedFileInfoCallback callback
;
40 std::vector
<base::FilePath
> file_paths
;
41 std::vector
<ui::SelectedFileInfo
> selected_files
;
44 // The callback type for GetFileNativeLocalPathFor{Opening,Saving}. It receives
45 // the resolved local path when successful, and receives empty path for failure.
46 typedef base::Callback
<void(const base::FilePath
&)> LocalPathCallback
;
48 // Converts a callback from Drive file system to LocalPathCallback.
49 void OnDriveGetFile(const base::FilePath
& path
,
50 const LocalPathCallback
& callback
,
51 drive::FileError error
,
52 const base::FilePath
& local_file_path
,
53 scoped_ptr
<drive::ResourceEntry
> entry
) {
54 if (error
!= drive::FILE_ERROR_OK
)
55 DLOG(ERROR
) << "Failed to get " << path
.value() << " with: " << error
;
56 callback
.Run(local_file_path
);
59 // Gets a resolved local file path of a non native |path| for file opening.
60 void GetFileNativeLocalPathForOpening(Profile
* profile
,
61 const base::FilePath
& path
,
62 const LocalPathCallback
& callback
) {
63 if (drive::util::IsUnderDriveMountPoint(path
)) {
64 drive::FileSystemInterface
* file_system
=
65 drive::util::GetFileSystemByProfile(profile
);
67 DLOG(ERROR
) << "Drive file selected while disabled: " << path
.value();
68 callback
.Run(base::FilePath());
71 file_system
->GetFile(drive::util::ExtractDrivePath(path
),
72 base::Bind(&OnDriveGetFile
, path
, callback
));
76 VolumeManager::Get(profile
)->snapshot_manager()->CreateManagedSnapshot(
80 // Gets a resolved local file path of a non native |path| for file saving.
81 void GetFileNativeLocalPathForSaving(Profile
* profile
,
82 const base::FilePath
& path
,
83 const LocalPathCallback
& callback
) {
84 if (drive::util::IsUnderDriveMountPoint(path
)) {
85 drive::FileSystemInterface
* file_system
=
86 drive::util::GetFileSystemByProfile(profile
);
88 DLOG(ERROR
) << "Drive file selected while disabled: " << path
.value();
89 callback
.Run(base::FilePath());
92 file_system
->GetFileForSaving(drive::util::ExtractDrivePath(path
),
93 base::Bind(&OnDriveGetFile
, path
, callback
));
97 // TODO(kinaba): For now, the only writable non-local volume is Drive.
99 callback
.Run(base::FilePath());
102 // Forward declarations of helper functions for GetSelectedFileInfo().
103 void ContinueGetSelectedFileInfo(Profile
* profile
,
104 scoped_ptr
<GetSelectedFileInfoParams
> params
,
105 const base::FilePath
& local_file_path
);
107 // Part of GetSelectedFileInfo().
108 void GetSelectedFileInfoInternal(Profile
* profile
,
109 scoped_ptr
<GetSelectedFileInfoParams
> params
) {
112 for (size_t i
= params
->selected_files
.size();
113 i
< params
->file_paths
.size(); ++i
) {
114 const base::FilePath
& file_path
= params
->file_paths
[i
];
116 if (file_manager::util::IsUnderNonNativeLocalPath(profile
, file_path
)) {
117 // When the caller of the select file dialog wants local file paths, and
118 // the selected path does not point to a native local path (e.g., Drive,
119 // MTP, or provided file system), we should resolve the path.
120 switch (params
->local_path_option
) {
121 case NO_LOCAL_PATH_RESOLUTION
:
122 // Pass empty local path.
123 params
->selected_files
.push_back(
124 ui::SelectedFileInfo(file_path
, base::FilePath()));
126 case NEED_LOCAL_PATH_FOR_OPENING
:
127 GetFileNativeLocalPathForOpening(
130 base::Bind(&ContinueGetSelectedFileInfo
,
132 base::Passed(¶ms
)));
133 return; // Remaining work is done in ContinueGetSelectedFileInfo.
134 case NEED_LOCAL_PATH_FOR_SAVING
:
135 GetFileNativeLocalPathForSaving(
138 base::Bind(&ContinueGetSelectedFileInfo
,
140 base::Passed(¶ms
)));
141 return; // Remaining work is done in ContinueGetSelectedFileInfo.
144 params
->selected_files
.push_back(
145 ui::SelectedFileInfo(file_path
, file_path
));
148 params
->callback
.Run(params
->selected_files
);
151 // Part of GetSelectedFileInfo().
152 void ContinueGetSelectedFileInfo(Profile
* profile
,
153 scoped_ptr
<GetSelectedFileInfoParams
> params
,
154 const base::FilePath
& local_path
) {
155 if (local_path
.empty()) {
156 params
->callback
.Run(std::vector
<ui::SelectedFileInfo
>());
159 const int index
= params
->selected_files
.size();
160 const base::FilePath
& file_path
= params
->file_paths
[index
];
161 params
->selected_files
.push_back(ui::SelectedFileInfo(file_path
, local_path
));
162 GetSelectedFileInfoInternal(profile
, params
.Pass());
167 void VolumeToVolumeMetadata(
169 const Volume
& volume
,
170 file_manager_private::VolumeMetadata
* volume_metadata
) {
171 DCHECK(volume_metadata
);
173 volume_metadata
->volume_id
= volume
.volume_id();
175 // TODO(kinaba): fill appropriate information once multi-profile support is
177 volume_metadata
->profile
.display_name
= profile
->GetProfileUserName();
178 volume_metadata
->profile
.is_current_profile
= true;
180 if (!volume
.source_path().empty()) {
181 volume_metadata
->source_path
.reset(
182 new std::string(volume
.source_path().AsUTF8Unsafe()));
185 switch (volume
.source()) {
187 volume_metadata
->source
= file_manager_private::SOURCE_FILE
;
190 volume_metadata
->source
= file_manager_private::SOURCE_DEVICE
;
193 volume_metadata
->source
=
194 extensions::api::file_manager_private::SOURCE_NETWORK
;
197 volume_metadata
->source
=
198 extensions::api::file_manager_private::SOURCE_SYSTEM
;
202 volume_metadata
->configurable
= volume
.configurable();
203 volume_metadata
->watchable
= volume
.watchable();
205 if (volume
.type() == VOLUME_TYPE_PROVIDED
) {
206 volume_metadata
->extension_id
.reset(new std::string(volume
.extension_id()));
207 volume_metadata
->file_system_id
.reset(
208 new std::string(volume
.file_system_id()));
211 volume_metadata
->volume_label
.reset(new std::string(volume
.volume_label()));
213 switch (volume
.type()) {
214 case VOLUME_TYPE_GOOGLE_DRIVE
:
215 volume_metadata
->volume_type
=
216 file_manager_private::VOLUME_TYPE_DRIVE
;
218 case VOLUME_TYPE_DOWNLOADS_DIRECTORY
:
219 volume_metadata
->volume_type
=
220 file_manager_private::VOLUME_TYPE_DOWNLOADS
;
222 case VOLUME_TYPE_REMOVABLE_DISK_PARTITION
:
223 volume_metadata
->volume_type
=
224 file_manager_private::VOLUME_TYPE_REMOVABLE
;
226 case VOLUME_TYPE_MOUNTED_ARCHIVE_FILE
:
227 volume_metadata
->volume_type
= file_manager_private::VOLUME_TYPE_ARCHIVE
;
229 case VOLUME_TYPE_PROVIDED
:
230 volume_metadata
->volume_type
= file_manager_private::VOLUME_TYPE_PROVIDED
;
232 case VOLUME_TYPE_MTP
:
233 volume_metadata
->volume_type
= file_manager_private::VOLUME_TYPE_MTP
;
235 case VOLUME_TYPE_TESTING
:
236 volume_metadata
->volume_type
=
237 file_manager_private::VOLUME_TYPE_TESTING
;
239 case NUM_VOLUME_TYPE
:
244 // Fill device_type iff the volume is removable partition.
245 if (volume
.type() == VOLUME_TYPE_REMOVABLE_DISK_PARTITION
) {
246 switch (volume
.device_type()) {
247 case chromeos::DEVICE_TYPE_UNKNOWN
:
248 volume_metadata
->device_type
=
249 file_manager_private::DEVICE_TYPE_UNKNOWN
;
251 case chromeos::DEVICE_TYPE_USB
:
252 volume_metadata
->device_type
= file_manager_private::DEVICE_TYPE_USB
;
254 case chromeos::DEVICE_TYPE_SD
:
255 volume_metadata
->device_type
= file_manager_private::DEVICE_TYPE_SD
;
257 case chromeos::DEVICE_TYPE_OPTICAL_DISC
:
258 case chromeos::DEVICE_TYPE_DVD
:
259 volume_metadata
->device_type
=
260 file_manager_private::DEVICE_TYPE_OPTICAL
;
262 case chromeos::DEVICE_TYPE_MOBILE
:
263 volume_metadata
->device_type
= file_manager_private::DEVICE_TYPE_MOBILE
;
266 volume_metadata
->device_path
.reset(
267 new std::string(volume
.system_path_prefix().AsUTF8Unsafe()));
268 volume_metadata
->is_parent_device
.reset(new bool(volume
.is_parent()));
270 volume_metadata
->device_type
=
271 file_manager_private::DEVICE_TYPE_NONE
;
274 volume_metadata
->is_read_only
= volume
.is_read_only();
275 volume_metadata
->has_media
= volume
.has_media();
277 switch (volume
.mount_condition()) {
278 case chromeos::disks::MOUNT_CONDITION_NONE
:
279 volume_metadata
->mount_condition
=
280 file_manager_private::MOUNT_CONDITION_NONE
;
282 case chromeos::disks::MOUNT_CONDITION_UNKNOWN_FILESYSTEM
:
283 volume_metadata
->mount_condition
=
284 file_manager_private::MOUNT_CONDITION_UNKNOWN
;
286 case chromeos::disks::MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM
:
287 volume_metadata
->mount_condition
=
288 file_manager_private::MOUNT_CONDITION_UNSUPPORTED
;
292 // If the context is known, then pass it.
293 switch (volume
.mount_context()) {
294 case MOUNT_CONTEXT_USER
:
295 volume_metadata
->mount_context
= file_manager_private::MOUNT_CONTEXT_USER
;
297 case MOUNT_CONTEXT_AUTO
:
298 volume_metadata
->mount_context
= file_manager_private::MOUNT_CONTEXT_AUTO
;
300 case MOUNT_CONTEXT_UNKNOWN
:
305 base::FilePath
GetLocalPathFromURL(content::RenderFrameHost
* render_frame_host
,
308 DCHECK(render_frame_host
);
311 scoped_refptr
<storage::FileSystemContext
> file_system_context
=
312 util::GetFileSystemContextForRenderFrameHost(profile
, render_frame_host
);
314 const storage::FileSystemURL
filesystem_url(
315 file_system_context
->CrackURL(url
));
317 if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url
))
318 return base::FilePath();
319 return filesystem_url
.path();
322 void GetSelectedFileInfo(content::RenderFrameHost
* render_frame_host
,
324 const std::vector
<GURL
>& file_urls
,
325 GetSelectedFileInfoLocalPathOption local_path_option
,
326 GetSelectedFileInfoCallback callback
) {
327 DCHECK(render_frame_host
);
330 scoped_ptr
<GetSelectedFileInfoParams
> params(new GetSelectedFileInfoParams
);
331 params
->local_path_option
= local_path_option
;
332 params
->callback
= callback
;
334 for (size_t i
= 0; i
< file_urls
.size(); ++i
) {
335 const GURL
& file_url
= file_urls
[i
];
336 const base::FilePath path
= GetLocalPathFromURL(
337 render_frame_host
, profile
, file_url
);
339 DVLOG(1) << "Selected: file path: " << path
.value();
340 params
->file_paths
.push_back(path
);
344 base::MessageLoop::current()->PostTask(
346 base::Bind(&GetSelectedFileInfoInternal
, profile
, base::Passed(¶ms
)));
349 void SetupProfileFileAccessPermissions(int render_view_process_id
,
351 const base::FilePath paths
[] = {
352 drive::util::GetDriveMountPointPath(profile
),
353 util::GetDownloadsFolderForProfile(profile
),
355 for (size_t i
= 0; i
< arraysize(paths
); ++i
) {
356 content::ChildProcessSecurityPolicy::GetInstance(
357 )->GrantCreateReadWriteFile(render_view_process_id
, paths
[i
]);
361 drive::EventLogger
* GetLogger(Profile
* profile
) {
362 drive::DriveIntegrationService
* service
=
363 drive::DriveIntegrationServiceFactory::FindForProfile(profile
);
364 return service
? service
->event_logger() : NULL
;
368 } // namespace file_manager