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_util.h"
      6 
      7 #include <string>
      8 
      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/snapshot_manager.h"
     21 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
     22 #include "chrome/browser/chromeos/fileapi/file_system_backend.h"
     23 #include "chrome/browser/profiles/profile.h"
     24 #include "chrome/common/extensions/api/file_manager_private.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"
     29 
     30 namespace file_manager_private = extensions::api::file_manager_private;
     31 
     32 namespace file_manager {
     33 namespace util {
     34 namespace {
     35 
     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;
     42 };
     43 
     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;
     47 
     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);
     57 }
     58 
     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);
     66     if (!file_system) {
     67       DLOG(ERROR) << "Drive file selected while disabled: " << path.value();
     68       callback.Run(base::FilePath());
     69       return;
     70     }
     71     file_system->GetFile(drive::util::ExtractDrivePath(path),
     72                          base::Bind(&OnDriveGetFile, path, callback));
     73     return;
     74   }
     75 
     76   VolumeManager::Get(profile)->snapshot_manager()->CreateManagedSnapshot(
     77       path, callback);
     78 }
     79 
     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;
     91     }
     92     file_system->GetFileForSaving(drive::util::ExtractDrivePath(path),
     93                                   base::Bind(&OnDriveGetFile, path, callback));
     94     return;
     95   }
     96 
     97   // TODO(kinaba): For now, the only writable non-local volume is Drive.
     98   NOTREACHED();
     99   callback.Run(base::FilePath());
    100 }
    101 
    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);
    106 
    107 // Part of GetSelectedFileInfo().
    108 void GetSelectedFileInfoInternal(Profile* profile,
    109                                  scoped_ptr<GetSelectedFileInfoParams> params) {
    110   DCHECK(profile);
    111 
    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];
    115 
    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.
    139       }
    140     }
    141     params->selected_files.push_back(
    142         ui::SelectedFileInfo(file_path, base::FilePath()));
    143   }
    144   params->callback.Run(params->selected_files);
    145 }
    146 
    147 // Part of GetSelectedFileInfo().
    148 void ContinueGetSelectedFileInfo(Profile* profile,
    149                                  scoped_ptr<GetSelectedFileInfoParams> params,
    150                                  const base::FilePath& local_path) {
    151   if (local_path.empty()) {
    152     params->callback.Run(std::vector<ui::SelectedFileInfo>());
    153     return;
    154   }
    155   const int index = params->selected_files.size();
    156   const base::FilePath& file_path = params->file_paths[index];
    157   params->selected_files.push_back(ui::SelectedFileInfo(file_path, local_path));
    158   GetSelectedFileInfoInternal(profile, params.Pass());
    159 }
    160 
    161 }  // namespace
    162 
    163 void VolumeInfoToVolumeMetadata(
    164     Profile* profile,
    165     const VolumeInfo& volume_info,
    166     file_manager_private::VolumeMetadata* volume_metadata) {
    167   DCHECK(volume_metadata);
    168 
    169   volume_metadata->volume_id = volume_info.volume_id;
    170 
    171   // TODO(kinaba): fill appropriate information once multi-profile support is
    172   // implemented.
    173   volume_metadata->profile.display_name = profile->GetProfileName();
    174   volume_metadata->profile.is_current_profile = true;
    175 
    176   if (!volume_info.source_path.empty()) {
    177     volume_metadata->source_path.reset(
    178         new std::string(volume_info.source_path.AsUTF8Unsafe()));
    179   }
    180 
    181   if (volume_info.type == VOLUME_TYPE_PROVIDED) {
    182     volume_metadata->extension_id.reset(
    183         new std::string(volume_info.extension_id));
    184 
    185     volume_metadata->file_system_id.reset(
    186         new std::string(volume_info.file_system_id));
    187   }
    188 
    189   volume_metadata->volume_label.reset(
    190       new std::string(volume_info.volume_label));
    191 
    192   switch (volume_info.type) {
    193     case VOLUME_TYPE_GOOGLE_DRIVE:
    194       volume_metadata->volume_type =
    195           file_manager_private::VOLUME_TYPE_DRIVE;
    196       break;
    197     case VOLUME_TYPE_DOWNLOADS_DIRECTORY:
    198       volume_metadata->volume_type =
    199           file_manager_private::VOLUME_TYPE_DOWNLOADS;
    200       break;
    201     case VOLUME_TYPE_REMOVABLE_DISK_PARTITION:
    202       volume_metadata->volume_type =
    203           file_manager_private::VOLUME_TYPE_REMOVABLE;
    204       break;
    205     case VOLUME_TYPE_MOUNTED_ARCHIVE_FILE:
    206       volume_metadata->volume_type = file_manager_private::VOLUME_TYPE_ARCHIVE;
    207       break;
    208     case VOLUME_TYPE_CLOUD_DEVICE:
    209       volume_metadata->volume_type =
    210           file_manager_private::VOLUME_TYPE_CLOUD_DEVICE;
    211       break;
    212     case VOLUME_TYPE_PROVIDED:
    213       volume_metadata->volume_type = file_manager_private::VOLUME_TYPE_PROVIDED;
    214       break;
    215     case VOLUME_TYPE_MTP:
    216       volume_metadata->volume_type = file_manager_private::VOLUME_TYPE_MTP;
    217       break;
    218     case VOLUME_TYPE_TESTING:
    219       volume_metadata->volume_type =
    220           file_manager_private::VOLUME_TYPE_TESTING;
    221       break;
    222     case NUM_VOLUME_TYPE:
    223       NOTREACHED();
    224       break;
    225   }
    226 
    227   // Fill device_type iff the volume is removable partition.
    228   if (volume_info.type == VOLUME_TYPE_REMOVABLE_DISK_PARTITION) {
    229     switch (volume_info.device_type) {
    230       case chromeos::DEVICE_TYPE_UNKNOWN:
    231         volume_metadata->device_type =
    232             file_manager_private::DEVICE_TYPE_UNKNOWN;
    233         break;
    234       case chromeos::DEVICE_TYPE_USB:
    235         volume_metadata->device_type = file_manager_private::DEVICE_TYPE_USB;
    236         break;
    237       case chromeos::DEVICE_TYPE_SD:
    238         volume_metadata->device_type = file_manager_private::DEVICE_TYPE_SD;
    239         break;
    240       case chromeos::DEVICE_TYPE_OPTICAL_DISC:
    241       case chromeos::DEVICE_TYPE_DVD:
    242         volume_metadata->device_type =
    243             file_manager_private::DEVICE_TYPE_OPTICAL;
    244         break;
    245       case chromeos::DEVICE_TYPE_MOBILE:
    246         volume_metadata->device_type = file_manager_private::DEVICE_TYPE_MOBILE;
    247         break;
    248     }
    249     volume_metadata->device_path.reset(
    250         new std::string(volume_info.system_path_prefix.AsUTF8Unsafe()));
    251     volume_metadata->is_parent_device.reset(
    252         new bool(volume_info.is_parent));
    253   } else {
    254     volume_metadata->device_type =
    255         file_manager_private::DEVICE_TYPE_NONE;
    256   }
    257 
    258   volume_metadata->is_read_only = volume_info.is_read_only;
    259 
    260   switch (volume_info.mount_condition) {
    261     case chromeos::disks::MOUNT_CONDITION_NONE:
    262       volume_metadata->mount_condition =
    263           file_manager_private::MOUNT_CONDITION_NONE;
    264       break;
    265     case chromeos::disks::MOUNT_CONDITION_UNKNOWN_FILESYSTEM:
    266       volume_metadata->mount_condition =
    267           file_manager_private::MOUNT_CONDITION_UNKNOWN;
    268       break;
    269     case chromeos::disks::MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM:
    270       volume_metadata->mount_condition =
    271           file_manager_private::MOUNT_CONDITION_UNSUPPORTED;
    272       break;
    273   }
    274 }
    275 
    276 base::FilePath GetLocalPathFromURL(content::RenderViewHost* render_view_host,
    277                                    Profile* profile,
    278                                    const GURL& url) {
    279   DCHECK(render_view_host);
    280   DCHECK(profile);
    281 
    282   scoped_refptr<storage::FileSystemContext> file_system_context =
    283       util::GetFileSystemContextForRenderViewHost(profile, render_view_host);
    284 
    285   const storage::FileSystemURL filesystem_url(
    286       file_system_context->CrackURL(url));
    287   base::FilePath path;
    288   if (!chromeos::FileSystemBackend::CanHandleURL(filesystem_url))
    289     return base::FilePath();
    290   return filesystem_url.path();
    291 }
    292 
    293 void GetSelectedFileInfo(content::RenderViewHost* render_view_host,
    294                          Profile* profile,
    295                          const std::vector<GURL>& file_urls,
    296                          GetSelectedFileInfoLocalPathOption local_path_option,
    297                          GetSelectedFileInfoCallback callback) {
    298   DCHECK(render_view_host);
    299   DCHECK(profile);
    300 
    301   scoped_ptr<GetSelectedFileInfoParams> params(new GetSelectedFileInfoParams);
    302   params->local_path_option = local_path_option;
    303   params->callback = callback;
    304 
    305   for (size_t i = 0; i < file_urls.size(); ++i) {
    306     const GURL& file_url = file_urls[i];
    307     const base::FilePath path = GetLocalPathFromURL(
    308         render_view_host, profile, file_url);
    309     if (!path.empty()) {
    310       DVLOG(1) << "Selected: file path: " << path.value();
    311       params->file_paths.push_back(path);
    312     }
    313   }
    314 
    315   base::MessageLoop::current()->PostTask(
    316       FROM_HERE,
    317       base::Bind(&GetSelectedFileInfoInternal, profile, base::Passed(&params)));
    318 }
    319 
    320 void SetupProfileFileAccessPermissions(int render_view_process_id,
    321                                        Profile* profile) {
    322   const base::FilePath paths[] = {
    323     drive::util::GetDriveMountPointPath(profile),
    324     util::GetDownloadsFolderForProfile(profile),
    325   };
    326   for (size_t i = 0; i < arraysize(paths); ++i) {
    327     content::ChildProcessSecurityPolicy::GetInstance(
    328         )->GrantCreateReadWriteFile(render_view_process_id, paths[i]);
    329   }
    330 }
    331 
    332 drive::EventLogger* GetLogger(Profile* profile) {
    333   drive::DriveIntegrationService* service =
    334       drive::DriveIntegrationServiceFactory::FindForProfile(profile);
    335   return service ? service->event_logger() : NULL;
    336 }
    337 
    338 }  // namespace util
    339 }  // namespace file_manager
    340