private SafeFindFileHandle FindFirstFile(string pathLp, out NativeMethods.WIN32_FIND_DATA win32FindData) { SafeFindFileHandle handle = Transaction == null || !NativeMethods.IsAtLeastWindowsVista // FindFirstFileEx() / FindFirstFileTransacted() // In the ANSI version of this function, the name is limited to MAX_PATH characters. // To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. // 2013-01-13: MSDN confirms LongPath usage. // A trailing backslash is not allowed. ? NativeMethods.FindFirstFileEx(Path.RemoveTrailingDirectorySeparator(pathLp, false), FindExInfoLevel, out win32FindData, _limitSearchToDirs, IntPtr.Zero, LargeCache) : NativeMethods.FindFirstFileTransacted(Path.RemoveTrailingDirectorySeparator(pathLp, false), FindExInfoLevel, out win32FindData, _limitSearchToDirs, IntPtr.Zero, LargeCache, Transaction.SafeHandle); int lastError = Marshal.GetLastWin32Error(); if (handle != null && handle.IsInvalid) { handle.Close(); if (!ContinueOnException) { switch ((uint)lastError) { case Win32Errors.ERROR_FILE_NOT_FOUND: case Win32Errors.ERROR_PATH_NOT_FOUND: // MSDN: .NET 3.5+: DirectoryNotFoundException: Path is invalid, such as referring to an unmapped drive. // Directory.Delete() NativeError.ThrowException(IsDirectory ? (int)Win32Errors.ERROR_PATH_NOT_FOUND : Win32Errors.ERROR_FILE_NOT_FOUND, pathLp); break; case Win32Errors.ERROR_DIRECTORY: // MSDN: .NET 3.5+: IOException: path is a file name. // Directory.EnumerateDirectories() // Directory.EnumerateFiles() // Directory.EnumerateFileSystemEntries() // Directory.GetDirectories() // Directory.GetFiles() // Directory.GetFileSystemEntries() NativeError.ThrowException(lastError, pathLp); break; case Win32Errors.ERROR_ACCESS_DENIED: // MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission. NativeError.ThrowException(lastError, pathLp); break; } // MSDN: .NET 3.5+: IOException NativeError.ThrowException(lastError, pathLp); } } return(handle); }
public FileSystemEntryInfo Get() { NativeMethods.Win32FindData win32FindData; // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups. using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors)) using (SafeFindFileHandle handle = FindFirstFile(InputPath, out win32FindData)) { return(handle.IsInvalid ? null : new FileSystemEntryInfo(win32FindData) { FullPath = InputPath }); } }
public T Get <T>() { NativeMethods.WIN32_FIND_DATA win32FindData; // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups. using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors)) using (SafeFindFileHandle handle = FindFirstFile(InputPath, out win32FindData)) { if (handle != null && !handle.IsInvalid) { return(NewFileSystemEntryType <T>(win32FindData, InputPath, (win32FindData.dwFileAttributes & FileAttributes.Directory) != 0)); } } return((T)(object)null); }
/// <summary>[AlphaFS] Enumerates the streams of type :$DATA from the specified file or directory.</summary> /// <param name="transaction">The transaction.</param> /// <param name="path">The path to the file or directory to enumerate streams of.</param> /// <param name="pathFormat">Indicates the format of the path parameter(s).</param> /// <returns>The streams of type :$DATA in the specified file or directory.</returns> internal static IEnumerable <AlternateDataStreamInfo> EnumerateAlternateDataStreamsCore(KernelTransaction transaction, string path, PathFormat pathFormat) { using (var buffer = new SafeGlobalMemoryBufferHandle(Marshal.SizeOf(typeof(NativeMethods.WIN32_FIND_STREAM_DATA)))) { string pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.CheckInvalidPathChars | GetFullPathOptions.CheckAdditional); using (SafeFindFileHandle handle = transaction == null ? NativeMethods.FindFirstStreamW(pathLp, NativeMethods.STREAM_INFO_LEVELS.FindStreamInfoStandard, buffer, 0) : NativeMethods.FindFirstStreamTransactedW(pathLp, NativeMethods.STREAM_INFO_LEVELS.FindStreamInfoStandard, buffer, 0, transaction.SafeHandle)) { int errorCode = Marshal.GetLastWin32Error(); if (handle.IsInvalid) { if (errorCode == Win32Errors.ERROR_HANDLE_EOF) { yield break; } NativeError.ThrowException(errorCode); } while (true) { yield return(new AlternateDataStreamInfo(pathLp, buffer.PtrToStructure <NativeMethods.WIN32_FIND_STREAM_DATA>(0))); if (!NativeMethods.FindNextStreamW(handle, buffer)) { int lastError = Marshal.GetLastWin32Error(); if (lastError == Win32Errors.ERROR_HANDLE_EOF) { break; } NativeError.ThrowException(lastError, pathLp); } } } } }
static internal extern bool FindNextFileW([In] SafeFindFileHandle hFindFile, [In, Out] WIN32_FIND_DATA lpFindFileData);
internal static int FillAttributeInfoCore(KernelTransaction transaction, string pathLp, ref NativeMethods.WIN32_FILE_ATTRIBUTE_DATA win32AttrData, bool tryagain, bool returnErrorOnNotFound) { int dataInitialised = (int)Win32Errors.ERROR_SUCCESS; #region Try Again // Someone has a handle to the file open, or other error. if (tryagain) { NativeMethods.WIN32_FIND_DATA findData; // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups. using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors)) { bool error = false; SafeFindFileHandle handle = transaction == null || !NativeMethods.IsAtLeastWindowsVista // FindFirstFileEx() / FindFirstFileTransacted() // In the ANSI version of this function, the name is limited to MAX_PATH characters. // To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. // 2013-01-13: MSDN confirms LongPath usage. // A trailing backslash is not allowed. ? NativeMethods.FindFirstFileEx(Path.RemoveTrailingDirectorySeparator(pathLp, false), NativeMethods.FindexInfoLevels, out findData, NativeMethods.FINDEX_SEARCH_OPS.SearchNameMatch, IntPtr.Zero, NativeMethods.LargeCache) : NativeMethods.FindFirstFileTransacted(Path.RemoveTrailingDirectorySeparator(pathLp, false), NativeMethods.FindexInfoLevels, out findData, NativeMethods.FINDEX_SEARCH_OPS.SearchNameMatch, IntPtr.Zero, NativeMethods.LargeCache, transaction.SafeHandle); try { if (handle != null && handle.IsInvalid) { error = true; dataInitialised = Marshal.GetLastWin32Error(); if (dataInitialised == Win32Errors.ERROR_FILE_NOT_FOUND || dataInitialised == Win32Errors.ERROR_PATH_NOT_FOUND || dataInitialised == Win32Errors.ERROR_NOT_READY) // Floppy device not ready. { if (!returnErrorOnNotFound) { // Return default value for backward compatibility dataInitialised = (int)Win32Errors.ERROR_SUCCESS; win32AttrData.dwFileAttributes = (FileAttributes)(-1); } } return(dataInitialised); } } finally { try { if (handle != null) { handle.Close(); } } catch { // If we're already returning an error, don't throw another one. if (!error) { NativeError.ThrowException(dataInitialised, pathLp); } } } } // Copy the attribute information. win32AttrData = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA(findData); } #endregion // Try Again else { using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors)) { if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista // GetFileAttributesEx() / GetFileAttributesTransacted() // In the ANSI version of this function, the name is limited to MAX_PATH characters. // To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. // 2013-01-13: MSDN confirms LongPath usage. ? NativeMethods.GetFileAttributesEx(pathLp, NativeMethods.GetFileExInfoLevels.GetFileExInfoStandard, out win32AttrData) : NativeMethods.GetFileAttributesTransacted(pathLp, NativeMethods.GetFileExInfoLevels.GetFileExInfoStandard, out win32AttrData, transaction.SafeHandle))) { dataInitialised = Marshal.GetLastWin32Error(); if (dataInitialised != Win32Errors.ERROR_FILE_NOT_FOUND && dataInitialised != Win32Errors.ERROR_PATH_NOT_FOUND && dataInitialised != Win32Errors.ERROR_NOT_READY) // Floppy device not ready. { // In case someone latched onto the file. Take the perf hit only for failure. return(FillAttributeInfoCore(transaction, pathLp, ref win32AttrData, true, returnErrorOnNotFound)); } if (!returnErrorOnNotFound) { // Return default value for backward compbatibility. dataInitialised = (int)Win32Errors.ERROR_SUCCESS; win32AttrData.dwFileAttributes = (FileAttributes)(-1); } } } } return(dataInitialised); }
public IEnumerable <FileSystemEntryInfo> Enumerate() { // MSDN: Queue // Represents a first-in, first-out collection of objects. // The capacity of a Queue is the number of elements the Queue can hold. // As elements are added to a Queue, the capacity is automatically increased as required through reallocation. The capacity can be decreased by calling TrimToSize. // The growth factor is the number by which the current capacity is multiplied when a greater capacity is required. The growth factor is determined when the Queue is constructed. // The capacity of the Queue will always increase by a minimum value, regardless of the growth factor; a growth factor of 1.0 will not prevent the Queue from increasing in size. // If the size of the collection can be estimated, specifying the initial capacity eliminates the need to perform a number of resizing operations while adding elements to the Queue. // This constructor is an O(n) operation, where n is capacity. Queue <string> dirs = new Queue <string>(1000); // Removes the object at the beginning of your Queue. // The algorithmic complexity of this is O(1). It doesn't loop over elements. dirs.Enqueue(InputPath); // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups. using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors)) while (dirs.Count > 0) { string path = Path.AddDirectorySeparator(dirs.Dequeue(), false); string pathLp = path + Path.WildcardStarMatchAll; NativeMethods.Win32FindData win32FindData; using (SafeFindFileHandle handle = FindFirstFile(pathLp, out win32FindData)) { if (handle.IsInvalid && ContinueOnException) { continue; } do { string fileName = win32FindData.FileName; switch (fileName) { // Skip entries. case ".": case "..": break; default: string fullPathLp = path + fileName; bool fseiIsDir = (win32FindData.FileAttributes & FileAttributes.Directory) == FileAttributes.Directory; // Or not: Skip on reparse points here to cleanly separate regular directories from links. if (SkipReparsePoints && (win32FindData.FileAttributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint) { continue; } // If object is a directory, add it to the queue for later traversal. if (fseiIsDir && _searchAllDirs) { dirs.Enqueue(fullPathLp); } if (!(_nameFilter == null || (_nameFilter != null && _nameFilter.IsMatch(fileName)))) { break; } // Make sure the requested file system object type is returned. // null = Return files and directories. // true = Return only directories. // false = Return only files. switch (FileSystemObjectType) { case null: yield return(new FileSystemEntryInfo(win32FindData) { FullPath = fullPathLp }); break; case true: if (fseiIsDir) { yield return new FileSystemEntryInfo(win32FindData) { FullPath = fullPathLp } } ; break; case false: if (!fseiIsDir) { yield return new FileSystemEntryInfo(win32FindData) { FullPath = fullPathLp } } ; break; } break; } } while (NativeMethods.FindNextFile(handle, out win32FindData)); uint lastError = (uint)Marshal.GetLastWin32Error(); switch (lastError) { case Win32Errors.ERROR_NO_MORE_FILES: lastError = Win32Errors.NO_ERROR; break; case Win32Errors.ERROR_FILE_NOT_FOUND: case Win32Errors.ERROR_PATH_NOT_FOUND: if (lastError == Win32Errors.ERROR_FILE_NOT_FOUND && IsFolder) { lastError = Win32Errors.ERROR_PATH_NOT_FOUND; } break; } if (!ContinueOnException && lastError != Win32Errors.NO_ERROR) { NativeError.ThrowException(lastError, InputPath); } } } }
internal static extern bool FindNextStreamW(SafeFindFileHandle handle, SafeGlobalMemoryBufferHandle lpFindStreamData);
internal static extern bool FindNextFileName(SafeFindFileHandle hFindStream, [MarshalAs(UnmanagedType.U4)] out uint stringLength, StringBuilder linkName);
internal static extern bool FindNextFile(SafeFindFileHandle hFindFile, out Win32FindData lpFindFileData);
/// <summary>[AlphaFS] Creates an enumeration of all the hard links to the specified <paramref name="path"/>.</summary> /// <exception cref="PlatformNotSupportedException">Thrown when a Platform Not Supported error condition occurs.</exception> /// <param name="transaction">The transaction.</param> /// <param name="path">The name of the file.</param> /// <param name="pathFormat">Indicates the format of the path parameter(s).</param> /// <returns>An enumerable collection of <see cref="string"/> of all the hard links to the specified <paramref name="path"/></returns> internal static IEnumerable <string> EnumerateHardlinksInternal(KernelTransaction transaction, string path, PathFormat pathFormat) { if (!NativeMethods.IsAtLeastWindowsVista) { throw new PlatformNotSupportedException(Resources.RequiresWindowsVistaOrHigher); } string pathLp = Path.GetExtendedLengthPathInternal(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck); // Default buffer length, will be extended if needed, although this should not happen. uint length = NativeMethods.MaxPathUnicode; StringBuilder builder = new StringBuilder((int)length); getFindFirstFileName: using (SafeFindFileHandle handle = transaction == null // FindFirstFileName() / FindFirstFileNameTransacted() // In the ANSI version of this function, the name is limited to MAX_PATH characters. // To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path. // 2013-01-13: MSDN does not confirm LongPath usage but a Unicode version of this function exists. ? NativeMethods.FindFirstFileName(pathLp, 0, out length, builder) : NativeMethods.FindFirstFileNameTransacted(pathLp, 0, out length, builder, transaction.SafeHandle)) { if (handle.IsInvalid) { int lastError = Marshal.GetLastWin32Error(); switch ((uint)lastError) { case Win32Errors.ERROR_MORE_DATA: builder = new StringBuilder((int)length); handle.Close(); goto getFindFirstFileName; default: // If the function fails, the return value is INVALID_HANDLE_VALUE. NativeError.ThrowException(lastError, pathLp); break; } } yield return(builder.ToString()); //length = NativeMethods.MaxPathUnicode; //builder = new StringBuilder((int)length); do { while (!NativeMethods.FindNextFileName(handle, out length, builder)) { int lastError = Marshal.GetLastWin32Error(); switch ((uint)lastError) { // We've reached the end of the enumeration. case Win32Errors.ERROR_HANDLE_EOF: yield break; case Win32Errors.ERROR_MORE_DATA: builder = new StringBuilder((int)length); continue; default: //If the function fails, the return value is zero (0). NativeError.ThrowException(lastError); break; } } yield return(builder.ToString()); } while (true); } }
static internal extern bool FindNextFileW([In] SafeFindFileHandle hFindFile, [In, Out] FileSystemEntryInfo lpFindFileData);
public IEnumerable <T> Enumerate <T>() { // MSDN: Queue // Represents a first-in, first-out collection of objects. // The capacity of a Queue is the number of elements the Queue can hold. // As elements are added to a Queue, the capacity is automatically increased as required through reallocation. The capacity can be decreased by calling TrimToSize. // The growth factor is the number by which the current capacity is multiplied when a greater capacity is required. The growth factor is determined when the Queue is constructed. // The capacity of the Queue will always increase by a minimum value, regardless of the growth factor; a growth factor of 1.0 will not prevent the Queue from increasing in size. // If the size of the collection can be estimated, specifying the initial capacity eliminates the need to perform a number of resizing operations while adding elements to the Queue. // This constructor is an O(n) operation, where n is capacity. var dirs = new Queue <string>(1000); // Removes the object at the beginning of your Queue. // The algorithmic complexity of this is O(1). It doesn't loop over elements. dirs.Enqueue(InputPath); // ChangeErrorMode is for the Win32 SetThreadErrorMode() method, used to suppress possible pop-ups. using (new NativeMethods.ChangeErrorMode(NativeMethods.ErrorMode.FailCriticalErrors)) while (dirs.Count > 0) { string path = Path.AddTrailingDirectorySeparator(dirs.Dequeue(), false); string pathLp = path + Path.WildcardStarMatchAll; NativeMethods.WIN32_FIND_DATA win32FindData; using (SafeFindFileHandle handle = FindFirstFile(pathLp, out win32FindData)) { if (handle != null && handle.IsInvalid && ContinueOnException) { handle.Close(); continue; } do { string fileName = win32FindData.cFileName; // Skip entries "." and ".." if (fileName.Equals(Path.CurrentDirectoryPrefix, StringComparison.OrdinalIgnoreCase) || fileName.Equals(Path.ParentDirectoryPrefix, StringComparison.OrdinalIgnoreCase)) { continue; } // Skip reparse points here to cleanly separate regular directories from links. if (SkipReparsePoints && (win32FindData.dwFileAttributes & FileAttributes.ReparsePoint) != 0) { continue; } string fseiFullPathLp = path + fileName; bool fseiIsFolder = (win32FindData.dwFileAttributes & FileAttributes.Directory) != 0; // If object is a directory, add it to the queue for later traversal. if (fseiIsFolder && Recursive) { dirs.Enqueue(fseiFullPathLp); } // Determine yield. if (!(_nameFilter == null || (_nameFilter != null && _nameFilter.IsMatch(fileName)))) { continue; } var res = NewFileSystemEntryType <T>(win32FindData, fseiFullPathLp, fseiIsFolder); if (res == null) { continue; } yield return(res); } while (NativeMethods.FindNextFile(handle, out win32FindData)); var lastError = (uint)Marshal.GetLastWin32Error(); if (!ContinueOnException) { switch (lastError) { case Win32Errors.ERROR_NO_MORE_FILES: lastError = Win32Errors.NO_ERROR; break; case Win32Errors.ERROR_FILE_NOT_FOUND: case Win32Errors.ERROR_PATH_NOT_FOUND: if (lastError == Win32Errors.ERROR_FILE_NOT_FOUND && IsDirectory) { lastError = Win32Errors.ERROR_PATH_NOT_FOUND; } break; } if (lastError != Win32Errors.NO_ERROR) { NativeError.ThrowException(lastError, pathLp); } } } } }