OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 |
5 #include "chrome/browser/media_galleries/media_scan_manager.h" | 5 #include "chrome/browser/media_galleries/media_scan_manager.h" |
6 | 6 |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/files/file_enumerator.h" | 8 #include "base/files/file_enumerator.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
203 MediaGalleryPrefInfo::kScanResult, | 203 MediaGalleryPrefInfo::kScanResult, |
204 gallery.volume_label, gallery.vendor_name, | 204 gallery.volume_label, gallery.vendor_name, |
205 gallery.model_name, gallery.total_size_in_bytes, | 205 gallery.model_name, gallery.total_size_in_bytes, |
206 gallery.last_attach_time, file_counts.audio_count, | 206 gallery.last_attach_time, file_counts.audio_count, |
207 file_counts.image_count, file_counts.video_count); | 207 file_counts.image_count, file_counts.video_count); |
208 } | 208 } |
209 UMA_HISTOGRAM_COUNTS_10000("MediaGalleries.ScanGalleriesPopulated", | 209 UMA_HISTOGRAM_COUNTS_10000("MediaGalleries.ScanGalleriesPopulated", |
210 unique_found_folders.size() + to_update.size()); | 210 unique_found_folders.size() + to_update.size()); |
211 } | 211 } |
212 | 212 |
213 struct ContainerCount { | |
214 int seen_count, entries_count; | |
215 bool has_parent; | |
216 | |
217 ContainerCount() | |
218 :seen_count(0), entries_count(-1), has_parent(false) {} | |
vandebo (ex-Chrome)
2014/05/21 15:55:09
nit: previous line, and ": "
Kevin Bailey
2014/05/21 17:29:36
Done.
| |
219 }; | |
220 | |
213 // A single directory may contain many folders with media in them, without | 221 // A single directory may contain many folders with media in them, without |
214 // containing any media itself. In fact, the primary purpose of that directory | 222 // containing any media itself. In fact, the primary purpose of that directory |
215 // may be to contain media directories. This function tries to find those | 223 // may be to contain media directories. This function tries to find those |
216 // immediate container directories. | 224 // container directories. |
217 MediaFolderFinder::MediaFolderFinderResults FindContainerScanResults( | 225 MediaFolderFinder::MediaFolderFinderResults FindContainerScanResults( |
218 const MediaFolderFinder::MediaFolderFinderResults& found_folders, | 226 const MediaFolderFinder::MediaFolderFinderResults& found_folders, |
219 const std::vector<base::FilePath>& sensitive_locations) { | 227 const std::vector<base::FilePath>& sensitive_locations) { |
220 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); | 228 DCHECK_CURRENTLY_ON(content::BrowserThread::FILE); |
221 std::vector<base::FilePath> abs_sensitive_locations; | 229 std::vector<base::FilePath> abs_sensitive_locations; |
222 for (size_t i = 0; i < sensitive_locations.size(); ++i) { | 230 for (size_t i = 0; i < sensitive_locations.size(); ++i) { |
223 base::FilePath path = base::MakeAbsoluteFilePath(sensitive_locations[i]); | 231 base::FilePath path = base::MakeAbsoluteFilePath(sensitive_locations[i]); |
224 if (!path.empty()) | 232 if (!path.empty()) |
225 abs_sensitive_locations.push_back(path); | 233 abs_sensitive_locations.push_back(path); |
226 } | 234 } |
227 // Count the number of scan results with the same parent directory. | 235 // Find parent directories with majority of media directories, |
228 typedef std::map<base::FilePath, int /*count*/> ContainerCandidates; | 236 // or container directories. |
237 // |candidates| keeps track of directories which might have enough | |
238 // media directories to have us return them. | |
239 typedef std::map<base::FilePath, ContainerCount> ContainerCandidates; | |
229 ContainerCandidates candidates; | 240 ContainerCandidates candidates; |
230 for (MediaFolderFinder::MediaFolderFinderResults::const_iterator it = | 241 // |candidates_to_check| are members of |candidates| that have crossed |
231 found_folders.begin(); it != found_folders.end(); ++it) { | 242 // threshold to be returned, and whose parents should likewise be checked. |
vandebo (ex-Chrome)
2014/05/21 15:55:09
nit: "...and whose parents still need to be checke
Kevin Bailey
2014/05/21 17:29:36
I was really trying to say that we would recur on
| |
232 base::FilePath parent_directory = it->first.DirName(); | 243 std::set<base::FilePath> candidates_to_check; |
244 MediaFolderFinder::MediaFolderFinderResults::const_iterator folder_it = | |
245 found_folders.begin(); | |
246 while (folder_it != found_folders.end() && !candidates_to_check.empty()) { | |
247 base::FilePath candidate; | |
248 // Go through incoming |found_folders| first, then discovered candidates. | |
249 if (folder_it != found_folders.end()) { | |
250 candidate = folder_it->first; | |
251 ++folder_it; | |
252 } else { | |
253 candidate = *candidates_to_check.begin(); | |
254 // Remove in case it gets added back. | |
255 candidates_to_check.erase(candidates_to_check.begin()); | |
256 } | |
257 base::FilePath parent_directory = candidate.DirName(); | |
233 | 258 |
234 // Skip sensitive folders and their ancestors. | 259 // Skip sensitive folders and their ancestors. |
235 bool is_sensitive = false; | 260 bool is_sensitive = false; |
236 base::FilePath abs_parent_directory = | 261 base::FilePath abs_parent_directory = |
237 base::MakeAbsoluteFilePath(parent_directory); | 262 base::MakeAbsoluteFilePath(parent_directory); |
238 if (abs_parent_directory.empty()) | 263 if (abs_parent_directory.empty()) { |
264 candidates.erase(candidates.find(candidate)); | |
vandebo (ex-Chrome)
2014/05/21 15:55:09
Not needed - you only add to candidates after this
Kevin Bailey
2014/05/21 17:29:36
I think this one was left-over but the next one is
| |
239 continue; | 265 continue; |
266 } | |
240 for (size_t i = 0; i < abs_sensitive_locations.size(); ++i) { | 267 for (size_t i = 0; i < abs_sensitive_locations.size(); ++i) { |
241 if (abs_parent_directory == abs_sensitive_locations[i] || | 268 if (abs_parent_directory == abs_sensitive_locations[i] || |
242 abs_parent_directory.IsParent(abs_sensitive_locations[i])) { | 269 abs_parent_directory.IsParent(abs_sensitive_locations[i])) { |
243 is_sensitive = true; | 270 is_sensitive = true; |
244 continue; | 271 break; |
245 } | 272 } |
246 } | 273 } |
247 if (is_sensitive) | 274 if (is_sensitive) { |
275 candidates.erase(candidates.find(candidate)); | |
vandebo (ex-Chrome)
2014/05/21 15:55:09
ditto
Kevin Bailey
2014/05/21 17:29:36
I don't think so. Consider:
A/
sensitive/
B/
vandebo (ex-Chrome)
2014/05/21 19:21:00
Please walk be through it if I'm missing something
Kevin Bailey
2014/05/21 20:17:38
Recall that a directory itself need not be sensiti
vandebo (ex-Chrome)
2014/05/22 17:35:51
Won't that check on 269 prevent A from ever being
Kevin Bailey
2014/05/27 14:50:13
Done.
| |
248 continue; | 276 continue; |
249 | 277 } |
250 ContainerCandidates::iterator existing = candidates.find(parent_directory); | 278 // Don't bother with ones we already have. |
251 if (existing == candidates.end()) { | 279 if (found_folders.find(parent_directory) != found_folders.end()) |
252 candidates[parent_directory] = 1; | 280 continue; |
253 } else { | 281 ContainerCandidates::iterator parent_it = candidates.find(parent_directory); |
254 existing->second++; | 282 if (parent_it == candidates.end()) { |
283 candidates[parent_directory].seen_count = 1; | |
284 continue; | |
285 } | |
286 parent_it->second.seen_count++; | |
vandebo (ex-Chrome)
2014/05/21 15:55:09
If you like, use ContainerCount* parent_counts = &
Kevin Bailey
2014/05/21 17:29:36
Done.
| |
287 // If a parent directory has more than one scan result, consider it. | |
288 // If we haven't scanned it yet, do so. | |
289 if (parent_it->second.entries_count == -1) { | |
290 base::FileEnumerator dir_counter(parent_it->first, false /*recursive*/, | |
vandebo (ex-Chrome)
2014/05/21 15:55:09
parent_it->first => parent_directory
Kevin Bailey
2014/05/21 17:29:36
Done.
| |
291 base::FileEnumerator::DIRECTORIES); | |
292 base::FileEnumerator::FileInfo info; | |
293 int count = 0; | |
vandebo (ex-Chrome)
2014/05/21 15:55:09
nit: you could use parent_it->second.entries_count
Kevin Bailey
2014/05/21 17:29:36
I generally prefer to write in an exception safe s
| |
294 for (base::FilePath name = dir_counter.Next(); | |
295 !name.empty(); | |
296 name = dir_counter.Next()) { | |
297 if (!base::IsLink(name)) | |
298 count++; | |
299 } | |
300 parent_it->second.entries_count = count; | |
301 } | |
302 if (parent_it->second.seen_count * 100 / parent_it->second.entries_count | |
303 >= kContainerDirectoryMinimumPercent) { | |
304 // We're keeping this parent. Mark immediate children for exclusion. | |
305 for (ContainerCandidates::iterator child_it = candidates.begin(); | |
306 child_it != candidates.end(); ++child_it) { | |
307 if (child_it != parent_it && | |
308 child_it->first.DirName() == parent_it->first) { | |
vandebo (ex-Chrome)
2014/05/21 15:55:09
parent_it->first => parent_directory
Kevin Bailey
2014/05/21 17:29:36
Done.
| |
309 child_it->second.has_parent = true; | |
310 } | |
311 } | |
312 // It's a qualified candidate now. | |
313 candidates_to_check.insert(parent_it->first); | |
vandebo (ex-Chrome)
2014/05/21 15:55:09
parent_it->first => parent_directory
Kevin Bailey
2014/05/21 17:29:36
Done.
| |
255 } | 314 } |
256 } | 315 } |
257 | |
258 // If a parent directory has more than one scan result, consider it. | |
259 MediaFolderFinder::MediaFolderFinderResults result; | 316 MediaFolderFinder::MediaFolderFinderResults result; |
317 // Copy and return worthy results. | |
260 for (ContainerCandidates::const_iterator it = candidates.begin(); | 318 for (ContainerCandidates::const_iterator it = candidates.begin(); |
261 it != candidates.end(); | 319 it != candidates.end(); ++it) { |
262 ++it) { | 320 if (it->second.seen_count > 1 && it->second.seen_count * 100 / |
vandebo (ex-Chrome)
2014/05/21 15:55:09
Instead of duplicating the criteria here would it
Kevin Bailey
2014/05/21 17:29:36
Sure, swapping it for |has_parent| is free.
| |
263 if (it->second <= 1) | 321 it->second.entries_count >= kContainerDirectoryMinimumPercent && |
264 continue; | 322 !it->second.has_parent) { |
265 | 323 result[it->first] = MediaGalleryScanResult(); |
266 base::FileEnumerator dir_counter(it->first, false /*recursive*/, | |
267 base::FileEnumerator::DIRECTORIES); | |
268 base::FileEnumerator::FileInfo info; | |
269 int count = 0; | |
270 for (base::FilePath name = dir_counter.Next(); | |
271 !name.empty(); | |
272 name = dir_counter.Next()) { | |
273 if (!base::IsLink(name)) | |
274 count++; | |
275 } | 324 } |
276 if (it->second * 100 / count >= kContainerDirectoryMinimumPercent) | |
277 result[it->first] = MediaGalleryScanResult(); | |
278 } | 325 } |
279 return result; | 326 return result; |
280 } | 327 } |
281 | 328 |
282 int CountScanResultsForExtension(MediaGalleriesPreferences* preferences, | 329 int CountScanResultsForExtension(MediaGalleriesPreferences* preferences, |
283 const extensions::Extension* extension, | 330 const extensions::Extension* extension, |
284 MediaGalleryScanResult* file_counts) { | 331 MediaGalleryScanResult* file_counts) { |
285 int gallery_count = 0; | 332 int gallery_count = 0; |
286 | 333 |
287 MediaGalleryPrefIdSet permitted_galleries = | 334 MediaGalleryPrefIdSet permitted_galleries = |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
508 gallery_count, | 555 gallery_count, |
509 file_counts); | 556 file_counts); |
510 } | 557 } |
511 } | 558 } |
512 scanning_extensions->clear(); | 559 scanning_extensions->clear(); |
513 preferences->SetLastScanCompletionTime(base::Time::Now()); | 560 preferences->SetLastScanCompletionTime(base::Time::Now()); |
514 } | 561 } |
515 scoped_extension_registry_observer_.RemoveAll(); | 562 scoped_extension_registry_observer_.RemoveAll(); |
516 folder_finder_.reset(); | 563 folder_finder_.reset(); |
517 } | 564 } |
OLD | NEW |