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_browser_private.h"
     25 #include "content/public/browser/child_process_security_policy.h"
     26 #include "ui/shell_dialogs/selected_file_info.h"
     27 #include "webkit/browser/fileapi/file_system_context.h"
     28 #include "webkit/browser/fileapi/file_system_url.h"
     29 
     30 namespace file_browser_private = extensions::api::file_browser_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   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());
    155 }
    156 
    157 }  // namespace
    158 
    159 void VolumeInfoToVolumeMetadata(
    160     Profile* profile,
    161     const VolumeInfo& volume_info,
    162     file_browser_private::VolumeMetadata* volume_metadata) {
    163   DCHECK(volume_metadata);
    164 
    165   volume_metadata->volume_id = volume_info.volume_id;
    166 
    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;
    171 
    172   if (!volume_info.source_path.empty()) {
    173     volume_metadata->source_path.reset(
    174         new std::string(volume_info.source_path.AsUTF8Unsafe()));
    175   }
    176 
    177   if (volume_info.type == VOLUME_TYPE_PROVIDED) {
    178     volume_metadata->extension_id.reset(
    179         new std::string(volume_info.extension_id));
    180 
    181     volume_metadata->file_system_id.reset(
    182         new std::string(volume_info.file_system_id));
    183   }
    184 
    185   volume_metadata->volume_label.reset(
    186       new std::string(volume_info.volume_label));
    187 
    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;
    221   }
    222 
    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;
    244     }
    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;
    252   }
    253 
    254   volume_metadata->is_read_only = volume_info.is_read_only;
    255 
    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;
    269   }
    270 }
    271 
    272 base::FilePath GetLocalPathFromURL(content::RenderViewHost* render_view_host,
    273                                    Profile* profile,
    274                                    const GURL& url) {
    275   DCHECK(render_view_host);
    276   DCHECK(profile);
    277 
    278   scoped_refptr<fileapi::FileSystemContext> file_system_context =
    279       util::GetFileSystemContextForRenderViewHost(profile, render_view_host);
    280 
    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();
    287 }
    288 
    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);
    296 
    297   scoped_ptr<GetSelectedFileInfoParams> params(new GetSelectedFileInfoParams);
    298   params->local_path_option = local_path_option;
    299   params->callback = callback;
    300 
    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);
    308     }
    309   }
    310 
    311   base::MessageLoop::current()->PostTask(
    312       FROM_HERE,
    313       base::Bind(&GetSelectedFileInfoInternal, profile, base::Passed(&params)));
    314 }
    315 
    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),
    321   };
    322   for (size_t i = 0; i < arraysize(paths); ++i) {
    323     content::ChildProcessSecurityPolicy::GetInstance(
    324         )->GrantCreateReadWriteFile(render_view_process_id, paths[i]);
    325   }
    326 }
    327 
    328 drive::EventLogger* GetLogger(Profile* profile) {
    329   drive::DriveIntegrationService* service =
    330       drive::DriveIntegrationServiceFactory::FindForProfileRegardlessOfStates(
    331           profile);
    332   return service ? service->event_logger() : NULL;
    333 }
    334 
    335 }  // namespace util
    336 }  // namespace file_manager
    337