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 <dirent.h> 8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <errno.h> 9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <fnmatch.h> 10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h" 12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/threading/thread_restrictions.h" 13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace base { 15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// FileEnumerator::FileInfo ---------------------------------------------------- 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::FileInfo::FileInfo() { 19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) memset(&stat_, 0, sizeof(stat_)); 20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FileEnumerator::FileInfo::IsDirectory() const { 23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return S_ISDIR(stat_.st_mode); 24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FilePath FileEnumerator::FileInfo::GetName() const { 27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return filename_; 28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)int64 FileEnumerator::FileInfo::GetSize() const { 31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return stat_.st_size; 32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const { 35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return base::Time::FromTimeT(stat_.st_mtime); 36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// FileEnumerator -------------------------------------------------------------- 39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::FileEnumerator(const FilePath& root_path, 41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool recursive, 42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int file_type) 43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : current_directory_entry_(0), 44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) root_path_(root_path), 45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) recursive_(recursive), 46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) file_type_(file_type) { 47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // INCLUDE_DOT_DOT must not be specified if recursive. 48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); 49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pending_paths_.push(root_path); 50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::FileEnumerator(const FilePath& root_path, 53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) bool recursive, 54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int file_type, 55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const FilePath::StringType& pattern) 56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) : current_directory_entry_(0), 57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) root_path_(root_path), 58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) recursive_(recursive), 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) file_type_(file_type), 60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pattern_(root_path.Append(pattern).value()) { 61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // INCLUDE_DOT_DOT must not be specified if recursive. 62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); 63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // The Windows version of this code appends the pattern to the root_path, 64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // potentially only matching against items in the top-most directory. 65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Do the same here. 66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (pattern.empty()) 67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pattern_ = FilePath::StringType(); 68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pending_paths_.push(root_path); 69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::~FileEnumerator() { 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FilePath FileEnumerator::Next() { 75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ++current_directory_entry_; 76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // While we've exhausted the entries in the current directory, do the next 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) while (current_directory_entry_ >= directory_entries_.size()) { 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (pending_paths_.empty()) 80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return FilePath(); 81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) root_path_ = pending_paths_.top(); 83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) root_path_ = root_path_.StripTrailingSeparators(); 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pending_paths_.pop(); 85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) std::vector<FileInfo> entries; 87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS)) 88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) directory_entries_.clear(); 91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) current_directory_entry_ = 0; 92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) for (std::vector<FileInfo>::const_iterator i = entries.begin(); 93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) i != entries.end(); ++i) { 94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FilePath full_path = root_path_.Append(i->filename_); 95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ShouldSkip(full_path)) 96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (pattern_.size() && 99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE)) 100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) continue; 101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (recursive_ && S_ISDIR(i->stat_.st_mode)) 103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) pending_paths_.push(full_path); 104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if ((S_ISDIR(i->stat_.st_mode) && (file_type_ & DIRECTORIES)) || 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) (!S_ISDIR(i->stat_.st_mode) && (file_type_ & FILES))) 107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) directory_entries_.push_back(*i); 108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return root_path_.Append( 112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) directory_entries_[current_directory_entry_].filename_); 113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)FileEnumerator::FileInfo FileEnumerator::GetInfo() const { 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return directory_entries_[current_directory_entry_]; 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)bool FileEnumerator::ReadDirectory(std::vector<FileInfo>* entries, 120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const FilePath& source, bool show_links) { 121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) base::ThreadRestrictions::AssertIOAllowed(); 122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DIR* dir = opendir(source.value().c_str()); 123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!dir) 124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return false; 125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 126868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_BSD) && \ 127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) !defined(OS_SOLARIS) && !defined(OS_ANDROID) 128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) #error Port warning: depending on the definition of struct dirent, \ 129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) additional space for pathname may be needed 130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif 131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) struct dirent dent_buf; 133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) struct dirent* dent; 134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) { 135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FileInfo info; 136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) info.filename_ = FilePath(dent->d_name); 137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) FilePath full_name = source.Append(dent->d_name); 139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) int ret; 140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (show_links) 141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ret = lstat(full_name.value().c_str(), &info.stat_); 142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) else 143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) ret = stat(full_name.value().c_str(), &info.stat_); 144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (ret < 0) { 145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // Print the stat() error message unless it was ENOENT and we're 146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) // following symlinks. 147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) if (!(errno == ENOENT && !show_links)) { 148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) DPLOG(ERROR) << "Couldn't stat " 149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) << source.Append(dent->d_name).value(); 150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) memset(&info.stat_, 0, sizeof(info.stat_)); 152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) entries->push_back(info); 154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) } 155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) closedir(dir); 157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) return true; 158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} 159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)} // namespace base 161