Home | History | Annotate | Download | only in disks
      1 // Copyright (c) 2012 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 "chromeos/disks/disk_mount_manager.h"
      6 
      7 #include <map>
      8 #include <set>
      9 
     10 #include "base/bind.h"
     11 #include "base/memory/weak_ptr.h"
     12 #include "base/observer_list.h"
     13 #include "base/stl_util.h"
     14 #include "base/strings/string_util.h"
     15 #include "chromeos/dbus/dbus_thread_manager.h"
     16 
     17 namespace chromeos {
     18 namespace disks {
     19 
     20 namespace {
     21 
     22 const char kDeviceNotFound[] = "Device could not be found";
     23 
     24 DiskMountManager* g_disk_mount_manager = NULL;
     25 
     26 // The DiskMountManager implementation.
     27 class DiskMountManagerImpl : public DiskMountManager {
     28  public:
     29   DiskMountManagerImpl() : weak_ptr_factory_(this) {
     30     DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get();
     31     DCHECK(dbus_thread_manager);
     32     cros_disks_client_ = dbus_thread_manager->GetCrosDisksClient();
     33     DCHECK(cros_disks_client_);
     34     cros_disks_client_->SetMountEventHandler(
     35         base::Bind(&DiskMountManagerImpl::OnMountEvent,
     36                    weak_ptr_factory_.GetWeakPtr()));
     37     cros_disks_client_->SetMountCompletedHandler(
     38         base::Bind(&DiskMountManagerImpl::OnMountCompleted,
     39                    weak_ptr_factory_.GetWeakPtr()));
     40     cros_disks_client_->SetFormatCompletedHandler(
     41         base::Bind(&DiskMountManagerImpl::OnFormatCompleted,
     42                    weak_ptr_factory_.GetWeakPtr()));
     43   }
     44 
     45   virtual ~DiskMountManagerImpl() {
     46     STLDeleteContainerPairSecondPointers(disks_.begin(), disks_.end());
     47   }
     48 
     49   // DiskMountManager override.
     50   virtual void AddObserver(Observer* observer) OVERRIDE {
     51     observers_.AddObserver(observer);
     52   }
     53 
     54   // DiskMountManager override.
     55   virtual void RemoveObserver(Observer* observer) OVERRIDE {
     56     observers_.RemoveObserver(observer);
     57   }
     58 
     59   // DiskMountManager override.
     60   virtual void MountPath(const std::string& source_path,
     61                          const std::string& source_format,
     62                          const std::string& mount_label,
     63                          MountType type) OVERRIDE {
     64     // Hidden and non-existent devices should not be mounted.
     65     if (type == MOUNT_TYPE_DEVICE) {
     66       DiskMap::const_iterator it = disks_.find(source_path);
     67       if (it == disks_.end() || it->second->is_hidden()) {
     68         OnMountCompleted(MountEntry(MOUNT_ERROR_INTERNAL, source_path, type,
     69                                     ""));
     70         return;
     71       }
     72     }
     73     cros_disks_client_->Mount(
     74         source_path,
     75         source_format,
     76         mount_label,
     77         // When succeeds, OnMountCompleted will be called by
     78         // "MountCompleted" signal instead.
     79         base::Bind(&base::DoNothing),
     80         base::Bind(&DiskMountManagerImpl::OnMountCompleted,
     81                    weak_ptr_factory_.GetWeakPtr(),
     82                    MountEntry(MOUNT_ERROR_INTERNAL, source_path, type, "")));
     83   }
     84 
     85   // DiskMountManager override.
     86   virtual void UnmountPath(const std::string& mount_path,
     87                            UnmountOptions options,
     88                            const UnmountPathCallback& callback) OVERRIDE {
     89     UnmountChildMounts(mount_path);
     90     cros_disks_client_->Unmount(mount_path, options,
     91                                 base::Bind(&DiskMountManagerImpl::OnUnmountPath,
     92                                            weak_ptr_factory_.GetWeakPtr(),
     93                                            callback,
     94                                            true,
     95                                            mount_path),
     96                                 base::Bind(&DiskMountManagerImpl::OnUnmountPath,
     97                                            weak_ptr_factory_.GetWeakPtr(),
     98                                            callback,
     99                                            false,
    100                                            mount_path));
    101   }
    102 
    103   // DiskMountManager override.
    104   virtual void FormatMountedDevice(const std::string& mount_path) OVERRIDE {
    105     MountPointMap::const_iterator mount_point = mount_points_.find(mount_path);
    106     if (mount_point == mount_points_.end()) {
    107       LOG(ERROR) << "Mount point with path \"" << mount_path << "\" not found.";
    108       OnFormatCompleted(FORMAT_ERROR_UNKNOWN, mount_path);
    109       return;
    110     }
    111 
    112     std::string device_path = mount_point->second.source_path;
    113     DiskMap::const_iterator disk = disks_.find(device_path);
    114     if (disk == disks_.end()) {
    115       LOG(ERROR) << "Device with path \"" << device_path << "\" not found.";
    116       OnFormatCompleted(FORMAT_ERROR_UNKNOWN, device_path);
    117       return;
    118     }
    119 
    120     UnmountPath(disk->second->mount_path(),
    121                 UNMOUNT_OPTIONS_NONE,
    122                 base::Bind(&DiskMountManagerImpl::OnUnmountPathForFormat,
    123                            weak_ptr_factory_.GetWeakPtr(),
    124                            device_path));
    125   }
    126 
    127   // DiskMountManager override.
    128   virtual void UnmountDeviceRecursively(
    129       const std::string& device_path,
    130       const UnmountDeviceRecursivelyCallbackType& callback) OVERRIDE {
    131     std::vector<std::string> devices_to_unmount;
    132 
    133     // Get list of all devices to unmount.
    134     int device_path_len = device_path.length();
    135     for (DiskMap::iterator it = disks_.begin(); it != disks_.end(); ++it) {
    136       if (!it->second->mount_path().empty() &&
    137           strncmp(device_path.c_str(), it->second->device_path().c_str(),
    138                   device_path_len) == 0) {
    139         devices_to_unmount.push_back(it->second->mount_path());
    140       }
    141     }
    142 
    143     // We should detect at least original device.
    144     if (devices_to_unmount.empty()) {
    145       if (disks_.find(device_path) == disks_.end()) {
    146         LOG(WARNING) << "Unmount recursive request failed for device "
    147                      << device_path << ", with error: " << kDeviceNotFound;
    148         callback.Run(false);
    149         return;
    150       }
    151 
    152       // Nothing to unmount.
    153       callback.Run(true);
    154       return;
    155     }
    156 
    157     // We will send the same callback data object to all Unmount calls and use
    158     // it to syncronize callbacks.
    159     // Note: this implementation has a potential memory leak issue. For
    160     // example if this instance is destructed before all the callbacks for
    161     // Unmount are invoked, the memory pointed by |cb_data| will be leaked.
    162     // It is because the UnmountDeviceRecursivelyCallbackData keeps how
    163     // many times OnUnmountDeviceRecursively callback is called and when
    164     // all the callbacks are called, |cb_data| will be deleted in the method.
    165     // However destructing the instance before all callback invocations will
    166     // cancel all pending callbacks, so that the |cb_data| would never be
    167     // deleted.
    168     // Fortunately, in the real scenario, the instance will be destructed
    169     // only for ShutDown. So, probably the memory would rarely be leaked.
    170     // TODO(hidehiko): Fix the issue.
    171     UnmountDeviceRecursivelyCallbackData* cb_data =
    172         new UnmountDeviceRecursivelyCallbackData(
    173             callback, devices_to_unmount.size());
    174     for (size_t i = 0; i < devices_to_unmount.size(); ++i) {
    175       cros_disks_client_->Unmount(
    176           devices_to_unmount[i],
    177           UNMOUNT_OPTIONS_NONE,
    178           base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively,
    179                      weak_ptr_factory_.GetWeakPtr(),
    180                      cb_data,
    181                      true,
    182                      devices_to_unmount[i]),
    183           base::Bind(&DiskMountManagerImpl::OnUnmountDeviceRecursively,
    184                      weak_ptr_factory_.GetWeakPtr(),
    185                      cb_data,
    186                      false,
    187                      devices_to_unmount[i]));
    188     }
    189   }
    190 
    191   // DiskMountManager override.
    192   virtual void RequestMountInfoRefresh() OVERRIDE {
    193     cros_disks_client_->EnumerateAutoMountableDevices(
    194         base::Bind(&DiskMountManagerImpl::OnRequestMountInfo,
    195                    weak_ptr_factory_.GetWeakPtr()),
    196         base::Bind(&base::DoNothing));
    197   }
    198 
    199   // DiskMountManager override.
    200   virtual const DiskMap& disks() const OVERRIDE { return disks_; }
    201 
    202   // DiskMountManager override.
    203   virtual const Disk* FindDiskBySourcePath(const std::string& source_path)
    204       const OVERRIDE {
    205     DiskMap::const_iterator disk_it = disks_.find(source_path);
    206     return disk_it == disks_.end() ? NULL : disk_it->second;
    207   }
    208 
    209   // DiskMountManager override.
    210   virtual const MountPointMap& mount_points() const OVERRIDE {
    211     return mount_points_;
    212   }
    213 
    214   // DiskMountManager override.
    215   virtual bool AddDiskForTest(Disk* disk) OVERRIDE {
    216     if (disks_.find(disk->device_path()) != disks_.end()) {
    217       LOG(ERROR) << "Attempt to add a duplicate disk";
    218       return false;
    219     }
    220 
    221     disks_.insert(std::make_pair(disk->device_path(), disk));
    222     return true;
    223   }
    224 
    225   // DiskMountManager override.
    226   // Corresponding disk should be added to the manager before this is called.
    227   virtual bool AddMountPointForTest(
    228       const MountPointInfo& mount_point) OVERRIDE {
    229     if (mount_points_.find(mount_point.mount_path) != mount_points_.end()) {
    230       LOG(ERROR) << "Attempt to add a duplicate mount point";
    231       return false;
    232     }
    233     if (mount_point.mount_type == chromeos::MOUNT_TYPE_DEVICE &&
    234         disks_.find(mount_point.source_path) == disks_.end()) {
    235       LOG(ERROR) << "Device mount points must have a disk entry.";
    236       return false;
    237     }
    238 
    239     mount_points_.insert(std::make_pair(mount_point.mount_path, mount_point));
    240     return true;
    241   }
    242 
    243  private:
    244   struct UnmountDeviceRecursivelyCallbackData {
    245     UnmountDeviceRecursivelyCallbackData(
    246         const UnmountDeviceRecursivelyCallbackType& in_callback,
    247         int in_num_pending_callbacks)
    248         : callback(in_callback),
    249           num_pending_callbacks(in_num_pending_callbacks) {
    250     }
    251 
    252     const UnmountDeviceRecursivelyCallbackType callback;
    253     size_t num_pending_callbacks;
    254   };
    255 
    256   // Unmounts all mount points whose source path is transitively parented by
    257   // |mount_path|.
    258   void UnmountChildMounts(const std::string& mount_path_in) {
    259     std::string mount_path = mount_path_in;
    260     // Let's make sure mount path has trailing slash.
    261     if (mount_path[mount_path.length() - 1] != '/')
    262       mount_path += '/';
    263 
    264     for (MountPointMap::iterator it = mount_points_.begin();
    265          it != mount_points_.end();
    266          ++it) {
    267       if (StartsWithASCII(it->second.source_path, mount_path,
    268                           true /*case sensitive*/)) {
    269         // TODO(tbarzic): Handle the case where this fails.
    270         UnmountPath(it->second.mount_path,
    271                     UNMOUNT_OPTIONS_NONE,
    272                     UnmountPathCallback());
    273       }
    274     }
    275   }
    276 
    277   // Callback for UnmountDeviceRecursively.
    278   void OnUnmountDeviceRecursively(
    279       UnmountDeviceRecursivelyCallbackData* cb_data,
    280       bool success,
    281       const std::string& mount_path) {
    282     if (success) {
    283       // Do standard processing for Unmount event.
    284       OnUnmountPath(UnmountPathCallback(), true, mount_path);
    285       VLOG(1) << mount_path <<  " unmounted.";
    286     }
    287     // This is safe as long as all callbacks are called on the same thread as
    288     // UnmountDeviceRecursively.
    289     cb_data->num_pending_callbacks--;
    290 
    291     if (cb_data->num_pending_callbacks == 0) {
    292       // This code has a problem that the |success| status used here is for the
    293       // last "unmount" callback, but not whether all unmounting is succeeded.
    294       // TODO(hidehiko): Fix the issue.
    295       cb_data->callback.Run(success);
    296       delete cb_data;
    297     }
    298   }
    299 
    300   // Callback to handle MountCompleted signal and Mount method call failure.
    301   void OnMountCompleted(const MountEntry& entry) {
    302     MountCondition mount_condition = MOUNT_CONDITION_NONE;
    303     if (entry.mount_type() == MOUNT_TYPE_DEVICE) {
    304       if (entry.error_code() == MOUNT_ERROR_UNKNOWN_FILESYSTEM) {
    305         mount_condition = MOUNT_CONDITION_UNKNOWN_FILESYSTEM;
    306       }
    307       if (entry.error_code() == MOUNT_ERROR_UNSUPPORTED_FILESYSTEM) {
    308         mount_condition = MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM;
    309       }
    310     }
    311     const MountPointInfo mount_info(entry.source_path(),
    312                                     entry.mount_path(),
    313                                     entry.mount_type(),
    314                                     mount_condition);
    315 
    316     NotifyMountStatusUpdate(MOUNTING, entry.error_code(), mount_info);
    317 
    318     // If the device is corrupted but it's still possible to format it, it will
    319     // be fake mounted.
    320     if ((entry.error_code() == MOUNT_ERROR_NONE ||
    321          mount_info.mount_condition) &&
    322         mount_points_.find(mount_info.mount_path) == mount_points_.end()) {
    323       mount_points_.insert(MountPointMap::value_type(mount_info.mount_path,
    324                                                      mount_info));
    325     }
    326     if ((entry.error_code() == MOUNT_ERROR_NONE ||
    327          mount_info.mount_condition) &&
    328         mount_info.mount_type == MOUNT_TYPE_DEVICE &&
    329         !mount_info.source_path.empty() &&
    330         !mount_info.mount_path.empty()) {
    331       DiskMap::iterator iter = disks_.find(mount_info.source_path);
    332       if (iter == disks_.end()) {
    333         // disk might have been removed by now?
    334         return;
    335       }
    336       Disk* disk = iter->second;
    337       DCHECK(disk);
    338       disk->set_mount_path(mount_info.mount_path);
    339     }
    340   }
    341 
    342   // Callback for UnmountPath.
    343   void OnUnmountPath(const UnmountPathCallback& callback,
    344                      bool success,
    345                      const std::string& mount_path) {
    346     MountPointMap::iterator mount_points_it = mount_points_.find(mount_path);
    347     if (mount_points_it == mount_points_.end()) {
    348       // The path was unmounted, but not as a result of this unmount request,
    349       // so return error.
    350       if (!callback.is_null())
    351         callback.Run(MOUNT_ERROR_INTERNAL);
    352       return;
    353     }
    354 
    355     NotifyMountStatusUpdate(
    356         UNMOUNTING,
    357         success ? MOUNT_ERROR_NONE : MOUNT_ERROR_INTERNAL,
    358         MountPointInfo(mount_points_it->second.source_path,
    359                        mount_points_it->second.mount_path,
    360                        mount_points_it->second.mount_type,
    361                        mount_points_it->second.mount_condition));
    362 
    363     std::string path(mount_points_it->second.source_path);
    364     if (success)
    365       mount_points_.erase(mount_points_it);
    366 
    367     DiskMap::iterator disk_iter = disks_.find(path);
    368     if (disk_iter != disks_.end()) {
    369       DCHECK(disk_iter->second);
    370       if (success)
    371         disk_iter->second->clear_mount_path();
    372     }
    373 
    374     if (!callback.is_null())
    375       callback.Run(success ? MOUNT_ERROR_NONE : MOUNT_ERROR_INTERNAL);
    376   }
    377 
    378   void OnUnmountPathForFormat(const std::string& device_path,
    379                               MountError error_code) {
    380     if (error_code == MOUNT_ERROR_NONE &&
    381         disks_.find(device_path) != disks_.end()) {
    382       FormatUnmountedDevice(device_path);
    383     } else {
    384       OnFormatCompleted(FORMAT_ERROR_UNKNOWN, device_path);
    385     }
    386   }
    387 
    388   // Starts device formatting.
    389   void FormatUnmountedDevice(const std::string& device_path) {
    390     DiskMap::const_iterator disk = disks_.find(device_path);
    391     DCHECK(disk != disks_.end() && disk->second->mount_path().empty());
    392 
    393     const char kFormatVFAT[] = "vfat";
    394     cros_disks_client_->Format(
    395         device_path,
    396         kFormatVFAT,
    397         base::Bind(&DiskMountManagerImpl::OnFormatStarted,
    398                    weak_ptr_factory_.GetWeakPtr(),
    399                    device_path),
    400         base::Bind(&DiskMountManagerImpl::OnFormatCompleted,
    401                    weak_ptr_factory_.GetWeakPtr(),
    402                    FORMAT_ERROR_UNKNOWN,
    403                    device_path));
    404   }
    405 
    406   // Callback for Format.
    407   void OnFormatStarted(const std::string& device_path) {
    408     NotifyFormatStatusUpdate(FORMAT_STARTED, FORMAT_ERROR_NONE, device_path);
    409   }
    410 
    411   // Callback to handle FormatCompleted signal and Format method call failure.
    412   void OnFormatCompleted(FormatError error_code,
    413                          const std::string& device_path) {
    414     NotifyFormatStatusUpdate(FORMAT_COMPLETED, error_code, device_path);
    415   }
    416 
    417   // Callbcak for GetDeviceProperties.
    418   void OnGetDeviceProperties(const DiskInfo& disk_info) {
    419     // TODO(zelidrag): Find a better way to filter these out before we
    420     // fetch the properties:
    421     // Ignore disks coming from the device we booted the system from.
    422     if (disk_info.on_boot_device())
    423       return;
    424 
    425     LOG(WARNING) << "Found disk " << disk_info.device_path();
    426     // Delete previous disk info for this path:
    427     bool is_new = true;
    428     DiskMap::iterator iter = disks_.find(disk_info.device_path());
    429     if (iter != disks_.end()) {
    430       delete iter->second;
    431       disks_.erase(iter);
    432       is_new = false;
    433     }
    434     Disk* disk = new Disk(disk_info.device_path(),
    435                           disk_info.mount_path(),
    436                           disk_info.system_path(),
    437                           disk_info.file_path(),
    438                           disk_info.label(),
    439                           disk_info.drive_label(),
    440                           disk_info.vendor_id(),
    441                           disk_info.vendor_name(),
    442                           disk_info.product_id(),
    443                           disk_info.product_name(),
    444                           disk_info.uuid(),
    445                           FindSystemPathPrefix(disk_info.system_path()),
    446                           disk_info.device_type(),
    447                           disk_info.total_size_in_bytes(),
    448                           disk_info.is_drive(),
    449                           disk_info.is_read_only(),
    450                           disk_info.has_media(),
    451                           disk_info.on_boot_device(),
    452                           disk_info.is_hidden());
    453     disks_.insert(std::make_pair(disk_info.device_path(), disk));
    454     NotifyDiskStatusUpdate(is_new ? DISK_ADDED : DISK_CHANGED, disk);
    455   }
    456 
    457   // Callbcak for RequestMountInfo.
    458   void OnRequestMountInfo(const std::vector<std::string>& devices) {
    459     std::set<std::string> current_device_set;
    460     if (!devices.empty()) {
    461       // Initiate properties fetch for all removable disks,
    462       for (size_t i = 0; i < devices.size(); i++) {
    463         current_device_set.insert(devices[i]);
    464         // Initiate disk property retrieval for each relevant device path.
    465         cros_disks_client_->GetDeviceProperties(
    466             devices[i],
    467             base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties,
    468                        weak_ptr_factory_.GetWeakPtr()),
    469             base::Bind(&base::DoNothing));
    470       }
    471     }
    472     // Search and remove disks that are no longer present.
    473     for (DiskMap::iterator iter = disks_.begin(); iter != disks_.end(); ) {
    474       if (current_device_set.find(iter->first) == current_device_set.end()) {
    475         Disk* disk = iter->second;
    476         NotifyDiskStatusUpdate(DISK_REMOVED, disk);
    477         delete iter->second;
    478         disks_.erase(iter++);
    479       } else {
    480         ++iter;
    481       }
    482     }
    483   }
    484 
    485   // Callback to handle mount event signals.
    486   void OnMountEvent(MountEventType event, const std::string& device_path_arg) {
    487     // Take a copy of the argument so we can modify it below.
    488     std::string device_path = device_path_arg;
    489     switch (event) {
    490       case CROS_DISKS_DISK_ADDED: {
    491         cros_disks_client_->GetDeviceProperties(
    492             device_path,
    493             base::Bind(&DiskMountManagerImpl::OnGetDeviceProperties,
    494                        weak_ptr_factory_.GetWeakPtr()),
    495             base::Bind(&base::DoNothing));
    496         break;
    497       }
    498       case CROS_DISKS_DISK_REMOVED: {
    499         // Search and remove disks that are no longer present.
    500         DiskMountManager::DiskMap::iterator iter = disks_.find(device_path);
    501         if (iter != disks_.end()) {
    502           Disk* disk = iter->second;
    503           NotifyDiskStatusUpdate(DISK_REMOVED, disk);
    504           delete iter->second;
    505           disks_.erase(iter);
    506         }
    507         break;
    508       }
    509       case CROS_DISKS_DEVICE_ADDED: {
    510         system_path_prefixes_.insert(device_path);
    511         NotifyDeviceStatusUpdate(DEVICE_ADDED, device_path);
    512         break;
    513       }
    514       case CROS_DISKS_DEVICE_REMOVED: {
    515         system_path_prefixes_.erase(device_path);
    516         NotifyDeviceStatusUpdate(DEVICE_REMOVED, device_path);
    517         break;
    518       }
    519       case CROS_DISKS_DEVICE_SCANNED: {
    520         NotifyDeviceStatusUpdate(DEVICE_SCANNED, device_path);
    521         break;
    522       }
    523       default: {
    524         LOG(ERROR) << "Unknown event: " << event;
    525       }
    526     }
    527   }
    528 
    529   // Notifies all observers about disk status update.
    530   void NotifyDiskStatusUpdate(DiskEvent event,
    531                               const Disk* disk) {
    532     FOR_EACH_OBSERVER(Observer, observers_, OnDiskEvent(event, disk));
    533   }
    534 
    535   // Notifies all observers about device status update.
    536   void NotifyDeviceStatusUpdate(DeviceEvent event,
    537                                 const std::string& device_path) {
    538     FOR_EACH_OBSERVER(Observer, observers_, OnDeviceEvent(event, device_path));
    539   }
    540 
    541   // Notifies all observers about mount completion.
    542   void NotifyMountStatusUpdate(MountEvent event,
    543                                MountError error_code,
    544                                const MountPointInfo& mount_info) {
    545     FOR_EACH_OBSERVER(Observer, observers_,
    546                       OnMountEvent(event, error_code, mount_info));
    547   }
    548 
    549   void NotifyFormatStatusUpdate(FormatEvent event,
    550                                 FormatError error_code,
    551                                 const std::string& device_path) {
    552     FOR_EACH_OBSERVER(Observer, observers_,
    553                       OnFormatEvent(event, error_code, device_path));
    554   }
    555 
    556   // Finds system path prefix from |system_path|.
    557   const std::string& FindSystemPathPrefix(const std::string& system_path) {
    558     if (system_path.empty())
    559       return base::EmptyString();
    560     for (SystemPathPrefixSet::const_iterator it = system_path_prefixes_.begin();
    561          it != system_path_prefixes_.end();
    562          ++it) {
    563       const std::string& prefix = *it;
    564       if (StartsWithASCII(system_path, prefix, true))
    565         return prefix;
    566     }
    567     return base::EmptyString();
    568   }
    569 
    570   // Mount event change observers.
    571   ObserverList<Observer> observers_;
    572 
    573   CrosDisksClient* cros_disks_client_;
    574 
    575   // The list of disks found.
    576   DiskMountManager::DiskMap disks_;
    577 
    578   DiskMountManager::MountPointMap mount_points_;
    579 
    580   typedef std::set<std::string> SystemPathPrefixSet;
    581   SystemPathPrefixSet system_path_prefixes_;
    582 
    583   base::WeakPtrFactory<DiskMountManagerImpl> weak_ptr_factory_;
    584 
    585   DISALLOW_COPY_AND_ASSIGN(DiskMountManagerImpl);
    586 };
    587 
    588 }  // namespace
    589 
    590 DiskMountManager::Disk::Disk(const std::string& device_path,
    591                              const std::string& mount_path,
    592                              const std::string& system_path,
    593                              const std::string& file_path,
    594                              const std::string& device_label,
    595                              const std::string& drive_label,
    596                              const std::string& vendor_id,
    597                              const std::string& vendor_name,
    598                              const std::string& product_id,
    599                              const std::string& product_name,
    600                              const std::string& fs_uuid,
    601                              const std::string& system_path_prefix,
    602                              DeviceType device_type,
    603                              uint64 total_size_in_bytes,
    604                              bool is_parent,
    605                              bool is_read_only,
    606                              bool has_media,
    607                              bool on_boot_device,
    608                              bool is_hidden)
    609     : device_path_(device_path),
    610       mount_path_(mount_path),
    611       system_path_(system_path),
    612       file_path_(file_path),
    613       device_label_(device_label),
    614       drive_label_(drive_label),
    615       vendor_id_(vendor_id),
    616       vendor_name_(vendor_name),
    617       product_id_(product_id),
    618       product_name_(product_name),
    619       fs_uuid_(fs_uuid),
    620       system_path_prefix_(system_path_prefix),
    621       device_type_(device_type),
    622       total_size_in_bytes_(total_size_in_bytes),
    623       is_parent_(is_parent),
    624       is_read_only_(is_read_only),
    625       has_media_(has_media),
    626       on_boot_device_(on_boot_device),
    627       is_hidden_(is_hidden) {
    628 }
    629 
    630 DiskMountManager::Disk::~Disk() {}
    631 
    632 bool DiskMountManager::AddDiskForTest(Disk* disk) {
    633   return false;
    634 }
    635 
    636 bool DiskMountManager::AddMountPointForTest(const MountPointInfo& mount_point) {
    637   return false;
    638 }
    639 
    640 // static
    641 std::string DiskMountManager::MountConditionToString(MountCondition condition) {
    642   switch (condition) {
    643     case MOUNT_CONDITION_NONE:
    644       return "";
    645     case MOUNT_CONDITION_UNKNOWN_FILESYSTEM:
    646       return "unknown_filesystem";
    647     case MOUNT_CONDITION_UNSUPPORTED_FILESYSTEM:
    648       return "unsupported_filesystem";
    649     default:
    650       NOTREACHED();
    651   }
    652   return "";
    653 }
    654 
    655 // static
    656 std::string DiskMountManager::DeviceTypeToString(DeviceType type) {
    657   switch (type) {
    658     case DEVICE_TYPE_USB:
    659       return "usb";
    660     case DEVICE_TYPE_SD:
    661       return "sd";
    662     case DEVICE_TYPE_OPTICAL_DISC:
    663       return "optical";
    664     case DEVICE_TYPE_MOBILE:
    665       return "mobile";
    666     default:
    667       return "unknown";
    668   }
    669 }
    670 
    671 // static
    672 void DiskMountManager::Initialize() {
    673   if (g_disk_mount_manager) {
    674     LOG(WARNING) << "DiskMountManager was already initialized";
    675     return;
    676   }
    677   g_disk_mount_manager = new DiskMountManagerImpl();
    678   VLOG(1) << "DiskMountManager initialized";
    679 }
    680 
    681 // static
    682 void DiskMountManager::InitializeForTesting(
    683     DiskMountManager* disk_mount_manager) {
    684   if (g_disk_mount_manager) {
    685     LOG(WARNING) << "DiskMountManager was already initialized";
    686     return;
    687   }
    688   g_disk_mount_manager = disk_mount_manager;
    689   VLOG(1) << "DiskMountManager initialized";
    690 }
    691 
    692 // static
    693 void DiskMountManager::Shutdown() {
    694   if (!g_disk_mount_manager) {
    695     LOG(WARNING) << "DiskMountManager::Shutdown() called with NULL manager";
    696     return;
    697   }
    698   delete g_disk_mount_manager;
    699   g_disk_mount_manager = NULL;
    700   VLOG(1) << "DiskMountManager Shutdown completed";
    701 }
    702 
    703 // static
    704 DiskMountManager* DiskMountManager::GetInstance() {
    705   return g_disk_mount_manager;
    706 }
    707 
    708 }  // namespace disks
    709 }  // namespace chromeos
    710