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