OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013 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 #include "base/files/file_enumerator.h" | |
6 | |
7 #include <string.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/threading/thread_restrictions.h" | |
11 | |
12 namespace base { | |
13 | |
14 // FileEnumerator::FileInfo ---------------------------------------------------- | |
15 | |
16 FileEnumerator::FileInfo::FileInfo() { | |
17 memset(&find_data_, 0, sizeof(find_data_)); | |
18 } | |
19 | |
20 bool FileEnumerator::FileInfo::IsDirectory() const { | |
21 return (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; | |
22 } | |
23 | |
24 FilePath FileEnumerator::FileInfo::GetName() const { | |
25 return FilePath(find_data_.cFileName); | |
26 } | |
27 | |
28 int64 FileEnumerator::FileInfo::GetSize() const { | |
29 ULARGE_INTEGER size; | |
30 size.HighPart = find_data_.nFileSizeHigh; | |
31 size.LowPart = find_data_.nFileSizeLow; | |
32 DCHECK_LE(size.QuadPart, std::numeric_limits<int64>::max()); | |
33 return static_cast<int64>(size.QuadPart); | |
34 } | |
35 | |
36 base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const { | |
37 return base::Time::FromFileTime(find_data_.ftLastWriteTime); | |
38 } | |
39 | |
40 // FileEnumerator -------------------------------------------------------------- | |
41 | |
42 FileEnumerator::FileEnumerator(const FilePath& root_path, | |
43 bool recursive, | |
44 int file_type) | |
45 : recursive_(recursive), | |
46 file_type_(file_type), | |
47 has_find_data_(false), | |
48 find_handle_(INVALID_HANDLE_VALUE) { | |
49 // INCLUDE_DOT_DOT must not be specified if recursive. | |
50 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); | |
51 memset(&find_data_, 0, sizeof(find_data_)); | |
52 pending_paths_.push(root_path); | |
53 } | |
54 | |
55 FileEnumerator::FileEnumerator(const FilePath& root_path, | |
56 bool recursive, | |
57 int file_type, | |
58 const FilePath::StringType& pattern) | |
59 : recursive_(recursive), | |
60 file_type_(file_type), | |
61 has_find_data_(false), | |
62 pattern_(pattern), | |
63 find_handle_(INVALID_HANDLE_VALUE) { | |
64 // INCLUDE_DOT_DOT must not be specified if recursive. | |
65 DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_))); | |
66 memset(&find_data_, 0, sizeof(find_data_)); | |
67 pending_paths_.push(root_path); | |
68 } | |
69 | |
70 FileEnumerator::~FileEnumerator() { | |
71 if (find_handle_ != INVALID_HANDLE_VALUE) | |
72 FindClose(find_handle_); | |
73 } | |
74 | |
75 FileEnumerator::FileInfo FileEnumerator::GetInfo() const { | |
76 if (!has_find_data_) { | |
77 NOTREACHED(); | |
78 return FileInfo(); | |
79 } | |
80 FileInfo ret; | |
81 memcpy(&ret.find_data_, &find_data_, sizeof(find_data_)); | |
82 return ret; | |
83 } | |
84 | |
85 FilePath FileEnumerator::Next() { | |
86 base::ThreadRestrictions::AssertIOAllowed(); | |
87 | |
88 while (has_find_data_ || !pending_paths_.empty()) { | |
89 if (!has_find_data_) { | |
90 // The last find FindFirstFile operation is done, prepare a new one. | |
91 root_path_ = pending_paths_.top(); | |
92 pending_paths_.pop(); | |
93 | |
94 // Start a new find operation. | |
95 FilePath src = root_path_; | |
96 | |
97 if (pattern_.empty()) | |
98 src = src.Append(L"*"); // No pattern = match everything. | |
99 else | |
100 src = src.Append(pattern_); | |
101 | |
102 find_handle_ = FindFirstFile(src.value().c_str(), &find_data_); | |
103 has_find_data_ = true; | |
104 } else { | |
105 // Search for the next file/directory. | |
106 if (!FindNextFile(find_handle_, &find_data_)) { | |
107 FindClose(find_handle_); | |
108 find_handle_ = INVALID_HANDLE_VALUE; | |
109 } | |
110 } | |
111 | |
112 if (INVALID_HANDLE_VALUE == find_handle_) { | |
113 has_find_data_ = false; | |
114 | |
115 // This is reached when we have finished a directory and are advancing to | |
116 // the next one in the queue. We applied the pattern (if any) to the files | |
117 // in the root search directory, but for those directories which were | |
118 // matched, we want to enumerate all files inside them. This will happen | |
119 // when the handle is empty. | |
120 pattern_ = FilePath::StringType(); | |
121 | |
122 continue; | |
123 } | |
124 | |
125 FilePath cur_file(find_data_.cFileName); | |
126 if (ShouldSkip(cur_file)) | |
127 continue; | |
128 | |
129 // Construct the absolute filename. | |
130 cur_file = root_path_.Append(find_data_.cFileName); | |
131 | |
132 if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { | |
133 if (recursive_) { | |
134 // If |cur_file| is a directory, and we are doing recursive searching, | |
135 // add it to pending_paths_ so we scan it after we finish scanning this | |
136 // directory. | |
137 pending_paths_.push(cur_file); | |
138 } | |
139 if (file_type_ & FileEnumerator::DIRECTORIES) | |
140 return cur_file; | |
141 } else if (file_type_ & FileEnumerator::FILES) { | |
142 return cur_file; | |
143 } | |
144 } | |
145 | |
146 return FilePath(); | |
147 } | |
148 | |
149 } // namespace base | |
OLD | NEW |