Files.app: Refactor local file path resolution utility for file dialog.
[chromium-blink-merge.git] / chrome / browser / chromeos / extensions / file_manager / private_api_util.cc
blobe191f6f1423d6c84c5bc0c82d78ac2e99674ced8
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"
7 #include <string>
9 #include "base/files/file_path.h"
10 #include "base/message_loop/message_loop.h"
11 #include "chrome/browser/chromeos/drive/drive.pb.h"
12 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
13 #include "chrome/browser/chromeos/drive/file_errors.h"
14 #include "chrome/browser/chromeos/drive/file_system_interface.h"
15 #include "chrome/browser/chromeos/drive/file_system_util.h"
16 #include "chrome/browser/chromeos/file_manager/app_id.h"
17 #include "chrome/browser/chromeos/file_manager/fileapi_util.h"
18 #include "chrome/browser/chromeos/file_manager/filesystem_api_util.h"
19 #include "chrome/browser/chromeos/file_manager/path_util.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_browser_private.h"
24 #include "content/public/browser/child_process_security_policy.h"
25 #include "ui/shell_dialogs/selected_file_info.h"
26 #include "webkit/browser/fileapi/file_system_context.h"
27 #include "webkit/browser/fileapi/file_system_url.h"
29 namespace file_browser_private = extensions::api::file_browser_private;
31 namespace file_manager {
32 namespace util {
33 namespace {
35 // The struct is used for GetSelectedFileInfo().
36 struct GetSelectedFileInfoParams {
37 GetSelectedFileInfoLocalPathOption local_path_option;
38 GetSelectedFileInfoCallback callback;
39 std::vector<base::FilePath> file_paths;
40 std::vector<ui::SelectedFileInfo> selected_files;
43 // The callback type for GetFileNativeLocalPathFor{Opening,Saving}. It receives
44 // the resolved local path when successful, and receives empty path for failure.
45 typedef base::Callback<void(const base::FilePath&)> LocalPathCallback;
47 // Converts a callback from Drive file system to LocalPathCallback.
48 void OnDriveGetFile(const base::FilePath& path,
49 const LocalPathCallback& callback,
50 drive::FileError error,
51 const base::FilePath& local_file_path,
52 scoped_ptr<drive::ResourceEntry> entry) {
53 if (error != drive::FILE_ERROR_OK)
54 DLOG(ERROR) << "Failed to get " << path.value() << " with: " << error;
55 callback.Run(local_file_path);
58 // Gets a resolved local file path of a non native |path| for file opening.
59 void GetFileNativeLocalPathForOpening(Profile* profile,
60 const base::FilePath& path,
61 const LocalPathCallback& callback) {
62 if (drive::util::IsUnderDriveMountPoint(path)) {
63 drive::FileSystemInterface* file_system =
64 drive::util::GetFileSystemByProfile(profile);
65 if (!file_system) {
66 DLOG(ERROR) << "Drive file selected while disabled: " << path.value();
67 callback.Run(base::FilePath());
68 return;
70 file_system->GetFile(drive::util::ExtractDrivePath(path),
71 base::Bind(&OnDriveGetFile, path, callback));
72 return;
75 // TODO(kinaba) crbug.com/383207 implement this.
76 NOTREACHED();
77 callback.Run(base::FilePath());
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);
87 if (!file_system) {
88 DLOG(ERROR) << "Drive file selected while disabled: " << path.value();
89 callback.Run(base::FilePath());
90 return;
92 file_system->GetFileForSaving(drive::util::ExtractDrivePath(path),
93 base::Bind(&OnDriveGetFile, path, callback));
94 return;
97 // TODO(kinaba): For now, the only writable non-local volume is Drive.
98 NOTREACHED();
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) {
110 DCHECK(profile);
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 break; // No special handling needed.
123 case NEED_LOCAL_PATH_FOR_OPENING:
124 GetFileNativeLocalPathForOpening(
125 profile,
126 file_path,
127 base::Bind(&ContinueGetSelectedFileInfo,
128 profile,
129 base::Passed(&params)));
130 return; // Remaining work is done in ContinueGetSelectedFileInfo.
131 case NEED_LOCAL_PATH_FOR_SAVING:
132 GetFileNativeLocalPathForSaving(
133 profile,
134 file_path,
135 base::Bind(&ContinueGetSelectedFileInfo,
136 profile,
137 base::Passed(&params)));
138 return; // Remaining work is done in ContinueGetSelectedFileInfo.
141 params->selected_files.push_back(
142 ui::SelectedFileInfo(file_path, base::FilePath()));
144 params->callback.Run(params->selected_files);
147 // Part of GetSelectedFileInfo().
148 void ContinueGetSelectedFileInfo(Profile* profile,
149 scoped_ptr<GetSelectedFileInfoParams> params,
150 const base::FilePath& local_path) {
151 const int index = params->selected_files.size();
152 const base::FilePath& file_path = params->file_paths[index];
153 params->selected_files.push_back(ui::SelectedFileInfo(file_path, local_path));
154 GetSelectedFileInfoInternal(profile, params.Pass());
157 } // namespace
159 void VolumeInfoToVolumeMetadata(
160 Profile* profile,
161 const VolumeInfo& volume_info,
162 file_browser_private::VolumeMetadata* volume_metadata) {
163 DCHECK(volume_metadata);
165 volume_metadata->volume_id = volume_info.volume_id;
167 // TODO(kinaba): fill appropriate information once multi-profile support is
168 // implemented.
169 volume_metadata->profile.display_name = profile->GetProfileName();
170 volume_metadata->profile.is_current_profile = true;
172 if (!volume_info.source_path.empty()) {
173 volume_metadata->source_path.reset(
174 new std::string(volume_info.source_path.AsUTF8Unsafe()));
177 if (volume_info.type == VOLUME_TYPE_PROVIDED) {
178 volume_metadata->extension_id.reset(
179 new std::string(volume_info.extension_id));
181 volume_metadata->file_system_id.reset(
182 new std::string(volume_info.file_system_id));
185 volume_metadata->volume_label.reset(
186 new std::string(volume_info.volume_label));
188 switch (volume_info.type) {
189 case VOLUME_TYPE_GOOGLE_DRIVE:
190 volume_metadata->volume_type =
191 file_browser_private::VOLUME_TYPE_DRIVE;
192 break;
193 case VOLUME_TYPE_DOWNLOADS_DIRECTORY:
194 volume_metadata->volume_type =
195 file_browser_private::VOLUME_TYPE_DOWNLOADS;
196 break;
197 case VOLUME_TYPE_REMOVABLE_DISK_PARTITION:
198 volume_metadata->volume_type =
199 file_browser_private::VOLUME_TYPE_REMOVABLE;
200 break;
201 case VOLUME_TYPE_MOUNTED_ARCHIVE_FILE:
202 volume_metadata->volume_type = file_browser_private::VOLUME_TYPE_ARCHIVE;
203 break;
204 case VOLUME_TYPE_CLOUD_DEVICE:
205 volume_metadata->volume_type =
206 file_browser_private::VOLUME_TYPE_CLOUD_DEVICE;
207 break;
208 case VOLUME_TYPE_PROVIDED:
209 volume_metadata->volume_type = file_browser_private::VOLUME_TYPE_PROVIDED;
210 break;
211 case VOLUME_TYPE_MTP:
212 volume_metadata->volume_type = file_browser_private::VOLUME_TYPE_MTP;
213 break;
214 case VOLUME_TYPE_TESTING:
215 volume_metadata->volume_type =
216 file_browser_private::VOLUME_TYPE_TESTING;
217 break;
218 case NUM_VOLUME_TYPE:
219 NOTREACHED();
220 break;
223 // Fill device_type iff the volume is removable partition.
224 if (volume_info.type == VOLUME_TYPE_REMOVABLE_DISK_PARTITION) {
225 switch (volume_info.device_type) {
226 case chromeos::DEVICE_TYPE_UNKNOWN:
227 volume_metadata->device_type =
228 file_browser_private::DEVICE_TYPE_UNKNOWN;
229 break;
230 case chromeos::DEVICE_TYPE_USB:
231 volume_metadata->device_type = file_browser_private::DEVICE_TYPE_USB;
232 break;
233 case chromeos::DEVICE_TYPE_SD:
234 volume_metadata->device_type = file_browser_private::DEVICE_TYPE_SD;
235 break;
236 case chromeos::DEVICE_TYPE_OPTICAL_DISC:
237 case chromeos::DEVICE_TYPE_DVD:
238 volume_metadata->device_type =
239 file_browser_private::DEVICE_TYPE_OPTICAL;
240 break;
241 case chromeos::DEVICE_TYPE_MOBILE:
242 volume_metadata->device_type = file_browser_private::DEVICE_TYPE_MOBILE;
243 break;
245 volume_metadata->device_path.reset(
246 new std::string(volume_info.system_path_prefix.AsUTF8Unsafe()));
247 volume_metadata->is_parent_device.reset(
248 new bool(volume_info.is_parent));
249 } else {
250 volume_metadata->device_type =
251 file_browser_private::DEVICE_TYPE_NONE;
254 volume_metadata->is_read_only = volume_info.is_read_only;
256 switch (volume_info.mount_condition) {
257 case chromeos::disks::MOUNT_CONDITION_NONE:
258 volume_metadata->mount_condition =
259 file_browser_private::MOUNT_CONDITION_NONE;
260 break;
261 case chromeos::disks::MOUNT_CONDITION_UNKNOWN_FILESYSTEM:
262 volume_metadata->mount_condition =
263 file_browser_private::MOUNT_CONDITION_UNKNOWN;
264 break;
265 case chromeos::disks::MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM:
266 volume_metadata->mount_condition =
267 file_browser_private::MOUNT_CONDITION_UNSUPPORTED;
268 break;
272 base::FilePath GetLocalPathFromURL(content::RenderViewHost* render_view_host,
273 Profile* profile,
274 const GURL& url) {
275 DCHECK(render_view_host);
276 DCHECK(profile);
278 scoped_refptr<fileapi::FileSystemContext> file_system_context =
279 util::GetFileSystemContextForRenderViewHost(profile, render_view_host);
281 const fileapi::FileSystemURL filesystem_url(
282 file_system_context->CrackURL(url));
283 base::FilePath path;
284 if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url))
285 return base::FilePath();
286 return filesystem_url.path();
289 void GetSelectedFileInfo(content::RenderViewHost* render_view_host,
290 Profile* profile,
291 const std::vector<GURL>& file_urls,
292 GetSelectedFileInfoLocalPathOption local_path_option,
293 GetSelectedFileInfoCallback callback) {
294 DCHECK(render_view_host);
295 DCHECK(profile);
297 scoped_ptr<GetSelectedFileInfoParams> params(new GetSelectedFileInfoParams);
298 params->local_path_option = local_path_option;
299 params->callback = callback;
301 for (size_t i = 0; i < file_urls.size(); ++i) {
302 const GURL& file_url = file_urls[i];
303 const base::FilePath path = GetLocalPathFromURL(
304 render_view_host, profile, file_url);
305 if (!path.empty()) {
306 DVLOG(1) << "Selected: file path: " << path.value();
307 params->file_paths.push_back(path);
311 base::MessageLoop::current()->PostTask(
312 FROM_HERE,
313 base::Bind(&GetSelectedFileInfoInternal, profile, base::Passed(&params)));
316 void SetupProfileFileAccessPermissions(int render_view_process_id,
317 Profile* profile) {
318 const base::FilePath paths[] = {
319 drive::util::GetDriveMountPointPath(profile),
320 util::GetDownloadsFolderForProfile(profile),
322 for (size_t i = 0; i < arraysize(paths); ++i) {
323 content::ChildProcessSecurityPolicy::GetInstance(
324 )->GrantCreateReadWriteFile(render_view_process_id, paths[i]);
328 drive::EventLogger* GetLogger(Profile* profile) {
329 drive::DriveIntegrationService* service =
330 drive::DriveIntegrationServiceFactory::FindForProfileRegardlessOfStates(
331 profile);
332 return service ? service->event_logger() : NULL;
335 } // namespace util
336 } // namespace file_manager