public void FinalPathNameLongPathPrefixRoundTripBehavior() { using (var cleaner = new TestFileCleaner(useDotNet: false)) { string longPath = PathGenerator.CreatePathOfLength(cleaner.TempFolder, 500); string filePath = Paths.Combine(longPath, Path.GetRandomFileName()); cleaner.FileService.CreateDirectory(longPath); cleaner.FileService.WriteAllText(filePath, "FinalPathNameLongPathPrefixRoundTripBehavior"); using (var handle = NativeMethods.FileManagement.CreateFile(filePath, FileAccess.Read, FileShare.ReadWrite, FileMode.Open, 0)) { handle.IsInvalid.Should().BeFalse(); string extendedPath = Paths.AddExtendedPrefix(filePath, addIfUnderLegacyMaxPath: true); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_NORMALIZED) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_OPENED) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_DOS) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_GUID) .Should().StartWith(@"\\?\Volume"); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_NT) .Should().StartWith(@"\Device\"); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_NONE) .Should().Be(filePath.Substring(2)); } } }
public void FinalPathNameVolumeNameBehavior() { // This test is asserting that the original volume name has nothing to do with the volume GetFinalPathNameByHandle returns using (var cleaner = new TestFileCleaner()) { string filePath = cleaner.CreateTestFile("FinalPathNameVolumeNameBehavior"); string canonicalRoot = cleaner.ExtendedFileService.GetCanonicalRoot(cleaner.FileService, filePath); string replacedPath = Paths.ReplaceRoot(canonicalRoot, filePath); using (var handle = NativeMethods.FileManagement.CreateFile(replacedPath.ToLower(), FileAccess.Read, FileShare.ReadWrite, FileMode.Open, 0)) { handle.IsInvalid.Should().BeFalse(); string extendedPath = Paths.AddExtendedPrefix(filePath, addIfUnderLegacyMaxPath: true); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_NORMALIZED) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_OPENED) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_DOS) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_GUID) .Should().StartWith(@"\\?\Volume"); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_NT) .Should().StartWith(@"\Device\"); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_NONE) .Should().Be(filePath.Substring(2)); } } }
public void FinalPathNameBehavior() { using (var cleaner = new TestFileCleaner()) { string filePath = cleaner.CreateTestFile("FinalPathNameBehavior"); using (var handle = NativeMethods.FileManagement.CreateFile(filePath.ToLower(), FileAccess.Read, FileShare.ReadWrite, FileMode.Open, 0)) { handle.IsInvalid.Should().BeFalse(); string extendedPath = Paths.AddExtendedPrefix(filePath, addIfUnderLegacyMaxPath: true); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_NORMALIZED) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_OPENED) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_DOS) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_GUID) .Should().StartWith(@"\\?\Volume"); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_NT) .Should().StartWith(@"\Device\"); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.VOLUME_NAME_NONE) .Should().Be(filePath.Substring(2)); } } }
public virtual void Refresh() { try { switch (_source) { case Source.Attributes: System.IO.FileAttributes attributes = (System.IO.FileAttributes)Storage.GetFileAttributesExtended(Paths.AddExtendedPrefix(Path)).FileAttributes; PopulateData(Path, attributes); break; case Source.FindResult: case Source.FileInfo: using (SafeFileHandle fileHandle = GetFileHandle(Path)) { var info = Storage.GetFileBasicInformation(fileHandle); PopulateData(Path, fileHandle, info); } break; } } catch (System.IO.FileNotFoundException) { Exists = false; } }
internal static IEnumerable <AlternateStreamInformation> GetAlternateStreamInformation(string path) { List <AlternateStreamInformation> streams = new List <AlternateStreamInformation>(); path = Paths.AddExtendedPrefix(path); using (var fileHandle = FileManagement.CreateFile( path, // To look at metadata we don't need read or write access 0, FileShare.ReadWrite, FileMode.Open, FileManagement.AllFileAttributeFlags.FILE_FLAG_BACKUP_SEMANTICS)) { using (BackupReader reader = new BackupReader(fileHandle)) { StreamInfo?info; while ((info = reader.GetNextInfo()).HasValue) { if (info.Value.Type == BackupStreamType.BACKUP_ALTERNATE_DATA) { streams.Add(new AlternateStreamInformation { Name = info.Value.Name, Size = info.Value.Size }); } } } } return(streams); }
internal static SafeFileHandle CreateFile( string path, FileAccess fileAccess, FileShare fileShare, FileMode creationDisposition, AllFileAttributeFlags flagsAndAttributes) { path = Paths.AddExtendedPrefix(path); if (creationDisposition == FileMode.Append) { creationDisposition = FileMode.OpenOrCreate; } uint dwDesiredAccess = ((fileAccess & FileAccess.Read) != 0 ? Private.GENERIC_READ : 0) | ((fileAccess & FileAccess.Write) != 0 ? Private.GENERIC_WRITE : 0); SafeFileHandle handle = Private.CreateFileW(path, dwDesiredAccess, fileShare, IntPtr.Zero, creationDisposition, flagsAndAttributes, IntPtr.Zero); if (handle.IsInvalid) { int error = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(error, path); } return(handle); }
public void SetAttributes(string path, System.IO.FileAttributes attributes) { if (path == null) { throw new ArgumentNullException(nameof(path)); } Storage.SetFileAttributes(Paths.AddExtendedPrefix(NormalizeIfNotExtended(path)), (FileAttributes)attributes); }
public System.IO.FileAttributes GetAttributes(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } return((System.IO.FileAttributes)Storage.GetFileAttributesExtended(Paths.AddExtendedPrefix(NormalizeIfNotExtended(path))).FileAttributes); }
public void DeleteFile(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } Storage.DeleteFile(Paths.AddExtendedPrefix(NormalizeIfNotExtended(path))); }
/// <summary> /// Returns the find information. /// </summary> /// <param name="directoriesOnly">Attempts to filter to just directories where supported.</param> /// <param name="getAlternateName">Returns the alternate (short) file name in the FindResult.AlternateName field if it exists.</param> internal static FindResult FindFirstFile( string path, bool directoriesOnly = false, bool getAlternateName = false, bool returnNullIfNotFound = true) { if (Paths.EndsInDirectorySeparator(path)) { // Find first file does not like trailing separators so we'll cull it // // There is one weird special case. If we're passed a legacy root volume (e.g. C:\) then removing the // trailing separator will make the path drive relative, leading to whatever the current directory is // on that particular drive (randomness). (System32 for some odd reason in my tests.) // // You can't find a volume on it's own anyway, so we'll exit out in this case. For C: without a // trailing slash it is legitimate to try and find whatever that matches. Note that we also don't need // to bother checking the first character, as anything else there would be invalid. path = Paths.RemoveTrailingSeparators(path); if ((path.Length == 2 && path[1] == ':') || // C: (path.Length == 6 && path[5] == ':' && path.StartsWith(Paths.ExtendedPathPrefix))) // \\?\C: { if (returnNullIfNotFound) { return(null); } throw GetIoExceptionForError(WinError.ERROR_FILE_NOT_FOUND, path); } } path = Paths.AddExtendedPrefix(path); WIN32_FIND_DATA findData; SafeFindHandle handle = Private.FindFirstFileExW( path, getAlternateName ? FINDEX_INFO_LEVELS.FindExInfoStandard : FINDEX_INFO_LEVELS.FindExInfoBasic, out findData, // FINDEX_SEARCH_OPS.FindExSearchNameMatch is what FindFirstFile calls Ex wtih directoriesOnly ? FINDEX_SEARCH_OPS.FindExSearchLimitToDirectories :FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, FIND_FIRST_EX_LARGE_FETCH); if (handle.IsInvalid) { int error = Marshal.GetLastWin32Error(); if (error == WinError.ERROR_FILE_NOT_FOUND && returnNullIfNotFound) { return(null); } throw GetIoExceptionForError(error, path); } return(new FindResult(handle, findData, Paths.GetDirectory(path))); }
internal static void CreateDirectory(string path) { // CreateDirectory will refuse paths that are over MAX_PATH - 12, so we always want to add the prefix path = Paths.AddExtendedPrefix(path, addIfUnderLegacyMaxPath: true); if (!Private.CreateDirectoryW(path, IntPtr.Zero)) { int error = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(error, path); } }
internal static void RemoveDirectory(string path) { path = Paths.AddExtendedPrefix(NativeMethods.FileManagement.GetFullPathName(path)); if (!Private.RemoveDirectoryW(path)) { int error = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(error, path); } }
internal static void DeleteFile(string path) { Debug.Assert(!Paths.IsRelative(path)); // Can't delete Posix files (end with "." for example) unless we've got the prefix path = Paths.AddExtendedPrefix(path, addIfUnderLegacyMaxPath: true); if (!Private.DeleteFileW(path)) { int error = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(error, path); } }
private static SafeFileHandle GetFileHandle(string path) { return(Storage.CreateFile( Paths.AddExtendedPrefix(path), CreationDisposition.OpenExisting, // We don't care about read or write, we're just getting metadata with this handle 0, ShareModes.ReadWrite, FileAttributes.None, FileFlags.OpenReparsePoint // To avoid traversing links | FileFlags.BackupSemantics)); // To open directories }
public void CreateFileExtendedTests(string fileName) { using (var cleaner = new TestFileCleaner()) { string filePath = Paths.AddExtendedPrefix(Paths.Combine(cleaner.TempFolder, fileName), addIfUnderLegacyMaxPath: true); using (var handle = NativeMethods.FileManagement.CreateFile(filePath, FileAccess.ReadWrite, FileShare.ReadWrite, FileMode.Create, 0)) { handle.IsInvalid.Should().BeFalse(); NativeMethods.FileManagement.FlushFileBuffers(handle); NativeMethods.FileManagement.FileExists(filePath).Should().BeTrue(); } } }
public void CreateDirectory(string path) { if (path == null) { throw new ArgumentNullException(nameof(path)); } path = GetFullPath(path); int pathRootLength = Paths.GetRootLength(path); if (pathRootLength < 0) { throw WindowsError.ERROR_BAD_PATHNAME.GetException(); } int i = pathRootLength; string subDirectory; while (i > 0 && i < path.Length) { i = path.IndexOf(Paths.DirectorySeparator, i); if (i == -1) { subDirectory = path; i = path.Length; } else { subDirectory = path.Substring(0, i); i++; } // CreateDirectory will refuse paths that are over MAX_PATH - 12, so we always want to add the prefix subDirectory = Paths.AddExtendedPrefix(subDirectory, addIfUnderLegacyMaxPath: true); var info = Storage.TryGetFileInfo(Paths.AddExtendedPrefix(subDirectory)); if (!info.HasValue) { // Doesn't exist, try to create it Storage.CreateDirectory(subDirectory); } else if ((info.Value.FileAttributes & FileAttributes.Directory) == FileAttributes.Directory) { // Directory exists, move on continue; } else { // File exists throw WindowsError.ERROR_FILE_EXISTS.GetException(subDirectory); } } }
internal static FileAttributes GetFileAttributes(string path) { path = Paths.AddExtendedPrefix(path); FileAttributes result = Private.GetFileAttributesW(path); if (result == InvalidFileAttributes) { int error = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(error, path); } return(result); }
public void LoadAsBinaryFromLongPath() { using (var cleaner = new TestFileCleaner(useDotNet: false)) { string longPath = PathGenerator.CreatePathOfLength(cleaner.TempFolder, 500); cleaner.FileService.CreateDirectory(longPath); string longPathLibrary = Paths.Combine(longPath, "LoadAsBinaryFromLongPath.dll"); cleaner.FileService.CopyFile(GetNativeTestLibraryLocation(), longPathLibrary); longPathLibrary = Paths.AddExtendedPrefix(longPathLibrary); using (var handle = NativeMethods.LoadLibrary(longPathLibrary, LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH)) { handle.IsInvalid.Should().BeFalse(); } } }
public void CopyFile(string existingPath, string newPath, bool overwrite = false) { if (existingPath == null) { throw new ArgumentNullException(nameof(existingPath)); } if (newPath == null) { throw new ArgumentNullException(nameof(newPath)); } Storage.CopyFile( Paths.AddExtendedPrefix(NormalizeIfNotExtended(existingPath)), Paths.AddExtendedPrefix(NormalizeIfNotExtended(newPath)), overwrite); }
public void LoadStringFromLongPath() { using (var cleaner = new TestFileCleaner(useDotNet: false)) { string longPath = PathGenerator.CreatePathOfLength(cleaner.TempFolder, 500); cleaner.FileService.CreateDirectory(longPath); string longPathLibrary = Paths.Combine(longPath, "LoadStringFromLongPath.dll"); cleaner.FileService.CopyFile(GetNativeTestLibraryLocation(), longPathLibrary); longPathLibrary = Paths.AddExtendedPrefix(longPathLibrary); using (var handle = NativeMethods.LoadLibrary(longPathLibrary, LoadLibraryFlags.LOAD_LIBRARY_AS_IMAGE_RESOURCE | LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE)) { string resource = NativeMethods.LoadString(handle, 101); resource.Should().Be("Test"); } } }
public void LoadFunctionFromLongPath() { using (var cleaner = new TestFileCleaner(useDotNet: false)) { string longPath = PathGenerator.CreatePathOfLength(cleaner.TempFolder, 500); cleaner.FileService.CreateDirectory(longPath); string longPathLibrary = Paths.Combine(longPath, "LoadFunctionFromLongPath.dll"); cleaner.FileService.CopyFile(GetNativeTestLibraryLocation(), longPathLibrary); longPathLibrary = Paths.AddExtendedPrefix(longPathLibrary); using (var handle = NativeMethods.LoadLibrary(longPathLibrary, 0)) { var doubler = NativeMethods.GetFunctionDelegate <DoubleDelegate>(handle, "Double"); doubler(2).Should().Be(4); } } }
public System.IO.Stream CreateFileStream(string path, System.IO.FileMode mode = System.IO.FileMode.Open, System.IO.FileAccess access = System.IO.FileAccess.Read, System.IO.FileShare share = System.IO.FileShare.ReadWrite) { if (path == null) { throw new ArgumentNullException(nameof(path)); } path = Paths.AddExtendedPrefix(NormalizeIfNotExtended(path)); // Flags match what FileStream does internally return(Storage.CreateFileStream( path, access, share, mode, fileAttributes: 0, fileFlags: FileFlags.None, securityFlags: SecurityQosFlags.QosPresent | SecurityQosFlags.Anonymous)); }
public void DeleteDirectory(string path, bool deleteChildren = false) { if (path == null) { throw new ArgumentNullException(nameof(path)); } // Always add the prefix to ensure we can delete Posix names (end in space/period) path = Paths.AddExtendedPrefix(NativeMethods.FileManagement.GetFullPathName(path), addIfUnderLegacyMaxPath: true); if (deleteChildren) { this.DeleteDirectoryRecursive(path); } else { NativeMethods.DirectoryManagement.RemoveDirectory(path); } }
public void DeleteDirectory(string path, bool deleteChildren = false) { if (path == null) { throw new ArgumentNullException(nameof(path)); } // Always add the prefix to ensure we can delete Posix names (end in space/period) path = Paths.AddExtendedPrefix(NormalizeIfNotExtended(path), addIfUnderLegacyMaxPath: true); if (deleteChildren) { DeleteDirectoryRecursive(path); } else { Storage.RemoveDirectory(path); } }
private static FileAttributes TryGetFileAttributesPrivate(string path) { path = Paths.AddExtendedPrefix(path); FileAttributes result = Private.GetFileAttributesW(path); if (result == InvalidFileAttributes) { int error = Marshal.GetLastWin32Error(); switch (error) { case WinError.ERROR_ACCESS_DENIED: case WinError.ERROR_NETWORK_ACCESS_DENIED: throw new UnauthorizedAccessException(String.Format(CultureInfo.InvariantCulture, "{0} : '{1}'", NativeErrorHelper.LastErrorToString(error), path)); } } return(result); }
internal static void CopyFile(string existingPath, string newPath, bool overwrite) { existingPath = Paths.AddExtendedPrefix(existingPath); newPath = Paths.AddExtendedPrefix(newPath); bool cancel = false; if (!Private.CopyFileExW( existingPath, newPath, null, IntPtr.Zero, ref cancel, overwrite ? 0 : CopyFileFlags.COPY_FILE_FAIL_IF_EXISTS)) { int error = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(error, existingPath); } }
public void FinalPathNameLinkBehavior() { var extendedFileService = new ExtendedFileService(); if (!extendedFileService.CanCreateSymbolicLinks()) { return; } // GetFinalPathName always points to the linked file unless you specifically open the reparse point using (var cleaner = new TestFileCleaner()) { string filePath = Paths.Combine(cleaner.TempFolder, "Target"); string extendedPath = Paths.AddExtendedPrefix(filePath, addIfUnderLegacyMaxPath: true); cleaner.FileService.WriteAllText(filePath, "CreateSymbolicLinkToFile"); string symbolicLink = Paths.Combine(cleaner.TempFolder, "Link"); string extendedLink = Paths.AddExtendedPrefix(symbolicLink, addIfUnderLegacyMaxPath: true); NativeMethods.FileManagement.CreateSymbolicLink(symbolicLink, filePath); NativeMethods.FileManagement.FileExists(symbolicLink).Should().BeTrue("symbolic link should exist"); // GetFinalPathName should normalize the casing, pushing ToUpper to validate using (var handle = NativeMethods.FileManagement.CreateFile(symbolicLink.ToUpperInvariant(), FileAccess.Read, FileShare.ReadWrite, FileMode.Open, 0)) { handle.IsInvalid.Should().BeFalse(); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_NORMALIZED) .Should().Be(extendedPath); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_OPENED) .Should().Be(extendedPath); } using (var handle = NativeMethods.FileManagement.CreateFile(symbolicLink.ToUpperInvariant(), FileAccess.Read, FileShare.ReadWrite, FileMode.Open, NativeMethods.FileManagement.AllFileAttributeFlags.FILE_FLAG_OPEN_REPARSE_POINT)) { handle.IsInvalid.Should().BeFalse(); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_NORMALIZED) .Should().Be(extendedLink); NativeMethods.FileManagement.GetFinalPathName(handle, NativeMethods.FileManagement.FinalPathFlags.FILE_NAME_OPENED) .Should().Be(extendedLink); } } }
internal static IEnumerable <IFileSystemInformation> EnumerateChildrenInternal( string directory, ChildType childType, string searchPattern, System.IO.SearchOption searchOption, FileAttributes excludeAttributes, IFileService fileService) { // We want to be able to see all files as we recurse and open new find handles (that might be over MAX_PATH). // We've already normalized our base directory. string extendedDirectory = Paths.AddExtendedPrefix(directory); var transformFilter = new FindTransformFilter(excludeAttributes, fileService); FindOperation <IFileSystemInformation> findOperation = new FindOperation <IFileSystemInformation>( extendedDirectory, searchPattern, recursive: searchOption == System.IO.SearchOption.AllDirectories ? true : false, transformFilter, transformFilter); return(findOperation); }
internal static string GetFinalPathName(string path, FinalPathFlags finalPathFlags, bool resolveLinks) { if (path == null) { return(null); } string lookupPath = Paths.AddExtendedPrefix(path); // BackupSemantics is needed to get directory handles AllFileAttributeFlags createFileFlags = AllFileAttributeFlags.FILE_ATTRIBUTE_NORMAL | AllFileAttributeFlags.FILE_FLAG_BACKUP_SEMANTICS; if (!resolveLinks) { createFileFlags |= AllFileAttributeFlags.FILE_FLAG_OPEN_REPARSE_POINT; } string finalPath = null; using (SafeFileHandle file = CreateFile( lookupPath, // To look at metadata we don't need read or write access 0, FileShare.ReadWrite, FileMode.Open, createFileFlags)) { if (file.IsInvalid) { int error = Marshal.GetLastWin32Error(); throw GetIoExceptionForError(error, path); } finalPath = NativeMethods.BufferInvoke((buffer) => Private.GetFinalPathNameByHandleW(file, buffer, (uint)buffer.CharCapacity, finalPathFlags), path); } // GetFinalPathNameByHandle will use the legacy drive for the volume (e.g. \\?\C:\). We may have started with \\?\Volume({GUID}) or some // other volume name format (C:\, etc.) we want to put it back. return(Paths.ReplaceRoot(path, finalPath)); }
public string GetShortPath(string path) { return(Storage.GetShortPathName(Paths.AddExtendedPrefix(path))); }