1 // Copyright 2014 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 // StorageMonitorLinux processes mount point change events, notifies listeners
6 // about the addition and deletion of media devices, and answers queries about
7 // mounted devices. StorageMonitorLinux uses a MtabWatcherLinux on a separate
8 // background sequence that is file IO capable.
9 
10 #ifndef COMPONENTS_STORAGE_MONITOR_STORAGE_MONITOR_LINUX_H_
11 #define COMPONENTS_STORAGE_MONITOR_STORAGE_MONITOR_LINUX_H_
12 
13 #if defined(OS_CHROMEOS)
14 #error "Use the ChromeOS-specific implementation instead."
15 #endif
16 
17 #include <map>
18 #include <memory>
19 #include <string>
20 
21 #include "base/compiler_specific.h"
22 #include "base/files/file_path.h"
23 #include "base/files/file_path_watcher.h"
24 #include "base/macros.h"
25 #include "base/memory/ref_counted.h"
26 #include "base/memory/weak_ptr.h"
27 #include "base/sequence_checker.h"
28 #include "build/build_config.h"
29 #include "components/storage_monitor/mtab_watcher_linux.h"
30 #include "components/storage_monitor/storage_monitor.h"
31 
32 namespace base {
33 class SequencedTaskRunner;
34 }
35 
36 namespace storage_monitor {
37 
38 class StorageMonitorLinux : public StorageMonitor {
39  public:
40   // Should only be called by browser start up code.
41   // Use StorageMonitor::GetInstance() instead.
42   // |mtab_file_path| is the path to a mtab file to watch for mount points.
43   explicit StorageMonitorLinux(const base::FilePath& mtab_file_path);
44   ~StorageMonitorLinux() override;
45 
46   // Must be called for StorageMonitorLinux to work.
47   void Init() override;
48 
49  protected:
50   // Gets device information given a |device_path| and |mount_point|.
51   using GetDeviceInfoCallback =
52       base::RepeatingCallback<std::unique_ptr<StorageInfo>(
53           const base::FilePath& device_path,
54           const base::FilePath& mount_point)>;
55 
56   void SetGetDeviceInfoCallbackForTest(
57       const GetDeviceInfoCallback& get_device_info_callback);
58 
59   // Parses |new_mtab| and find all changes.
60   virtual void UpdateMtab(
61       const MtabWatcherLinux::MountPointDeviceMap& new_mtab);
62 
63  private:
64   // Structure to save mounted device information such as device path, unique
65   // identifier, device name and partition size.
66   struct MountPointInfo {
67     base::FilePath mount_device;
68     StorageInfo storage_info;
69   };
70 
71   // Mapping of mount points to MountPointInfo.
72   using MountMap = std::map<base::FilePath, MountPointInfo>;
73 
74   // (mount point, priority)
75   // For devices that are mounted to multiple mount points, this helps us track
76   // which one we've notified system monitor about.
77   using ReferencedMountPoint = std::map<base::FilePath, bool>;
78 
79   // (mount device, map of known mount points)
80   // For each mount device, track the places it is mounted and which one (if
81   // any) we have notified system monitor about.
82   using MountPriorityMap = std::map<base::FilePath, ReferencedMountPoint>;
83 
84   // StorageMonitor implementation.
85   bool GetStorageInfoForPath(const base::FilePath& path,
86                              StorageInfo* device_info) const override;
87   void EjectDevice(const std::string& device_id,
88                    base::OnceCallback<void(EjectStatus)> callback) override;
89 
90   // Called when the MtabWatcher has been created.
91   void OnMtabWatcherCreated(std::unique_ptr<MtabWatcherLinux> watcher);
92 
93   bool IsDeviceAlreadyMounted(const base::FilePath& mount_device) const;
94 
95   // Assuming |mount_device| is already mounted, and it gets mounted again at
96   // |mount_point|, update the mappings.
97   void HandleDeviceMountedMultipleTimes(const base::FilePath& mount_device,
98                                         const base::FilePath& mount_point);
99 
100   // Adds |mount_device| to the mappings and notify listeners, if any.
101   void AddNewMount(const base::FilePath& mount_device,
102                    std::unique_ptr<StorageInfo> storage_info);
103 
104   // Mtab file that lists the mount points.
105   const base::FilePath mtab_path_;
106 
107   // Callback to get device information. Set this to a custom callback for
108   // testing.
109   GetDeviceInfoCallback get_device_info_callback_;
110 
111   // Mapping of relevant mount points and their corresponding mount devices.
112   // Keep in mind on Linux, a device can be mounted at multiple mount points,
113   // and multiple devices can be mounted at a mount point.
114   MountMap mount_info_map_;
115 
116   // Because a device can be mounted to multiple places, we only want to
117   // notify about one of them. If (and only if) that one is unmounted, we need
118   // to notify about it's departure and notify about another one of it's mount
119   // points.
120   MountPriorityMap mount_priority_map_;
121 
122   // Must be created and destroyed on |mtab_watcher_task_runner_|.
123   std::unique_ptr<MtabWatcherLinux> mtab_watcher_;
124 
125   scoped_refptr<base::SequencedTaskRunner> mtab_watcher_task_runner_;
126 
127   SEQUENCE_CHECKER(sequence_checker_);
128 
129   base::WeakPtrFactory<StorageMonitorLinux> weak_ptr_factory_{this};
130 
131   DISALLOW_COPY_AND_ASSIGN(StorageMonitorLinux);
132 };
133 
134 }  // namespace storage_monitor
135 
136 #endif  // COMPONENTS_STORAGE_MONITOR_STORAGE_MONITOR_LINUX_H_
137