3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 /*============================================================
8 ** Class: FileSystemEnumerable
10 ** <OWNER>[....]</OWNER>
13 ** Purpose: Enumerates files and dirs
15 ===========================================================*/
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.Security;
21 using System.Security.Permissions;
22 using Microsoft.Win32;
23 using Microsoft.Win32.SafeHandles;
25 using System.Runtime.InteropServices;
26 using System.Globalization;
27 using System.Runtime.Versioning;
28 using System.Diagnostics.Contracts;
29 using System.Threading;
35 // The key methods instantiate FileSystemEnumerableIterators. These compose the iterator with search result
36 // handlers that instantiate the FileInfo, DirectoryInfo, String, etc. The handlers then perform any
37 // additional required permission demands.
38 internal static class FileSystemEnumerableFactory
40 internal static IEnumerable<String> CreateFileNameIterator(String path, String originalUserPath, String searchPattern,
41 bool includeFiles, bool includeDirs, SearchOption searchOption, bool checkHost)
43 Contract.Requires(path != null);
44 Contract.Requires(originalUserPath != null);
45 Contract.Requires(searchPattern != null);
47 SearchResultHandler<String> handler = new StringResultHandler(includeFiles, includeDirs);
48 return new FileSystemEnumerableIterator<String>(path, originalUserPath, searchPattern, searchOption, handler, checkHost);
51 internal static IEnumerable<FileInfo> CreateFileInfoIterator(String path, String originalUserPath, String searchPattern, SearchOption searchOption)
53 Contract.Requires(path != null);
54 Contract.Requires(originalUserPath != null);
55 Contract.Requires(searchPattern != null);
57 SearchResultHandler<FileInfo> handler = new FileInfoResultHandler();
58 return new FileSystemEnumerableIterator<FileInfo>(path, originalUserPath, searchPattern, searchOption, handler, true);
61 internal static IEnumerable<DirectoryInfo> CreateDirectoryInfoIterator(String path, String originalUserPath, String searchPattern, SearchOption searchOption)
64 Contract.Requires(path != null);
65 Contract.Requires(originalUserPath != null);
66 Contract.Requires(searchPattern != null);
68 SearchResultHandler<DirectoryInfo> handler = new DirectoryInfoResultHandler();
69 return new FileSystemEnumerableIterator<DirectoryInfo>(path, originalUserPath, searchPattern, searchOption, handler, true);
72 internal static IEnumerable<FileSystemInfo> CreateFileSystemInfoIterator(String path, String originalUserPath, String searchPattern, SearchOption searchOption)
74 Contract.Requires(path != null);
75 Contract.Requires(originalUserPath != null);
76 Contract.Requires(searchPattern != null);
78 SearchResultHandler<FileSystemInfo> handler = new FileSystemInfoResultHandler();
79 return new FileSystemEnumerableIterator<FileSystemInfo>(path, originalUserPath, searchPattern, searchOption, handler, true);
83 // Abstract Iterator, borrowed from Linq. Used in anticipation of need for similar enumerables
85 abstract internal class Iterator<TSource> : IEnumerable<TSource>, IEnumerator<TSource>
89 internal TSource current;
93 threadId = Thread.CurrentThread.ManagedThreadId;
96 public TSource Current
98 get { return current; }
101 protected abstract Iterator<TSource> Clone();
103 public void Dispose()
106 GC.SuppressFinalize(this);
109 protected virtual void Dispose(bool disposing)
111 current = default(TSource);
115 public IEnumerator<TSource> GetEnumerator()
117 if (threadId == Thread.CurrentThread.ManagedThreadId && state == 0)
123 Iterator<TSource> duplicate = Clone();
128 public abstract bool MoveNext();
130 object IEnumerator.Current
132 get { return Current; }
135 IEnumerator IEnumerable.GetEnumerator()
137 return GetEnumerator();
140 void IEnumerator.Reset()
142 throw new NotSupportedException();
148 // Enumerates file system entries matching the search parameters. For recursive searches this
149 // searches through all the sub dirs and executes the search criteria against every dir.
151 // Generic implementation:
152 // FileSystemEnumerableIterator is generic. When it gets a WIN32_FIND_DATA, it calls the
153 // result handler to create an instance of the generic type.
156 // Use FileSystemEnumerableFactory to obtain FSEnumerables that can enumerate file system
157 // entries as String path names, FileInfos, DirectoryInfos, or FileSystemInfos.
160 // For all the dirs/files returned, demands path discovery permission for their parent folders
161 internal class FileSystemEnumerableIterator<TSource> : Iterator<TSource>
164 private const int STATE_INIT = 1;
165 private const int STATE_SEARCH_NEXT_DIR = 2;
166 private const int STATE_FIND_NEXT_FILE = 3;
167 private const int STATE_FINISH = 4;
169 private SearchResultHandler<TSource> _resultHandler;
170 private List<Directory.SearchData> searchStack;
171 private Directory.SearchData searchData;
172 private String searchCriteria;
173 [System.Security.SecurityCritical]
174 SafeFindHandle _hnd = null;
175 bool needsParentPathDiscoveryDemand;
177 // empty means we know in advance that we won't find any search results, which can happen if:
178 // 1. we don't have a search pattern
179 // 2. we're enumerating only the top directory and found no matches during the first call
180 // This flag allows us to return early for these cases. We can't know this in advance for
181 // SearchOption.AllDirectories because we do a "*" search for subdirs and then use the
182 // searchPattern at each directory level.
185 private String userPath;
186 private SearchOption searchOption;
187 private String fullPath;
188 private String normalizedSearchPath;
190 private bool _checkHost;
192 [System.Security.SecuritySafeCritical]
193 internal FileSystemEnumerableIterator(String path, String originalUserPath, String searchPattern, SearchOption searchOption, SearchResultHandler<TSource> resultHandler, bool checkHost)
195 Contract.Requires(path != null);
196 Contract.Requires(originalUserPath != null);
197 Contract.Requires(searchPattern != null);
198 Contract.Requires(searchOption == SearchOption.AllDirectories || searchOption == SearchOption.TopDirectoryOnly);
199 Contract.Requires(resultHandler != null);
201 #if !MONO // TODO: check if we need this on Windows
202 oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
205 searchStack = new List<Directory.SearchData>();
207 String normalizedSearchPattern = NormalizeSearchPattern(searchPattern);
209 if (normalizedSearchPattern.Length == 0)
215 _resultHandler = resultHandler;
216 this.searchOption = searchOption;
218 fullPath = Path.GetFullPathInternal(path);
219 String fullSearchString = GetFullSearchString(fullPath, normalizedSearchPattern);
220 normalizedSearchPath = Path.GetDirectoryName(fullSearchString);
222 // permission demands
223 String[] demandPaths = new String[2];
225 // TODO: we don't call FileIOPermission.HasIllegalCharacters on Mono since CAS is disabled
227 // Any illegal chars such as *, ? will be caught by FileIOPermission.HasIllegalCharacters
229 demandPaths[0] = Directory.GetDemandDir(fullPath, true);
230 // For filters like foo\*.cs we need to verify if the directory foo is not denied access.
231 // Do a demand on the combined path so that we can fail early in case of deny
232 demandPaths[1] = Directory.GetDemandDir(normalizedSearchPath, true);
233 _checkHost = checkHost;
238 FileSecurityState state1 = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPaths[0]);
239 state1.EnsureState();
240 FileSecurityState state2 = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPaths[1]);
241 state2.EnsureState();
244 FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false);
248 // normalize search criteria
249 searchCriteria = GetNormalizedSearchCriteria(fullSearchString, normalizedSearchPath);
252 String searchPatternDirName = Path.GetDirectoryName(normalizedSearchPattern);
253 String userPathTemp = originalUserPath;
254 if (searchPatternDirName != null && searchPatternDirName.Length != 0)
256 userPathTemp = Path.Combine(userPathTemp, searchPatternDirName);
258 this.userPath = userPathTemp;
260 searchData = new Directory.SearchData(normalizedSearchPath, this.userPath, searchOption);
267 [System.Security.SecurityCritical]
268 private void CommonInit()
270 Contract.Assert(searchCriteria != null && searchData != null, "searchCriteria and searchData should be initialized");
272 // Execute searchCriteria against the current directory
273 String searchPath = Path.InternalCombine(searchData.fullPath, searchCriteria);
275 Win32Native.WIN32_FIND_DATA data = new Win32Native.WIN32_FIND_DATA();
277 // Open a Find handle
280 _hnd = new SafeFindHandle (MonoIO.FindFirstFile (searchPath, out data.cFileName, out data.dwFileAttributes, out error));
282 _hnd = Win32Native.FindFirstFile(searchPath, data);
290 int hr = Marshal.GetLastWin32Error();
292 if (hr != Win32Native.ERROR_FILE_NOT_FOUND && hr != Win32Native.ERROR_NO_MORE_FILES)
294 HandleError(hr, searchData.fullPath);
298 // flag this as empty only if we're searching just top directory
299 // Used in fast path for top directory only
300 empty = searchData.searchOption == SearchOption.TopDirectoryOnly;
303 // fast path for TopDirectoryOnly. If we have a result, go ahead and set it to
304 // current. If empty, dispose handle.
305 if (searchData.searchOption == SearchOption.TopDirectoryOnly)
313 SearchResult searchResult = CreateSearchResult(searchData, data);
314 if (_resultHandler.IsResultIncluded(searchResult))
316 current = _resultHandler.CreateObject(searchResult);
320 // for AllDirectories, we first recurse into dirs, so cleanup and add searchData
325 searchStack.Add(searchData);
329 [System.Security.SecuritySafeCritical]
330 private FileSystemEnumerableIterator(String fullPath, String normalizedSearchPath, String searchCriteria, String userPath, SearchOption searchOption, SearchResultHandler<TSource> resultHandler, bool checkHost)
332 this.fullPath = fullPath;
333 this.normalizedSearchPath = normalizedSearchPath;
334 this.searchCriteria = searchCriteria;
335 this._resultHandler = resultHandler;
336 this.userPath = userPath;
337 this.searchOption = searchOption;
338 this._checkHost = checkHost;
340 searchStack = new List<Directory.SearchData>();
342 if (searchCriteria != null)
344 // permission demands
345 String[] demandPaths = new String[2];
346 // Any illegal chars such as *, ? will be caught by FileIOPermission.HasIllegalCharacters
347 demandPaths[0] = Directory.GetDemandDir(fullPath, true);
348 // For filters like foo\*.cs we need to verify if the directory foo is not denied access.
349 // Do a demand on the combined path so that we can fail early in case of deny
350 demandPaths[1] = Directory.GetDemandDir(normalizedSearchPath, true);
355 FileSecurityState state1 = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPaths[0]);
356 state1.EnsureState();
357 FileSecurityState state2 = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPaths[1]);
358 state2.EnsureState();
361 FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false);
364 searchData = new Directory.SearchData(normalizedSearchPath, userPath, searchOption);
373 protected override Iterator<TSource> Clone()
375 return new FileSystemEnumerableIterator<TSource>(fullPath, normalizedSearchPath, searchCriteria, userPath, searchOption, _resultHandler, _checkHost);
378 [System.Security.SecuritySafeCritical]
379 protected override void Dispose(bool disposing)
390 #if !MONO // TODO: check if we need this on Windows
391 Win32Native.SetErrorMode(oldMode);
393 base.Dispose(disposing);
397 [System.Security.SecuritySafeCritical]
398 public override bool MoveNext()
400 Win32Native.WIN32_FIND_DATA data = new Win32Native.WIN32_FIND_DATA();
407 state = STATE_FINISH;
408 goto case STATE_FINISH;
410 if (searchData.searchOption == SearchOption.TopDirectoryOnly)
412 state = STATE_FIND_NEXT_FILE;
419 goto case STATE_FIND_NEXT_FILE;
424 state = STATE_SEARCH_NEXT_DIR;
425 goto case STATE_SEARCH_NEXT_DIR;
428 case STATE_SEARCH_NEXT_DIR:
430 Contract.Assert(searchData.searchOption != SearchOption.TopDirectoryOnly, "should not reach this code path if searchOption == TopDirectoryOnly");
431 // Traverse directory structure. We need to get '*'
432 while (searchStack.Count > 0)
434 searchData = searchStack[0];
435 Contract.Assert((searchData.fullPath != null), "fullpath can't be null!");
436 searchStack.RemoveAt(0);
438 // Traverse the subdirs
439 AddSearchableDirsToStack(searchData);
441 // Execute searchCriteria against the current directory
442 String searchPath = Path.InternalCombine(searchData.fullPath, searchCriteria);
444 // Open a Find handle
447 _hnd = new SafeFindHandle (MonoIO.FindFirstFile (searchPath, out data.cFileName, out data.dwFileAttributes, out error));
449 _hnd = Win32Native.FindFirstFile(searchPath, data);
456 int hr = Marshal.GetLastWin32Error();
458 if (hr == Win32Native.ERROR_FILE_NOT_FOUND || hr == Win32Native.ERROR_NO_MORE_FILES || hr == Win32Native.ERROR_PATH_NOT_FOUND)
462 HandleError(hr, searchData.fullPath);
465 state = STATE_FIND_NEXT_FILE;
466 needsParentPathDiscoveryDemand = true;
467 SearchResult searchResult = CreateSearchResult(searchData, data);
468 if (_resultHandler.IsResultIncluded(searchResult))
470 if (needsParentPathDiscoveryDemand)
472 DoDemand(searchData.fullPath);
473 needsParentPathDiscoveryDemand = false;
475 current = _resultHandler.CreateObject(searchResult);
480 goto case STATE_FIND_NEXT_FILE;
483 state = STATE_FINISH;
484 goto case STATE_FINISH;
486 case STATE_FIND_NEXT_FILE:
488 if (searchData != null && _hnd != null)
490 // Keep asking for more matching files/dirs, add it to the list
493 while (MonoIO.FindNextFile (_hnd.DangerousGetHandle(), out data.cFileName, out data.dwFileAttributes, out error))
495 while (Win32Native.FindNextFile(_hnd, data))
498 SearchResult searchResult = CreateSearchResult(searchData, data);
499 if (_resultHandler.IsResultIncluded(searchResult))
501 if (needsParentPathDiscoveryDemand)
503 DoDemand(searchData.fullPath);
504 needsParentPathDiscoveryDemand = false;
506 current = _resultHandler.CreateObject(searchResult);
514 // Make sure we quit with a sensible error.
515 int hr = Marshal.GetLastWin32Error();
521 // ERROR_FILE_NOT_FOUND is valid here because if the top level
522 // dir doen't contain any subdirs and matching files then
523 // we will get here with this errorcode from the searchStack walk
524 if ((hr != 0) && (hr != Win32Native.ERROR_NO_MORE_FILES)
525 && (hr != Win32Native.ERROR_FILE_NOT_FOUND))
527 HandleError(hr, searchData.fullPath);
530 if (searchData.searchOption == SearchOption.TopDirectoryOnly)
532 state = STATE_FINISH;
533 goto case STATE_FINISH;
537 state = STATE_SEARCH_NEXT_DIR;
538 goto case STATE_SEARCH_NEXT_DIR;
550 [System.Security.SecurityCritical]
551 private SearchResult CreateSearchResult(Directory.SearchData localSearchData, Win32Native.WIN32_FIND_DATA findData)
553 String userPathFinal = Path.InternalCombine(localSearchData.userPath, findData.cFileName);
554 String fullPathFinal = Path.InternalCombine(localSearchData.fullPath, findData.cFileName);
555 return new SearchResult(fullPathFinal, userPathFinal, findData);
558 [System.Security.SecurityCritical]
559 private void HandleError(int hr, String path)
562 __Error.WinIOError(hr, path);
565 [System.Security.SecurityCritical] // auto-generated
566 private void AddSearchableDirsToStack(Directory.SearchData localSearchData)
568 Contract.Requires(localSearchData != null);
570 String searchPath = Path.InternalCombine(localSearchData.fullPath, "*");
571 SafeFindHandle hnd = null;
572 Win32Native.WIN32_FIND_DATA data = new Win32Native.WIN32_FIND_DATA();
575 // Get all files and dirs
578 hnd = new SafeFindHandle (MonoIO.FindFirstFile (searchPath, out data.cFileName, out data.dwFileAttributes, out error));
580 hnd = Win32Native.FindFirstFile(searchPath, data);
588 int hr = Marshal.GetLastWin32Error();
591 // This could happen if the dir doesn't contain any files.
592 // Continue with the recursive search though, eventually
593 // searchStack will become empty
594 if (hr == Win32Native.ERROR_FILE_NOT_FOUND || hr == Win32Native.ERROR_NO_MORE_FILES || hr == Win32Native.ERROR_PATH_NOT_FOUND)
597 HandleError(hr, localSearchData.fullPath);
600 // Add subdirs to searchStack. Exempt ReparsePoints as appropriate
604 if (FileSystemEnumerableHelpers.IsDir(data))
606 String tempFullPath = Path.InternalCombine(localSearchData.fullPath, data.cFileName);
607 String tempUserPath = Path.InternalCombine(localSearchData.userPath, data.cFileName);
609 SearchOption option = localSearchData.searchOption;
611 #if EXCLUDE_REPARSEPOINTS
612 // Traverse reparse points depending on the searchoption specified
613 if ((searchDataSubDir.searchOption == SearchOption.AllDirectories) && (0 != (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_REPARSE_POINT)))
614 option = SearchOption.TopDirectoryOnly;
616 // Setup search data for the sub directory and push it into the stack
617 Directory.SearchData searchDataSubDir = new Directory.SearchData(tempFullPath, tempUserPath, option);
619 searchStack.Insert(incr++, searchDataSubDir);
622 } while (MonoIO.FindNextFile (hnd.DangerousGetHandle(), out data.cFileName, out data.dwFileAttributes, out error));
624 } while (Win32Native.FindNextFile(hnd, data));
626 // We don't care about errors here
635 [System.Security.SecurityCritical]
636 internal void DoDemand(String fullPathToDemand)
641 String demandDir = Directory.GetDemandDir(fullPathToDemand, true);
642 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandDir);
646 String demandDir = Directory.GetDemandDir(fullPathToDemand, true);
647 FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandDir, false, false);
652 private static String NormalizeSearchPattern(String searchPattern)
654 Contract.Requires(searchPattern != null);
656 // Win32 normalization trims only U+0020.
657 String tempSearchPattern = searchPattern.TrimEnd(Path.TrimEndChars);
659 // Make this corner case more useful, like dir
660 if (tempSearchPattern.Equals("."))
662 tempSearchPattern = "*";
665 Path.CheckSearchPattern(tempSearchPattern);
666 return tempSearchPattern;
669 private static String GetNormalizedSearchCriteria(String fullSearchString, String fullPathMod)
671 Contract.Requires(fullSearchString != null);
672 Contract.Requires(fullPathMod != null);
673 Contract.Requires(fullSearchString.Length >= fullPathMod.Length);
675 String searchCriteria = null;
676 char lastChar = fullPathMod[fullPathMod.Length - 1];
677 if (Path.IsDirectorySeparator(lastChar))
679 // Can happen if the path is C:\temp, in which case GetDirectoryName would return C:\
680 searchCriteria = fullSearchString.Substring(fullPathMod.Length);
684 Contract.Assert(fullSearchString.Length > fullPathMod.Length);
685 searchCriteria = fullSearchString.Substring(fullPathMod.Length + 1);
687 return searchCriteria;
690 private static String GetFullSearchString(String fullPath, String searchPattern)
692 Contract.Requires(fullPath != null);
693 Contract.Requires(searchPattern != null);
695 String tempStr = Path.InternalCombine(fullPath, searchPattern);
697 // If path ends in a trailing slash (\), append a * or we'll get a "Cannot find the file specified" exception
698 char lastChar = tempStr[tempStr.Length - 1];
699 if (Path.IsDirectorySeparator(lastChar) || lastChar == Path.VolumeSeparatorChar)
701 tempStr = tempStr + '*';
708 internal abstract class SearchResultHandler<TSource>
711 [System.Security.SecurityCritical]
712 internal abstract bool IsResultIncluded(SearchResult result);
714 [System.Security.SecurityCritical]
715 internal abstract TSource CreateObject(SearchResult result);
719 internal class StringResultHandler : SearchResultHandler<String>
721 private bool _includeFiles;
722 private bool _includeDirs;
724 internal StringResultHandler(bool includeFiles, bool includeDirs)
726 _includeFiles = includeFiles;
727 _includeDirs = includeDirs;
730 [System.Security.SecurityCritical]
731 internal override bool IsResultIncluded(SearchResult result)
733 bool includeFile = _includeFiles && FileSystemEnumerableHelpers.IsFile(result.FindData);
734 bool includeDir = _includeDirs && FileSystemEnumerableHelpers.IsDir(result.FindData);
735 Contract.Assert(!(includeFile && includeDir), result.FindData.cFileName + ": current item can't be both file and dir!");
736 return (includeFile || includeDir);
739 [System.Security.SecurityCritical]
740 internal override String CreateObject(SearchResult result)
742 return result.UserPath;
746 internal class FileInfoResultHandler : SearchResultHandler<FileInfo>
748 [System.Security.SecurityCritical]
749 internal override bool IsResultIncluded(SearchResult result)
751 return FileSystemEnumerableHelpers.IsFile(result.FindData);
754 [System.Security.SecurityCritical]
755 internal override FileInfo CreateObject(SearchResult result)
757 String name = result.FullPath;
760 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, name);
763 FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, name, false, false);
766 FileInfo fi = new FileInfo(name, false);
767 fi.InitializeFrom(result.FindData);
772 internal class DirectoryInfoResultHandler : SearchResultHandler<DirectoryInfo>
774 [System.Security.SecurityCritical]
775 internal override bool IsResultIncluded(SearchResult result)
777 return FileSystemEnumerableHelpers.IsDir(result.FindData);
780 [System.Security.SecurityCritical]
781 internal override DirectoryInfo CreateObject(SearchResult result)
783 String name = result.FullPath;
784 String permissionName = name + "\\.";
788 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, permissionName);
791 FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, permissionName, false, false);
794 DirectoryInfo di = new DirectoryInfo(name, false);
795 di.InitializeFrom(result.FindData);
800 internal class FileSystemInfoResultHandler : SearchResultHandler<FileSystemInfo>
803 [System.Security.SecurityCritical]
804 internal override bool IsResultIncluded(SearchResult result)
806 bool includeFile = FileSystemEnumerableHelpers.IsFile(result.FindData);
807 bool includeDir = FileSystemEnumerableHelpers.IsDir(result.FindData);
808 Contract.Assert(!(includeFile && includeDir), result.FindData.cFileName + ": current item can't be both file and dir!");
810 return (includeDir || includeFile);
813 [System.Security.SecurityCritical]
814 internal override FileSystemInfo CreateObject(SearchResult result)
816 bool isFile = FileSystemEnumerableHelpers.IsFile(result.FindData);
817 bool isDir = FileSystemEnumerableHelpers.IsDir(result.FindData);
821 String name = result.FullPath;
822 String permissionName = name + "\\.";
826 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, permissionName);
829 FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, permissionName, false, false);
832 DirectoryInfo di = new DirectoryInfo(name, false);
833 di.InitializeFrom(result.FindData);
838 Contract.Assert(isFile);
839 String name = result.FullPath;
843 FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, name);
846 FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, name, false, false);
849 FileInfo fi = new FileInfo(name, false);
850 fi.InitializeFrom(result.FindData);
857 internal sealed class SearchResult
859 private String fullPath; // fully-qualifed path
860 private String userPath; // user-specified path
861 [System.Security.SecurityCritical]
862 private Win32Native.WIN32_FIND_DATA findData;
864 [System.Security.SecurityCritical]
865 internal SearchResult(String fullPath, String userPath, Win32Native.WIN32_FIND_DATA findData)
867 Contract.Requires(fullPath != null);
868 Contract.Requires(userPath != null);
870 this.fullPath = fullPath;
871 this.userPath = userPath;
872 this.findData = findData;
875 internal String FullPath
877 get { return fullPath; }
880 internal String UserPath
882 get { return userPath; }
885 internal Win32Native.WIN32_FIND_DATA FindData
887 [System.Security.SecurityCritical]
888 get { return findData; }
893 internal static class FileSystemEnumerableHelpers
895 [System.Security.SecurityCritical] // auto-generated
896 internal static bool IsDir(Win32Native.WIN32_FIND_DATA data)
898 // Don't add "." nor ".."
900 return (0 != (data.dwFileAttributes & (int)Win32Native.FILE_ATTRIBUTE_DIRECTORY))
902 return (0 != (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY))
904 && !data.cFileName.Equals(".") && !data.cFileName.Equals("..");
907 [System.Security.SecurityCritical] // auto-generated
908 internal static bool IsFile(Win32Native.WIN32_FIND_DATA data)
911 return 0 == (data.dwFileAttributes & (int)Win32Native.FILE_ATTRIBUTE_DIRECTORY);
913 return 0 == (data.dwFileAttributes & Win32Native.FILE_ATTRIBUTE_DIRECTORY);