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