windows_win/raw/
file.rs

1//! Provides File Management functions
2
3use 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
15///Level of information to store about file during search.
16pub enum FileInfoLevel {
17    ///Corresponds to FindExInfoStandard. Default.
18    Standard,
19    ///Corresponds to FindExInfoBasic.
20    Basic,
21    ///Corresponds to FindExInfoMaxInfoLevel.
22    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
41///File search type
42pub enum FileSearchType {
43    ///Search file by name. Corresponds to FindExSearchNameMatch. Default.
44    NameMatch,
45    ///Ask to search directories only. Corresponds to FindExSearchLimitToDirectories.
46    ///
47    ///Note that this flag may be ignored by OS.
48    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
66///File System Entry.
67pub struct Entry(WIN32_FIND_DATAW);
68
69impl Entry {
70    ///Determines whether Entry is directory or not.
71    pub fn is_dir(&self) -> bool {
72        (self.0.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0
73    }
74
75    ///Determines whether Entry is file or not.
76    pub fn is_file(&self) -> bool {
77        !self.is_dir()
78    }
79
80    ///Returns size of entry
81    pub fn size(&self) -> u64 {
82        ((self.0.nFileSizeHigh as u64) << 32) | (self.0.nFileSizeLow as u64)
83    }
84
85    ///Returns whether Entry is read-only
86    pub fn is_read_only(&self) -> bool {
87        (self.0.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0
88    }
89
90    ///Returns name of Entry.
91    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
99///File System Search iterator.
100pub struct Search(HANDLE);
101
102impl Search {
103    ///Creates new instance of Search.
104    ///
105    ///Due to the way how underlying WinAPI works first entry is also returned alongside it.
106    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    ///Attempts to search again.
130    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    ///Closes search.
144    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