Home | History | Annotate | Download | only in file_manager
      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
    261