1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file. 4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h" 6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <string.h> 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h" 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "base/win/windows_version.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace base { 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// FileEnumerator::FileInfo ---------------------------------------------------- 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::FileInfo::FileInfo() { 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) memset(&find_data_, 0, sizeof(find_data_)); 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FileEnumerator::FileInfo::IsDirectory() const { 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FilePath FileEnumerator::FileInfo::GetName() const { 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return FilePath(find_data_.cFileName); 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)int64 FileEnumerator::FileInfo::GetSize() const { 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ULARGE_INTEGER size; 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) size.HighPart = find_data_.nFileSizeHigh; 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) size.LowPart = find_data_.nFileSizeLow; 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK_LE(size.QuadPart, std::numeric_limits<int64>::max()); 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return static_cast<int64>(size.QuadPart); 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const { 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return base::Time::FromFileTime(find_data_.ftLastWriteTime); 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// FileEnumerator -------------------------------------------------------------- 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::FileEnumerator(const FilePath& root_path, 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool recursive, 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int file_type) 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : recursive_(recursive), 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) file_type_(file_type), 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) has_find_data_(false), 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) find_handle_(INVALID_HANDLE_VALUE) { 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // INCLUDE_DOT_DOT must not be specified if recursive. 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) memset(&find_data_, 0, sizeof(find_data_)); 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pending_paths_.push(root_path); 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::FileEnumerator(const FilePath& root_path, 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool recursive, 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int file_type, 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const FilePath::StringType& pattern) 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : recursive_(recursive), 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) file_type_(file_type), 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) has_find_data_(false), 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pattern_(pattern), 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) find_handle_(INVALID_HANDLE_VALUE) { 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // INCLUDE_DOT_DOT must not be specified if recursive. 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) memset(&find_data_, 0, sizeof(find_data_)); 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pending_paths_.push(root_path); 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::~FileEnumerator() { 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (find_handle_ != INVALID_HANDLE_VALUE) 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FindClose(find_handle_); 74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::FileInfo FileEnumerator::GetInfo() const { 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!has_find_data_) { 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) NOTREACHED(); 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return FileInfo(); 80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FileInfo ret; 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) memcpy(&ret.find_data_, &find_data_, sizeof(find_data_)); 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return ret; 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FilePath FileEnumerator::Next() { 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) while (has_find_data_ || !pending_paths_.empty()) { 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!has_find_data_) { 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // The last find FindFirstFile operation is done, prepare a new one. 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) root_path_ = pending_paths_.top(); 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pending_paths_.pop(); 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Start a new find operation. 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FilePath src = root_path_; 97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (pattern_.empty()) 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) src = src.Append(L"*"); // No pattern = match everything. 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) else 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) src = src.Append(pattern_); 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 1031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (base::win::GetVersion() >= base::win::VERSION_WIN7) { 1041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Use a "large fetch" on newer Windows which should speed up large 1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // enumerations (we seldom abort in the middle). 1061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) find_handle_ = FindFirstFileEx(src.value().c_str(), 1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) FindExInfoBasic, // Omit short name. 1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) &find_data_, 1091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) FindExSearchNameMatch, 1101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) NULL, 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) FIND_FIRST_EX_LARGE_FETCH); 1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } else { 1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) find_handle_ = FindFirstFile(src.value().c_str(), &find_data_); 1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) has_find_data_ = true; 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else { 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Search for the next file/directory. 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!FindNextFile(find_handle_, &find_data_)) { 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FindClose(find_handle_); 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) find_handle_ = INVALID_HANDLE_VALUE; 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (INVALID_HANDLE_VALUE == find_handle_) { 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) has_find_data_ = false; 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // This is reached when we have finished a directory and are advancing to 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // the next one in the queue. We applied the pattern (if any) to the files 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // in the root search directory, but for those directories which were 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // matched, we want to enumerate all files inside them. This will happen 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // when the handle is empty. 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pattern_ = FilePath::StringType(); 133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FilePath cur_file(find_data_.cFileName); 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ShouldSkip(cur_file)) 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Construct the absolute filename. 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) cur_file = root_path_.Append(find_data_.cFileName); 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (recursive_) { 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // If |cur_file| is a directory, and we are doing recursive searching, 147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // add it to pending_paths_ so we scan it after we finish scanning this 1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // directory. However, don't do recursion through reparse points or we 1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) // may end up with an infinite cycle. 1503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (!(find_data_.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) 1513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) pending_paths_.push(cur_file); 152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (file_type_ & FileEnumerator::DIRECTORIES) 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return cur_file; 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } else if (file_type_ & FileEnumerator::FILES) { 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return cur_file; 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return FilePath(); 161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace base 164