1use std::ffi;
4use std::os::windows::ffi::{
5 OsStrExt,
6 OsStringExt
7};
8use core::{default, ptr, mem, convert};
9
10use crate::sys::*;
11use crate::utils::{self, Result};
12
13const NO_MORE_FILES: i32 = ERROR_NO_MORE_FILES as i32;
14
15pub enum FileInfoLevel {
17 Standard,
19 Basic,
21 Max
23}
24
25impl convert::Into<FINDEX_INFO_LEVELS> for FileInfoLevel {
26 fn into(self) -> FINDEX_INFO_LEVELS {
27 match self {
28 FileInfoLevel::Standard => FindExInfoStandard,
29 FileInfoLevel::Basic => FindExInfoBasic,
30 FileInfoLevel::Max => FindExInfoMaxInfoLevel
31 }
32 }
33}
34
35impl default::Default for FileInfoLevel {
36 fn default() -> Self {
37 FileInfoLevel::Standard
38 }
39}
40
41pub enum FileSearchType {
43 NameMatch,
45 DirectoriesOnly
49}
50
51impl convert::Into<FINDEX_SEARCH_OPS> for FileSearchType {
52 fn into(self) -> FINDEX_SEARCH_OPS {
53 match self {
54 FileSearchType::NameMatch => FindExSearchNameMatch,
55 FileSearchType::DirectoriesOnly => FindExSearchLimitToDirectories
56 }
57 }
58}
59
60impl default::Default for FileSearchType {
61 fn default() -> Self {
62 FileSearchType::NameMatch
63 }
64}
65
66pub struct Entry(WIN32_FIND_DATAW);
68
69impl Entry {
70 pub fn is_dir(&self) -> bool {
72 (self.0.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0
73 }
74
75 pub fn is_file(&self) -> bool {
77 !self.is_dir()
78 }
79
80 pub fn size(&self) -> u64 {
82 ((self.0.nFileSizeHigh as u64) << 32) | (self.0.nFileSizeLow as u64)
83 }
84
85 pub fn is_read_only(&self) -> bool {
87 (self.0.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0
88 }
89
90 pub fn name(&self) -> ffi::OsString {
92 ffi::OsString::from_wide(match self.0.cFileName.iter().position(|c| *c == 0) {
93 Some(n) => &self.0.cFileName[..n],
94 None => &self.0.cFileName
95 })
96 }
97}
98
99pub struct Search(HANDLE);
101
102impl Search {
103 pub fn new<T: ?Sized + AsRef<ffi::OsStr>>(name: &T, level: FileInfoLevel, typ: FileSearchType, flags: DWORD) -> Result<(Search, Entry)> {
107 let mut utf16_buff: Vec<u16> = name.as_ref().encode_wide().collect();
108 utf16_buff.push(0);
109
110 let mut file_data: WIN32_FIND_DATAW = unsafe { mem::zeroed() };
111
112 let result = unsafe {
113 FindFirstFileExW(utf16_buff.as_ptr(),
114 level.into(),
115 &mut file_data as *mut _ as *mut c_void,
116 typ.into(),
117 ptr::null_mut(),
118 flags)
119 };
120
121 if result == INVALID_HANDLE_VALUE {
122 Err(utils::get_last_error())
123 }
124 else {
125 Ok((Search(result), Entry(file_data)))
126 }
127 }
128
129 pub fn again(&self) -> Result<Entry> {
131 let mut file_data: WIN32_FIND_DATAW = unsafe { mem::zeroed() };
132
133 unsafe {
134 if FindNextFileW(self.0, &mut file_data) != 0 {
135 Ok(Entry(file_data))
136 }
137 else {
138 Err(utils::get_last_error())
139 }
140 }
141 }
142
143 pub fn close(self) {
145 unsafe {
146 FindClose(self.0);
147 }
148 }
149}
150
151impl Iterator for Search {
152 type Item = Result<Entry>;
153
154 fn next(&mut self) -> Option<Self::Item> {
155 match self.again() {
156 Ok(data) => Some(Ok(data)),
157 Err(error) => {
158 match error.raw_code() {
159 NO_MORE_FILES => None,
160 _ => Some(Err(error))
161 }
162 }
163 }
164 }
165}
166
167impl Drop for Search {
168 fn drop(&mut self) {
169 unsafe {
170 debug_assert!(FindClose(self.0) != 0);
171 }
172 }
173}
174