1 // Windows/FileFind.cpp |
|
2 |
|
3 #include "StdAfx.h" |
|
4 |
|
5 #include "FileFind.h" |
|
6 #ifndef _UNICODE |
|
7 #include "../Common/StringConvert.h" |
|
8 #endif |
|
9 |
|
10 #ifndef _UNICODE |
|
11 extern bool g_IsNT; |
|
12 #endif |
|
13 |
|
14 namespace NWindows { |
|
15 namespace NFile { |
|
16 |
|
17 #if defined(WIN_LONG_PATH) && defined(_UNICODE) |
|
18 #define WIN_LONG_PATH2 |
|
19 #endif |
|
20 |
|
21 bool GetLongPath(LPCWSTR fileName, UString &res); |
|
22 |
|
23 namespace NFind { |
|
24 |
|
25 static const TCHAR kDot = TEXT('.'); |
|
26 |
|
27 bool CFileInfo::IsDots() const |
|
28 { |
|
29 if (!IsDirectory() || Name.IsEmpty()) |
|
30 return false; |
|
31 if (Name[0] != kDot) |
|
32 return false; |
|
33 return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); |
|
34 } |
|
35 |
|
36 #ifndef _UNICODE |
|
37 bool CFileInfoW::IsDots() const |
|
38 { |
|
39 if (!IsDirectory() || Name.IsEmpty()) |
|
40 return false; |
|
41 if (Name[0] != kDot) |
|
42 return false; |
|
43 return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); |
|
44 } |
|
45 #endif |
|
46 |
|
47 static void ConvertWIN32_FIND_DATA_To_FileInfo( |
|
48 const WIN32_FIND_DATA &findData, |
|
49 CFileInfo &fileInfo) |
|
50 { |
|
51 fileInfo.Attributes = findData.dwFileAttributes; |
|
52 fileInfo.CreationTime = findData.ftCreationTime; |
|
53 fileInfo.LastAccessTime = findData.ftLastAccessTime; |
|
54 fileInfo.LastWriteTime = findData.ftLastWriteTime; |
|
55 fileInfo.Size = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; |
|
56 fileInfo.Name = findData.cFileName; |
|
57 #ifndef _WIN32_WCE |
|
58 fileInfo.ReparseTag = findData.dwReserved0; |
|
59 #else |
|
60 fileInfo.ObjectID = findData.dwOID; |
|
61 #endif |
|
62 } |
|
63 |
|
64 #ifndef _UNICODE |
|
65 |
|
66 static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } |
|
67 |
|
68 static void ConvertWIN32_FIND_DATA_To_FileInfo( |
|
69 const WIN32_FIND_DATAW &findData, |
|
70 CFileInfoW &fileInfo) |
|
71 { |
|
72 fileInfo.Attributes = findData.dwFileAttributes; |
|
73 fileInfo.CreationTime = findData.ftCreationTime; |
|
74 fileInfo.LastAccessTime = findData.ftLastAccessTime; |
|
75 fileInfo.LastWriteTime = findData.ftLastWriteTime; |
|
76 fileInfo.Size = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; |
|
77 fileInfo.Name = findData.cFileName; |
|
78 #ifndef _WIN32_WCE |
|
79 fileInfo.ReparseTag = findData.dwReserved0; |
|
80 #else |
|
81 fileInfo.ObjectID = findData.dwOID; |
|
82 #endif |
|
83 } |
|
84 |
|
85 static void ConvertWIN32_FIND_DATA_To_FileInfo( |
|
86 const WIN32_FIND_DATA &findData, |
|
87 CFileInfoW &fileInfo) |
|
88 { |
|
89 fileInfo.Attributes = findData.dwFileAttributes; |
|
90 fileInfo.CreationTime = findData.ftCreationTime; |
|
91 fileInfo.LastAccessTime = findData.ftLastAccessTime; |
|
92 fileInfo.LastWriteTime = findData.ftLastWriteTime; |
|
93 fileInfo.Size = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; |
|
94 fileInfo.Name = GetUnicodeString(findData.cFileName, GetCurrentCodePage()); |
|
95 #ifndef _WIN32_WCE |
|
96 fileInfo.ReparseTag = findData.dwReserved0; |
|
97 #else |
|
98 fileInfo.ObjectID = findData.dwOID; |
|
99 #endif |
|
100 } |
|
101 #endif |
|
102 |
|
103 //////////////////////////////// |
|
104 // CFindFile |
|
105 |
|
106 bool CFindFile::Close() |
|
107 { |
|
108 if (_handle == INVALID_HANDLE_VALUE) |
|
109 return true; |
|
110 if (!::FindClose(_handle)) |
|
111 return false; |
|
112 _handle = INVALID_HANDLE_VALUE; |
|
113 return true; |
|
114 } |
|
115 |
|
116 |
|
117 bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo) |
|
118 { |
|
119 if (!Close()) |
|
120 return false; |
|
121 WIN32_FIND_DATA findData; |
|
122 _handle = ::FindFirstFile(wildcard, &findData); |
|
123 #ifdef WIN_LONG_PATH2 |
|
124 if (_handle == INVALID_HANDLE_VALUE) |
|
125 { |
|
126 UString longPath; |
|
127 if (GetLongPath(wildcard, longPath)) |
|
128 _handle = ::FindFirstFileW(longPath, &findData); |
|
129 } |
|
130 #endif |
|
131 if (_handle == INVALID_HANDLE_VALUE) |
|
132 return false; |
|
133 ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
|
134 return true; |
|
135 } |
|
136 |
|
137 #ifndef _UNICODE |
|
138 bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo) |
|
139 { |
|
140 if (!Close()) |
|
141 return false; |
|
142 if (g_IsNT) |
|
143 { |
|
144 WIN32_FIND_DATAW findData; |
|
145 _handle = ::FindFirstFileW(wildcard, &findData); |
|
146 #ifdef WIN_LONG_PATH |
|
147 if (_handle == INVALID_HANDLE_VALUE) |
|
148 { |
|
149 UString longPath; |
|
150 if (GetLongPath(wildcard, longPath)) |
|
151 _handle = ::FindFirstFileW(longPath, &findData); |
|
152 } |
|
153 #endif |
|
154 if (_handle != INVALID_HANDLE_VALUE) |
|
155 ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
|
156 } |
|
157 else |
|
158 { |
|
159 WIN32_FIND_DATAA findData; |
|
160 _handle = ::FindFirstFileA(UnicodeStringToMultiByte(wildcard, |
|
161 GetCurrentCodePage()), &findData); |
|
162 if (_handle != INVALID_HANDLE_VALUE) |
|
163 ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
|
164 } |
|
165 return (_handle != INVALID_HANDLE_VALUE); |
|
166 } |
|
167 #endif |
|
168 |
|
169 bool CFindFile::FindNext(CFileInfo &fileInfo) |
|
170 { |
|
171 WIN32_FIND_DATA findData; |
|
172 bool result = BOOLToBool(::FindNextFile(_handle, &findData)); |
|
173 if (result) |
|
174 ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
|
175 return result; |
|
176 } |
|
177 |
|
178 #ifndef _UNICODE |
|
179 bool CFindFile::FindNext(CFileInfoW &fileInfo) |
|
180 { |
|
181 if (g_IsNT) |
|
182 { |
|
183 WIN32_FIND_DATAW findData; |
|
184 if (!::FindNextFileW(_handle, &findData)) |
|
185 return false; |
|
186 ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
|
187 } |
|
188 else |
|
189 { |
|
190 WIN32_FIND_DATAA findData; |
|
191 if (!::FindNextFileA(_handle, &findData)) |
|
192 return false; |
|
193 ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); |
|
194 } |
|
195 return true; |
|
196 } |
|
197 #endif |
|
198 |
|
199 bool FindFile(LPCTSTR wildcard, CFileInfo &fileInfo) |
|
200 { |
|
201 CFindFile finder; |
|
202 return finder.FindFirst(wildcard, fileInfo); |
|
203 } |
|
204 |
|
205 #ifndef _UNICODE |
|
206 bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo) |
|
207 { |
|
208 CFindFile finder; |
|
209 return finder.FindFirst(wildcard, fileInfo); |
|
210 } |
|
211 #endif |
|
212 |
|
213 bool DoesFileExist(LPCTSTR name) |
|
214 { |
|
215 CFileInfo fileInfo; |
|
216 return FindFile(name, fileInfo); |
|
217 } |
|
218 |
|
219 #ifndef _UNICODE |
|
220 bool DoesFileExist(LPCWSTR name) |
|
221 { |
|
222 CFileInfoW fileInfo; |
|
223 return FindFile(name, fileInfo); |
|
224 } |
|
225 #endif |
|
226 |
|
227 ///////////////////////////////////// |
|
228 // CEnumerator |
|
229 |
|
230 bool CEnumerator::NextAny(CFileInfo &fileInfo) |
|
231 { |
|
232 if (_findFile.IsHandleAllocated()) |
|
233 return _findFile.FindNext(fileInfo); |
|
234 else |
|
235 return _findFile.FindFirst(_wildcard, fileInfo); |
|
236 } |
|
237 |
|
238 bool CEnumerator::Next(CFileInfo &fileInfo) |
|
239 { |
|
240 for (;;) |
|
241 { |
|
242 if (!NextAny(fileInfo)) |
|
243 return false; |
|
244 if (!fileInfo.IsDots()) |
|
245 return true; |
|
246 } |
|
247 } |
|
248 |
|
249 bool CEnumerator::Next(CFileInfo &fileInfo, bool &found) |
|
250 { |
|
251 if (Next(fileInfo)) |
|
252 { |
|
253 found = true; |
|
254 return true; |
|
255 } |
|
256 found = false; |
|
257 return (::GetLastError() == ERROR_NO_MORE_FILES); |
|
258 } |
|
259 |
|
260 #ifndef _UNICODE |
|
261 bool CEnumeratorW::NextAny(CFileInfoW &fileInfo) |
|
262 { |
|
263 if (_findFile.IsHandleAllocated()) |
|
264 return _findFile.FindNext(fileInfo); |
|
265 else |
|
266 return _findFile.FindFirst(_wildcard, fileInfo); |
|
267 } |
|
268 |
|
269 bool CEnumeratorW::Next(CFileInfoW &fileInfo) |
|
270 { |
|
271 for (;;) |
|
272 { |
|
273 if (!NextAny(fileInfo)) |
|
274 return false; |
|
275 if (!fileInfo.IsDots()) |
|
276 return true; |
|
277 } |
|
278 } |
|
279 |
|
280 bool CEnumeratorW::Next(CFileInfoW &fileInfo, bool &found) |
|
281 { |
|
282 if (Next(fileInfo)) |
|
283 { |
|
284 found = true; |
|
285 return true; |
|
286 } |
|
287 found = false; |
|
288 return (::GetLastError() == ERROR_NO_MORE_FILES); |
|
289 } |
|
290 |
|
291 #endif |
|
292 |
|
293 //////////////////////////////// |
|
294 // CFindChangeNotification |
|
295 // FindFirstChangeNotification can return 0. MSDN doesn't tell about it. |
|
296 |
|
297 bool CFindChangeNotification::Close() |
|
298 { |
|
299 if (!IsHandleAllocated()) |
|
300 return true; |
|
301 if (!::FindCloseChangeNotification(_handle)) |
|
302 return false; |
|
303 _handle = INVALID_HANDLE_VALUE; |
|
304 return true; |
|
305 } |
|
306 |
|
307 HANDLE CFindChangeNotification::FindFirst(LPCTSTR pathName, bool watchSubtree, DWORD notifyFilter) |
|
308 { |
|
309 _handle = ::FindFirstChangeNotification(pathName, BoolToBOOL(watchSubtree), notifyFilter); |
|
310 #ifdef WIN_LONG_PATH2 |
|
311 if (!IsHandleAllocated()) |
|
312 { |
|
313 UString longPath; |
|
314 if (GetLongPath(pathName, longPath)) |
|
315 _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); |
|
316 } |
|
317 #endif |
|
318 return _handle; |
|
319 } |
|
320 |
|
321 #ifndef _UNICODE |
|
322 HANDLE CFindChangeNotification::FindFirst(LPCWSTR pathName, bool watchSubtree, DWORD notifyFilter) |
|
323 { |
|
324 if (!g_IsNT) |
|
325 return FindFirst(UnicodeStringToMultiByte(pathName, GetCurrentCodePage()), watchSubtree, notifyFilter); |
|
326 _handle = ::FindFirstChangeNotificationW(pathName, BoolToBOOL(watchSubtree), notifyFilter); |
|
327 #ifdef WIN_LONG_PATH |
|
328 if (!IsHandleAllocated()) |
|
329 { |
|
330 UString longPath; |
|
331 if (GetLongPath(pathName, longPath)) |
|
332 _handle = ::FindFirstChangeNotificationW(longPath, BoolToBOOL(watchSubtree), notifyFilter); |
|
333 } |
|
334 #endif |
|
335 return _handle; |
|
336 } |
|
337 #endif |
|
338 |
|
339 #ifndef _WIN32_WCE |
|
340 bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings) |
|
341 { |
|
342 driveStrings.Clear(); |
|
343 UINT32 size = GetLogicalDriveStrings(0, NULL); |
|
344 if (size == 0) |
|
345 return false; |
|
346 CSysString buffer; |
|
347 UINT32 newSize = GetLogicalDriveStrings(size, buffer.GetBuffer(size)); |
|
348 if (newSize == 0) |
|
349 return false; |
|
350 if (newSize > size) |
|
351 return false; |
|
352 CSysString string; |
|
353 for(UINT32 i = 0; i < newSize; i++) |
|
354 { |
|
355 TCHAR c = buffer[i]; |
|
356 if (c == TEXT('\0')) |
|
357 { |
|
358 driveStrings.Add(string); |
|
359 string.Empty(); |
|
360 } |
|
361 else |
|
362 string += c; |
|
363 } |
|
364 if (!string.IsEmpty()) |
|
365 return false; |
|
366 return true; |
|
367 } |
|
368 |
|
369 #ifndef _UNICODE |
|
370 bool MyGetLogicalDriveStrings(UStringVector &driveStrings) |
|
371 { |
|
372 driveStrings.Clear(); |
|
373 if (g_IsNT) |
|
374 { |
|
375 UINT32 size = GetLogicalDriveStringsW(0, NULL); |
|
376 if (size == 0) |
|
377 return false; |
|
378 UString buffer; |
|
379 UINT32 newSize = GetLogicalDriveStringsW(size, buffer.GetBuffer(size)); |
|
380 if (newSize == 0) |
|
381 return false; |
|
382 if (newSize > size) |
|
383 return false; |
|
384 UString string; |
|
385 for(UINT32 i = 0; i < newSize; i++) |
|
386 { |
|
387 WCHAR c = buffer[i]; |
|
388 if (c == L'\0') |
|
389 { |
|
390 driveStrings.Add(string); |
|
391 string.Empty(); |
|
392 } |
|
393 else |
|
394 string += c; |
|
395 } |
|
396 return string.IsEmpty(); |
|
397 } |
|
398 CSysStringVector driveStringsA; |
|
399 bool res = MyGetLogicalDriveStrings(driveStringsA); |
|
400 for (int i = 0; i < driveStringsA.Size(); i++) |
|
401 driveStrings.Add(GetUnicodeString(driveStringsA[i])); |
|
402 return res; |
|
403 } |
|
404 #endif |
|
405 |
|
406 #endif |
|
407 |
|
408 }}} |
|