OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
Lei Zhang
2012/04/04 05:31:29
Done.
| |
5 #include "content/browser/media_device_notifications_linux.h" | 5 #include "content/browser/media_device_notifications_linux.h" |
6 | 6 |
7 #include <mntent.h> | 7 #include <mntent.h> |
8 #include <stdio.h> | 8 #include <stdio.h> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/file_path.h" | |
11 #include "base/file_util.h" | 12 #include "base/file_util.h" |
12 #include "base/string_util.h" | 13 #include "base/string_util.h" |
13 #include "base/system_monitor/system_monitor.h" | 14 #include "base/system_monitor/system_monitor.h" |
14 #include "content/public/browser/browser_thread.h" | 15 #include "content/public/browser/browser_thread.h" |
15 | 16 |
16 using base::SystemMonitor; | |
17 | |
18 namespace { | 17 namespace { |
19 | 18 |
20 const char* const kDCIMDirName = "DCIM"; | 19 const char kDCIMDirName[] = "DCIM"; |
21 | 20 |
22 // List of file systems we care about. | 21 // List of file systems we care about. |
23 const char* const kKnownFileSystems[] = { | 22 const char* const kKnownFileSystems[] = { |
24 "ext2", | 23 "ext2", |
25 "ext3", | 24 "ext3", |
26 "ext4", | 25 "ext4", |
27 "fat", | 26 "fat", |
28 "hfsplus", | 27 "hfsplus", |
29 "iso9660", | 28 "iso9660", |
30 "msdos", | 29 "msdos", |
31 "ntfs", | 30 "ntfs", |
32 "udf", | 31 "udf", |
33 "vfat", | 32 "vfat", |
34 }; | 33 }; |
35 | 34 |
36 } // namespace | 35 } // namespace |
37 | 36 |
38 namespace content { | 37 namespace content { |
39 | 38 |
39 using base::SystemMonitor; | |
40 | |
41 // A simple pass-through class. MediaDeviceNotificationsLinux cannot directly | |
42 // inherit from FilePathWatcher::Delegate due to multiple inheritance. | |
43 class MediaDeviceNotificationsLinux::WatcherDelegate | |
44 : public base::files::FilePathWatcher::Delegate { | |
45 public: | |
46 explicit WatcherDelegate(MediaDeviceNotificationsLinux* notifier); | |
47 | |
48 // base::files::FilePathWatcher::Delegate implementation. | |
49 virtual void OnFilePathChanged(const FilePath& path) OVERRIDE; | |
50 | |
51 private: | |
52 friend class base::RefCountedThreadSafe<WatcherDelegate>; | |
53 | |
54 // Avoids code deleting the object while there are references to it. | |
55 virtual ~WatcherDelegate(); | |
56 | |
57 // The MediaDeviceNotificationsLinux instance that owns this WatcherDelegate. | |
58 // No need to reference it, as that would create a circular reference. | |
ajl
2012/04/03 23:35:57
What do you mean by "reference" here - are you ref
Lei Zhang
2012/04/04 05:31:29
Done.
| |
59 MediaDeviceNotificationsLinux* notifier_; | |
60 | |
61 DISALLOW_COPY_AND_ASSIGN(WatcherDelegate); | |
62 }; | |
63 | |
64 MediaDeviceNotificationsLinux::WatcherDelegate::WatcherDelegate( | |
65 MediaDeviceNotificationsLinux* notifier) | |
66 : notifier_(notifier) { | |
67 } | |
68 | |
69 MediaDeviceNotificationsLinux::WatcherDelegate::~WatcherDelegate() { | |
70 } | |
71 | |
72 void MediaDeviceNotificationsLinux::WatcherDelegate::OnFilePathChanged( | |
73 const FilePath& path) { | |
74 notifier_->OnFilePathChanged(path); | |
75 } | |
76 | |
40 MediaDeviceNotificationsLinux::MediaDeviceNotificationsLinux( | 77 MediaDeviceNotificationsLinux::MediaDeviceNotificationsLinux( |
41 const FilePath& path) | 78 const FilePath& path) |
42 : initialized_(false), | 79 : initialized_(false), |
43 mtab_path_(path), | 80 mtab_path_(path), |
44 current_device_id_(0U) { | 81 current_device_id_(0U) { |
45 CHECK(!path.empty()); | 82 CHECK(!path.empty()); |
46 | 83 |
47 // Put |kKnownFileSystems| in std::set to get O(log N) access time. | 84 // Put |kKnownFileSystems| in std::set to get O(log N) access time. |
48 for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i) | 85 for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i) { |
49 known_file_systems_.insert(kKnownFileSystems[i]); | 86 known_file_systems_.insert(kKnownFileSystems[i]); |
87 } | |
50 } | 88 } |
51 | 89 |
52 MediaDeviceNotificationsLinux::~MediaDeviceNotificationsLinux() { | 90 MediaDeviceNotificationsLinux::~MediaDeviceNotificationsLinux() { |
53 } | 91 } |
54 | 92 |
55 void MediaDeviceNotificationsLinux::Init() { | 93 void MediaDeviceNotificationsLinux::Init() { |
56 BrowserThread::PostTask( | 94 BrowserThread::PostTask( |
57 BrowserThread::FILE, FROM_HERE, | 95 BrowserThread::FILE, FROM_HERE, |
58 base::Bind(&MediaDeviceNotificationsLinux::InitOnFileThread, this)); | 96 base::Bind(&MediaDeviceNotificationsLinux::InitOnFileThread, this)); |
59 } | 97 } |
60 | 98 |
61 void MediaDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path) { | 99 void MediaDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path) { |
62 if (path != mtab_path_) { | 100 if (path != mtab_path_) { |
101 // This cannot happen unless FileWatcher is buggy. | |
ajl
2012/04/03 23:35:57
Thanks for adding a comment here. I think it woul
Lei Zhang
2012/04/04 05:31:29
Done.
| |
63 NOTREACHED(); | 102 NOTREACHED(); |
64 return; | 103 return; |
65 } | 104 } |
66 | 105 |
67 UpdateMtab(); | 106 UpdateMtab(); |
68 } | 107 } |
69 | 108 |
70 void MediaDeviceNotificationsLinux::InitOnFileThread() { | 109 void MediaDeviceNotificationsLinux::InitOnFileThread() { |
71 DCHECK(!initialized_); | 110 DCHECK(!initialized_); |
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 111 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
(...skipping 11 matching lines...) Expand all Loading... | |
84 void MediaDeviceNotificationsLinux::UpdateMtab() { | 123 void MediaDeviceNotificationsLinux::UpdateMtab() { |
85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
86 | 125 |
87 MountMap new_mtab; | 126 MountMap new_mtab; |
88 ReadMtab(&new_mtab); | 127 ReadMtab(&new_mtab); |
89 | 128 |
90 // Check existing mtab entries for unaccounted mount points. | 129 // Check existing mtab entries for unaccounted mount points. |
91 // These mount points must have been removed in the new mtab. | 130 // These mount points must have been removed in the new mtab. |
92 MountMap::iterator it = mtab_.begin(); | 131 MountMap::iterator it = mtab_.begin(); |
93 while (it != mtab_.end()) { | 132 while (it != mtab_.end()) { |
94 const MountPoint& mount_point(it->first); | 133 const std::string& mount_point = it->first; |
95 // |mount_point| not in |new_mtab|. | 134 // |mount_point| not in |new_mtab|. |
96 if (new_mtab.find(mount_point) == new_mtab.end()) { | 135 if (new_mtab.find(mount_point) == new_mtab.end()) { |
97 const SystemMonitor::DeviceIdType& device_id(it->second.second); | 136 const SystemMonitor::DeviceIdType& device_id = it->second.second; |
98 RemoveOldDevice(device_id); | 137 RemoveOldDevice(device_id); |
99 mtab_.erase(it++); | 138 mtab_.erase(it++); |
Lei Zhang
2012/04/04 05:31:29
Ok, I'll put all the erase() calls in a separate l
| |
100 continue; | 139 continue; |
101 } | 140 } |
102 // Existing mount point. Ignore and deal in the next loop. | 141 // Existing mount point. Ignore and deal in the next loop. |
103 ++it; | 142 ++it; |
104 } | 143 } |
105 | 144 |
106 // Check new mtab entries against existing ones. | 145 // Check new mtab entries against existing ones. |
107 for (MountMap::iterator newiter = new_mtab.begin(); | 146 for (MountMap::iterator newiter = new_mtab.begin(); |
108 newiter != new_mtab.end(); | 147 newiter != new_mtab.end(); |
109 ++newiter) { | 148 ++newiter) { |
110 const MountPoint& mount_point(newiter->first); | 149 const std::string& mount_point = newiter->first; |
111 const MountDeviceAndId& mount_device_and_id(newiter->second); | 150 const MountDeviceAndId& mount_device_and_id = newiter->second; |
112 const MountDevice& mount_device(newiter->second.first); | 151 const std::string& mount_device = mount_device_and_id.first; |
113 SystemMonitor::DeviceIdType& id(newiter->second.second); | 152 SystemMonitor::DeviceIdType& id = newiter->second.second; |
114 MountMap::iterator olditer = mtab_.find(mount_point); | 153 MountMap::iterator olditer = mtab_.find(mount_point); |
115 // Check to see if it is a new mount point. | 154 // Check to see if it is a new mount point. |
116 if (olditer == mtab_.end()) { | 155 if (olditer == mtab_.end()) { |
117 if (IsMediaDevice(mount_point)) { | 156 if (IsMediaDevice(mount_point)) { |
118 AddNewDevice(mount_device, mount_point, &id); | 157 AddNewDevice(mount_device, mount_point, &id); |
119 mtab_[mount_point] = mount_device_and_id; | 158 mtab_.insert(std::make_pair(mount_point, mount_device_and_id)); |
120 } | 159 } |
121 continue; | 160 continue; |
122 } | 161 } |
123 | 162 |
124 // Existing mount point. Check to see if a new device is mounted there. | 163 // Existing mount point. Check to see if a new device is mounted there. |
125 MountDeviceAndId& old_mount_device_and_id(olditer->second); | 164 MountDeviceAndId& old_mount_device_and_id = olditer->second; |
126 if (mount_device == old_mount_device_and_id.first) | 165 if (mount_device == old_mount_device_and_id.first) |
127 continue; | 166 continue; |
128 | 167 |
129 // New device mounted. | 168 // New device mounted. |
130 RemoveOldDevice(old_mount_device_and_id.second); | 169 RemoveOldDevice(old_mount_device_and_id.second); |
131 if (IsMediaDevice(mount_point)) { | 170 if (IsMediaDevice(mount_point)) { |
132 AddNewDevice(mount_device, mount_point, &id); | 171 AddNewDevice(mount_device, mount_point, &id); |
133 olditer->second = mount_device_and_id; | 172 olditer->second = mount_device_and_id; |
134 } | 173 } |
135 } | 174 } |
136 } | 175 } |
137 | 176 |
138 void MediaDeviceNotificationsLinux::ReadMtab(MountMap* mtab) { | 177 void MediaDeviceNotificationsLinux::ReadMtab(MountMap* mtab) { |
139 FILE* fp = setmntent(mtab_path_.value().c_str(), "r"); | 178 FILE* fp = setmntent(mtab_path_.value().c_str(), "r"); |
140 if (!fp) | 179 if (!fp) |
141 return; | 180 return; |
142 | 181 |
143 MountMap& new_mtab = *mtab; | 182 MountMap& new_mtab = *mtab; |
144 struct mntent entry; | 183 mntent entry; |
145 char buf[512]; | 184 char buf[512]; |
146 SystemMonitor::DeviceIdType mount_position = 0; | 185 SystemMonitor::DeviceIdType mount_position = 0; |
147 typedef std::pair<MountPoint, SystemMonitor::DeviceIdType> MountPointAndId; | 186 typedef std::pair<std::string, SystemMonitor::DeviceIdType> MountPointAndId; |
148 typedef std::map<MountDevice, MountPointAndId> DeviceMap; | 187 typedef std::map<std::string, MountPointAndId> DeviceMap; |
149 DeviceMap device_map; | 188 DeviceMap device_map; |
150 while (getmntent_r(fp, &entry, buf, sizeof(buf))) { | 189 while (getmntent_r(fp, &entry, buf, sizeof(buf))) { |
151 // We only care about real file systems. | 190 // We only care about real file systems. |
152 if (known_file_systems_.find(entry.mnt_type) == known_file_systems_.end()) | 191 if (known_file_systems_.find(entry.mnt_type) == known_file_systems_.end()) |
153 continue; | 192 continue; |
154 // Add entries, but overwrite entries for the same mount device. Keep track | 193 // Add entries, but overwrite entries for the same mount device. Keep track |
155 // of the entry positions in the device id field and use that below to | 194 // of the entry positions in the device id field and use that below to |
156 // resolve multiple devices mounted at the same mount point. | 195 // resolve multiple devices mounted at the same mount point. |
157 device_map[entry.mnt_fsname] = | 196 device_map[entry.mnt_fsname] = |
ajl
2012/04/03 23:35:57
Here is another place where it looks like you coul
Lei Zhang
2012/04/04 05:31:29
Done. I believe this is the only other one.
| |
158 std::make_pair(entry.mnt_dir, mount_position++); | 197 std::make_pair(entry.mnt_dir, mount_position++); |
159 } | 198 } |
160 endmntent(fp); | 199 endmntent(fp); |
161 | 200 |
162 for (DeviceMap::iterator device_it = device_map.begin(); | 201 for (DeviceMap::iterator device_it = device_map.begin(); |
163 device_it != device_map.end(); | 202 device_it != device_map.end(); |
164 ++device_it) { | 203 ++device_it) { |
165 const MountDevice& device = device_it->first; | 204 const std::string& device = device_it->first; |
166 const MountPoint& mount_point = device_it->second.first; | 205 const std::string& mount_point = device_it->second.first; |
167 const SystemMonitor::DeviceIdType& position = device_it->second.second; | 206 const SystemMonitor::DeviceIdType& position = device_it->second.second; |
168 | 207 |
169 // No device at |mount_point|, save |device| to it. | 208 // No device at |mount_point|, save |device| to it. |
170 MountMap::iterator mount_it = new_mtab.find(mount_point); | 209 MountMap::iterator mount_it = new_mtab.find(mount_point); |
171 if (mount_it == new_mtab.end()) { | 210 if (mount_it == new_mtab.end()) { |
172 new_mtab[mount_point] = std::make_pair(device, position); | 211 new_mtab.insert(std::make_pair(mount_point, |
212 std::make_pair(device, position))); | |
173 continue; | 213 continue; |
174 } | 214 } |
175 | 215 |
176 // There is already a device mounted at |mount_point|. Check to see if | 216 // There is already a device mounted at |mount_point|. Check to see if |
177 // the existing mount entry is newer than the current one. | 217 // the existing mount entry is newer than the current one. |
178 MountDevice& existing_device = mount_it->second.first; | 218 std::string& existing_device = mount_it->second.first; |
179 SystemMonitor::DeviceIdType& existing_position = mount_it->second.second; | 219 SystemMonitor::DeviceIdType& existing_position = mount_it->second.second; |
180 if (existing_position > position) | 220 if (existing_position > position) |
181 continue; | 221 continue; |
182 | 222 |
183 // The current entry is newer, update the mount point entry. | 223 // The current entry is newer, update the mount point entry. |
184 existing_device = device; | 224 existing_device = device; |
185 existing_position = position; | 225 existing_position = position; |
186 } | 226 } |
187 } | 227 } |
188 | 228 |
189 bool MediaDeviceNotificationsLinux::IsMediaDevice( | 229 bool MediaDeviceNotificationsLinux::IsMediaDevice( |
190 const MountPoint& mount_point) { | 230 const std::string& mount_point) { |
191 FilePath dcim_path(mount_point); | 231 FilePath dcim_path(mount_point); |
192 FilePath::StringType dcim_dir(kDCIMDirName); | 232 FilePath::StringType dcim_dir = kDCIMDirName; |
193 if (!file_util::DirectoryExists(dcim_path.Append(dcim_dir))) { | 233 if (!file_util::DirectoryExists(dcim_path.Append(dcim_dir))) { |
194 // Check for lowercase 'dcim' as well. | 234 // Check for lowercase 'dcim' as well. |
195 FilePath dcim_path_lower(dcim_path.Append(StringToLowerASCII(dcim_dir))); | 235 FilePath dcim_path_lower(dcim_path.Append(StringToLowerASCII(dcim_dir))); |
196 if (!file_util::DirectoryExists(dcim_path_lower)) { | 236 if (!file_util::DirectoryExists(dcim_path_lower)) { |
197 return false; | 237 return false; |
198 } | 238 } |
199 } | 239 } |
200 return true; | 240 return true; |
201 } | 241 } |
202 | 242 |
203 void MediaDeviceNotificationsLinux::AddNewDevice( | 243 void MediaDeviceNotificationsLinux::AddNewDevice( |
204 const MountDevice& mount_device, | 244 const std::string& mount_device, |
205 const MountPoint& mount_point, | 245 const std::string& mount_point, |
206 base::SystemMonitor::DeviceIdType* device_id) { | 246 base::SystemMonitor::DeviceIdType* device_id) { |
207 *device_id = current_device_id_++; | 247 *device_id = current_device_id_++; |
208 base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); | 248 base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); |
209 system_monitor->ProcessMediaDeviceAttached(*device_id, | 249 system_monitor->ProcessMediaDeviceAttached(*device_id, |
210 mount_device, | 250 mount_device, |
211 FilePath(mount_point)); | 251 FilePath(mount_point)); |
212 } | 252 } |
213 | 253 |
214 void MediaDeviceNotificationsLinux::RemoveOldDevice( | 254 void MediaDeviceNotificationsLinux::RemoveOldDevice( |
215 const base::SystemMonitor::DeviceIdType& device_id) { | 255 const base::SystemMonitor::DeviceIdType& device_id) { |
216 base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); | 256 base::SystemMonitor* system_monitor = base::SystemMonitor::Get(); |
217 system_monitor->ProcessMediaDeviceDetached(device_id); | 257 system_monitor->ProcessMediaDeviceDetached(device_id); |
218 } | 258 } |
219 | 259 |
220 MediaDeviceNotificationsLinux::WatcherDelegate::WatcherDelegate( | |
221 MediaDeviceNotificationsLinux* notifier) | |
222 : notifier_(notifier) { | |
223 } | |
224 | |
225 MediaDeviceNotificationsLinux::WatcherDelegate::~WatcherDelegate() { | |
226 } | |
227 | |
228 void MediaDeviceNotificationsLinux::WatcherDelegate::OnFilePathChanged( | |
229 const FilePath& path) { | |
230 notifier_->OnFilePathChanged(path); | |
231 } | |
232 | |
233 } // namespace content | 260 } // namespace content |
OLD | NEW |