private_api_mount.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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/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_browser_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
24using chromeos::disks::DiskMountManager;
25using content::BrowserThread;
26namespace file_browser_private = extensions::api::file_browser_private;
27
28namespace extensions {
29
30namespace {
31
32// Does chmod o+r for the given path to ensure the file is readable from avfs.
33void 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
48bool FileBrowserPrivateAddMountFunction::RunAsync() {
49  using file_browser_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    file_system->MarkCacheFileAsMounted(
77        drive::util::ExtractDrivePath(path),
78        base::Bind(
79            &FileBrowserPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted,
80            this, path.BaseName()));
81  } else {
82    file_manager::VolumeManager* volume_manager =
83        file_manager::VolumeManager::Get(GetProfile());
84    DCHECK(volume_manager);
85
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;
93        break;
94      }
95    }
96
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(
101          FROM_HERE,
102          base::Bind(&EnsureReadableFilePermissionOnBlockingPool,
103                     path,
104                     google_apis::CreateRelayCallback(
105                         base::Bind(&FileBrowserPrivateAddMountFunction::
106                                        RunAfterMarkCacheFileAsMounted,
107                                    this,
108                                    path.BaseName()))));
109    } else {
110      RunAfterMarkCacheFileAsMounted(
111          path.BaseName(), drive::FILE_ERROR_OK, path);
112    }
113  }
114  return true;
115}
116
117void FileBrowserPrivateAddMountFunction::RunAfterMarkCacheFileAsMounted(
118    const base::FilePath& display_name,
119    drive::FileError error,
120    const base::FilePath& file_path) {
121  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
122
123  if (error != drive::FILE_ERROR_OK) {
124    SendResponse(false);
125    return;
126  }
127
128  // Pass back the actual source path of the mount point.
129  SetResult(new base::StringValue(file_path.AsUTF8Unsafe()));
130  SendResponse(true);
131
132  // MountPath() takes a std::string.
133  DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance();
134  disk_mount_manager->MountPath(
135      file_path.AsUTF8Unsafe(),
136      base::FilePath(display_name.Extension()).AsUTF8Unsafe(),
137      display_name.AsUTF8Unsafe(),
138      chromeos::MOUNT_TYPE_ARCHIVE);
139}
140
141bool FileBrowserPrivateRemoveMountFunction::RunAsync() {
142  using file_browser_private::RemoveMount::Params;
143  const scoped_ptr<Params> params(Params::Create(*args_));
144  EXTENSION_FUNCTION_VALIDATE(params);
145
146  drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
147  if (logger) {
148    logger->Log(logging::LOG_INFO,
149                "%s[%d] called. (volume_id: '%s')",
150                name().c_str(),
151                request_id(),
152                params->volume_id.c_str());
153  }
154  set_log_on_completion(true);
155
156  using file_manager::VolumeManager;
157  using file_manager::VolumeInfo;
158  VolumeManager* volume_manager = VolumeManager::Get(GetProfile());
159  DCHECK(volume_manager);
160
161  VolumeInfo volume_info;
162  if (!volume_manager->FindVolumeInfoById(params->volume_id, &volume_info))
163    return false;
164
165  // TODO(tbarzic): Send response when callback is received, it would make more
166  // sense than remembering issued unmount requests in file manager and showing
167  // errors for them when MountCompleted event is received.
168  switch (volume_info.type) {
169    case file_manager::VOLUME_TYPE_REMOVABLE_DISK_PARTITION:
170    case file_manager::VOLUME_TYPE_MOUNTED_ARCHIVE_FILE: {
171      DiskMountManager::GetInstance()->UnmountPath(
172          volume_info.mount_path.value(),
173          chromeos::UNMOUNT_OPTIONS_NONE,
174          DiskMountManager::UnmountPathCallback());
175      break;
176    }
177    case file_manager::VOLUME_TYPE_PROVIDED: {
178      chromeos::file_system_provider::Service* service =
179          chromeos::file_system_provider::Service::Get(GetProfile());
180      DCHECK(service);
181      // TODO(mtomasz): Pass a more detailed error than just a bool.
182      if (!service->RequestUnmount(volume_info.extension_id,
183                                   volume_info.file_system_id)) {
184        return false;
185      }
186      break;
187    }
188    default:
189      // Requested unmounting a device which is not unmountable.
190      return false;
191  }
192
193  SendResponse(true);
194  return true;
195}
196
197bool FileBrowserPrivateGetVolumeMetadataListFunction::RunAsync() {
198  if (args_->GetSize())
199    return false;
200
201  const std::vector<file_manager::VolumeInfo>& volume_info_list =
202      file_manager::VolumeManager::Get(GetProfile())->GetVolumeInfoList();
203
204  std::string log_string;
205  std::vector<linked_ptr<file_browser_private::VolumeMetadata> > result;
206  for (size_t i = 0; i < volume_info_list.size(); ++i) {
207    linked_ptr<file_browser_private::VolumeMetadata> volume_metadata(
208        new file_browser_private::VolumeMetadata);
209    file_manager::util::VolumeInfoToVolumeMetadata(
210        GetProfile(), volume_info_list[i], volume_metadata.get());
211    result.push_back(volume_metadata);
212    if (!log_string.empty())
213      log_string += ", ";
214    log_string += volume_info_list[i].mount_path.AsUTF8Unsafe();
215  }
216
217  drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
218  if (logger) {
219    logger->Log(logging::LOG_INFO,
220                "%s[%d] succeeded. (results: '[%s]', %" PRIuS " mount points)",
221                name().c_str(), request_id(), log_string.c_str(),
222                result.size());
223  }
224
225  results_ =
226      file_browser_private::GetVolumeMetadataList::Results::Create(result);
227  SendResponse(true);
228  return true;
229}
230
231}  // namespace extensions
232