Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / extensions / file_manager / private_api_mount.cc
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.
4
5 #include "chrome/browser/chromeos/extensions/file_manager/private_api_mount.h"
6
7 #include <string>
8
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"
23
24 using chromeos::disks::DiskMountManager;
25 using content::BrowserThread;
26 namespace file_manager_private = extensions::api::file_manager_private;
27
28 namespace extensions {
29
30 namespace {
31
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&)>&
36         callback) {
37   int mode = 0;
38   if (!base::GetPosixFilePermissions(path, &mode) ||
39       !base::SetPosixFilePermissions(path, mode | S_IROTH)) {
40     callback.Run(drive::FILE_ERROR_ACCESS_DENIED, base::FilePath());
41     return;
42   }
43   callback.Run(drive::FILE_ERROR_OK, path);
44 }
45
46 }  // namespace
47
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);
52
53   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
54   if (logger) {
55     logger->Log(logging::LOG_INFO,
56                 "%s[%d] called. (source: '%s')",
57                 name().c_str(),
58                 request_id(),
59                 params->source.empty() ? "(none)" : params->source.c_str());
60   }
61   set_log_on_completion(true);
62
63   const base::FilePath path = file_manager::util::GetLocalPathFromURL(
64       render_view_host(), GetProfile(), GURL(params->source));
65
66   if (path.empty())
67     return false;
68
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());
73     if (!file_system)
74       return false;
75
76     // Ensure that the cache file exists.
77     const base::FilePath drive_path = drive::util::ExtractDrivePath(path);
78     file_system->GetFile(
79         drive_path,
80         base::Bind(&FileManagerPrivateAddMountFunction::RunAfterGetDriveFile,
81                    this,
82                    drive_path));
83   } else {
84     file_manager::VolumeManager* volume_manager =
85         file_manager::VolumeManager::Get(GetProfile());
86     DCHECK(volume_manager);
87
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;
95         break;
96       }
97     }
98
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(
103           FROM_HERE,
104           base::Bind(&EnsureReadableFilePermissionOnBlockingPool,
105                      path,
106                      google_apis::CreateRelayCallback(
107                          base::Bind(&FileManagerPrivateAddMountFunction::
108                                         RunAfterMarkCacheFileAsMounted,
109                                     this,
110                                     path.BaseName()))));
111     } else {
112       RunAfterMarkCacheFileAsMounted(
113           path.BaseName(), drive::FILE_ERROR_OK, path);
114     }
115   }
116   return true;
117 }
118
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);
125
126   if (error != drive::FILE_ERROR_OK) {
127     SendResponse(false);
128     return;
129   }
130
131   drive::FileSystemInterface* const file_system =
132       drive::util::GetFileSystemByProfile(GetProfile());
133   if (!file_system) {
134     SendResponse(false);
135     return;
136   }
137
138   file_system->MarkCacheFileAsMounted(
139       drive_path,
140       base::Bind(
141           &FileManagerPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted,
142           this,
143           drive_path.BaseName()));
144 }
145
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));
151
152   if (error != drive::FILE_ERROR_OK) {
153     SendResponse(false);
154     return;
155   }
156
157   // Pass back the actual source path of the mount point.
158   SetResult(new base::StringValue(file_path.AsUTF8Unsafe()));
159   SendResponse(true);
160
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);
168 }
169
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);
174
175   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
176   if (logger) {
177     logger->Log(logging::LOG_INFO,
178                 "%s[%d] called. (volume_id: '%s')",
179                 name().c_str(),
180                 request_id(),
181                 params->volume_id.c_str());
182   }
183   set_log_on_completion(true);
184
185   using file_manager::VolumeManager;
186   using file_manager::VolumeInfo;
187   VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
188   DCHECK(volume_manager);
189
190   VolumeInfo volume_info;
191   if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info))
192     return false;
193
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());
204       break;
205     }
206     case file_manager::VOLUME_TYPE_PROVIDED: {
207       chromeos::file_system_provider::Service* service =
208           chromeos::file_system_provider::Service::Get(GetProfile());
209       DCHECK(service);
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)) {
213         return false;
214       }
215       break;
216     }
217     default:
218       // Requested unmounting a device which is not unmountable.
219       return false;
220   }
221
222   SendResponse(true);
223   return true;
224 }
225
226 bool FileManagerPrivateGetVolumeMetadataListFunction::RunAsync() {
227   if (args_->GetSize())
228     return false;
229
230   const std::vector<file_manager::VolumeInfo>& volume_info_list =
231       file_manager::VolumeManager::Get(GetProfile())->GetVolumeInfoList();
232
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())
242       log_string += ", ";
243     log_string += volume_info_list[i].mount_path.AsUTF8Unsafe();
244   }
245
246   drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
247   if (logger) {
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(),
251                 result.size());
252   }
253
254   results_ =
255       file_manager_private::GetVolumeMetadataList::Results::Create(result);
256   SendResponse(true);
257   return true;
258 }
259
260 }  // namespace extensions