internal static void EncryptDecryptFileCore(bool isFolder, string path, bool encrypt, PathFormat pathFormat) { if (pathFormat != PathFormat.LongFullPath) { path = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck); pathFormat = PathFormat.LongFullPath; } // MSDN: If lpFileName specifies a read-only file, the function fails and GetLastError returns ERROR_FILE_READ_ONLY. var attrs = GetAttributesExCore <NativeMethods.WIN32_FILE_ATTRIBUTE_DATA>(null, path, pathFormat, true); var isReadOnly = (attrs.dwFileAttributes & FileAttributes.ReadOnly) != 0; if (isReadOnly) { SetAttributesCore(null, isFolder, path, attrs.dwFileAttributes &= ~FileAttributes.ReadOnly, pathFormat); } // EncryptFile() / DecryptFile() // 2013-01-13: MSDN does not confirm LongPath usage but a Unicode version of this function exists. var success = encrypt ? NativeMethods.EncryptFile(path) : NativeMethods.DecryptFile(path, 0); var lastError = Marshal.GetLastWin32Error(); if (isReadOnly) { var isHidden = (attrs.dwFileAttributes & FileAttributes.Hidden) != 0; // Get most current attributes. attrs = GetAttributesExCore <NativeMethods.WIN32_FILE_ATTRIBUTE_DATA>(null, path, pathFormat, true); attrs.dwFileAttributes |= FileAttributes.ReadOnly; if (isHidden) { attrs.dwFileAttributes |= FileAttributes.Hidden; } SetAttributesCore(null, isFolder, path, attrs.dwFileAttributes, pathFormat); } if (!success) { switch ((uint)lastError) { case Win32Errors.ERROR_ACCESS_DENIED: if (!string.Equals("NTFS", new DriveInfo(path).DriveFormat, StringComparison.OrdinalIgnoreCase)) { throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The drive does not support NTFS encryption: [{0}]", Path.GetPathRoot(path, false))); } break; case Win32Errors.ERROR_FILE_READ_ONLY: if (IsDirectory(attrs.dwFileAttributes)) { throw new DirectoryReadOnlyException(path); } else { throw new FileReadOnlyException(path); } default: if (lastError == Win32Errors.ERROR_FILE_NOT_FOUND && isFolder) { lastError = (int)Win32Errors.ERROR_PATH_NOT_FOUND; } NativeError.ThrowException(lastError, path); break; } } }
public FindFileSystemEntryInfo(KernelTransaction transaction, bool isFolder, string path, string searchPattern, DirectoryEnumerationOptions?options, DirectoryEnumerationFilters customFilters, PathFormat pathFormat, Type typeOfT) { if (null == options) { throw new ArgumentNullException("options"); } Transaction = transaction; OriginalInputPath = path; InputPath = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck); IsRelativePath = !Path.IsPathRooted(OriginalInputPath, false); RelativeAbsolutePrefix = IsRelativePath ? InputPath.Replace(OriginalInputPath, string.Empty) : null; SearchPattern = searchPattern.TrimEnd(Path.TrimEndChars); // .NET behaviour. FileSystemObjectType = null; ContinueOnException = (options & DirectoryEnumerationOptions.ContinueOnException) != 0; AsLongPath = (options & DirectoryEnumerationOptions.AsLongPath) != 0; AsString = typeOfT == typeof(string); AsFileSystemInfo = !AsString && (typeOfT == typeof(FileSystemInfo) || typeOfT.BaseType == typeof(FileSystemInfo)); LargeCache = (options & DirectoryEnumerationOptions.LargeCache) != 0 ? NativeMethods.UseLargeCache : NativeMethods.FIND_FIRST_EX_FLAGS.NONE; // Only FileSystemEntryInfo makes use of (8.3) AlternateFileName. FindExInfoLevel = AsString || AsFileSystemInfo || (options & DirectoryEnumerationOptions.BasicSearch) != 0 ? NativeMethods.FindexInfoLevel : NativeMethods.FINDEX_INFO_LEVELS.Standard; if (null != customFilters) { InclusionFilter = customFilters.InclusionFilter; RecursionFilter = customFilters.RecursionFilter; ErrorHandler = customFilters.ErrorFilter; #if !NET35 CancellationToken = customFilters.CancellationToken; #endif } #if !NET35 if (null == CancellationToken) { CancellationToken = new CancellationToken(); } #endif if (isFolder) { IsDirectory = true; Recursive = (options & DirectoryEnumerationOptions.Recursive) != 0 || null != RecursionFilter; SkipReparsePoints = (options & DirectoryEnumerationOptions.SkipReparsePoints) != 0; // Need folders or files to enumerate. if ((options & DirectoryEnumerationOptions.FilesAndFolders) == 0) { options |= DirectoryEnumerationOptions.FilesAndFolders; } } else { options &= ~DirectoryEnumerationOptions.Folders; // Remove enumeration of folders. options |= DirectoryEnumerationOptions.Files; // Add enumeration of files. } FileSystemObjectType = (options & DirectoryEnumerationOptions.FilesAndFolders) == DirectoryEnumerationOptions.FilesAndFolders // Folders and files (null). ? (bool?)null // Only folders (true) or only files (false). : (options & DirectoryEnumerationOptions.Folders) != 0; }
/// <summary>[AlphaFS] Creates an enumeration of all the hard links to the specified <paramref name="path"/>.</summary> /// <returns>An enumerable collection of <see cref="string"/> of all the hard links to the specified <paramref name="path"/></returns> /// <exception cref="PlatformNotSupportedException">The operating system is older than Windows Vista.</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> internal static IEnumerable <string> EnumerateHardlinksCore(KernelTransaction transaction, string path, PathFormat pathFormat) { if (!NativeMethods.IsAtLeastWindowsVista) { throw new PlatformNotSupportedException(new Win32Exception((int)Win32Errors.ERROR_OLD_WIN_VERSION).Message); } var pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck); // Default buffer length, will be extended if needed, although this should not happen. uint length = NativeMethods.MaxPathUnicode; var builder = new StringBuilder((int)length); getFindFirstFileName: using (var safeHandle = transaction == null // FindFirstFileNameW() / FindFirstFileNameTransactedW() / FindNextFileNameW() // 2013-01-13: MSDN does not confirm LongPath usage but a Unicode version of this function exists. // 2017-05-30: FindFirstFileNameW() MSDN confirms LongPath usage: Starting with Windows 10, version 1607 ? NativeMethods.FindFirstFileNameW(pathLp, 0, out length, builder) : NativeMethods.FindFirstFileNameTransactedW(pathLp, 0, out length, builder, transaction.SafeHandle)) { var lastError = Marshal.GetLastWin32Error(); if (!NativeMethods.IsValidHandle(safeHandle, false)) { switch ((uint)lastError) { case Win32Errors.ERROR_MORE_DATA: builder = new StringBuilder((int)length); goto getFindFirstFileName; default: // If the function fails, the return value is INVALID_HANDLE_VALUE. NativeError.ThrowException(lastError, pathLp); break; } } yield return(builder.ToString()); do { while (!NativeMethods.FindNextFileNameW(safeHandle, out length, builder)) { 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); } }
internal static void DeleteDirectoryCore(FileSystemEntryInfo fileSystemEntryInfo, KernelTransaction transaction, string path, bool recursive, bool ignoreReadOnly, bool continueOnNotExist, PathFormat pathFormat) { #region Setup if (pathFormat == PathFormat.RelativePath) { Path.CheckSupportedPathFormat(path, true, true); } if (fileSystemEntryInfo == null) { // MSDN: .NET 3.5+: DirectoryNotFoundException: // Path does not exist or could not be found. // Path refers to a file instead of a directory. // The specified path is invalid (for example, it is on an unmapped drive). fileSystemEntryInfo = File.GetFileSystemEntryInfoCore(true, transaction, Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator), continueOnNotExist, pathFormat); } if (fileSystemEntryInfo == null) { return; } string pathLp = fileSystemEntryInfo.LongFullPath; #endregion // Setup // Do not follow mount points nor symbolic links, but do delete the reparse point itself. // If directory is reparse point, disable recursion. if (recursive && fileSystemEntryInfo.IsReparsePoint) { recursive = false; } // Check to see if this is a mount point, and unmount it. if (fileSystemEntryInfo.IsMountPoint) { int lastError = Volume.DeleteVolumeMountPointCore(pathLp, true); if (lastError != Win32Errors.ERROR_SUCCESS && lastError != Win32Errors.ERROR_PATH_NOT_FOUND) { NativeError.ThrowException(lastError, pathLp); } // Now it is safe to delete the actual directory. } if (recursive) { // Enumerate all file system objects. foreach (var fsei in EnumerateFileSystemEntryInfosCore <FileSystemEntryInfo>(transaction, pathLp, Path.WildcardStarMatchAll, DirectoryEnumerationOptions.FilesAndFolders, PathFormat.LongFullPath)) { if (fsei.IsDirectory) { DeleteDirectoryCore(fsei, transaction, null, true, ignoreReadOnly, true, PathFormat.LongFullPath); } else { File.DeleteFileCore(transaction, fsei.LongFullPath, ignoreReadOnly, PathFormat.LongFullPath); } } } #region Remove startRemoveDirectory: if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista // RemoveDirectory() / RemoveDirectoryTransacted() // 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. // 2014-09-09: MSDN confirms LongPath usage. // RemoveDirectory on a symbolic link will remove the link itself. ? NativeMethods.RemoveDirectory(pathLp) : NativeMethods.RemoveDirectoryTransacted(pathLp, transaction.SafeHandle))) { int lastError = Marshal.GetLastWin32Error(); switch ((uint)lastError) { case Win32Errors.ERROR_DIR_NOT_EMPTY: // MSDN: .NET 3.5+: IOException: The directory specified by path is not an empty directory. throw new DirectoryNotEmptyException(pathLp); case Win32Errors.ERROR_DIRECTORY: // MSDN: .NET 3.5+: DirectoryNotFoundException: Path refers to a file instead of a directory. if (File.ExistsCore(false, transaction, pathLp, PathFormat.LongFullPath)) { throw new DirectoryNotFoundException(string.Format(CultureInfo.CurrentCulture, "({0}) {1}", Win32Errors.ERROR_INVALID_PARAMETER, string.Format(CultureInfo.CurrentCulture, Resources.Target_Directory_Is_A_File, pathLp))); } break; case Win32Errors.ERROR_PATH_NOT_FOUND: if (continueOnNotExist) { return; } break; case Win32Errors.ERROR_SHARING_VIOLATION: // MSDN: .NET 3.5+: IOException: The directory is being used by another process or there is an open handle on the directory. NativeError.ThrowException(lastError, pathLp); break; case Win32Errors.ERROR_ACCESS_DENIED: var data = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA(); int dataInitialised = File.FillAttributeInfoCore(transaction, pathLp, ref data, false, true); if (data.dwFileAttributes != (FileAttributes)(-1)) { if ((data.dwFileAttributes & FileAttributes.ReadOnly) != 0) { // MSDN: .NET 3.5+: IOException: The directory specified by path is read-only. if (ignoreReadOnly) { // Reset directory attributes. File.SetAttributesCore(true, transaction, pathLp, FileAttributes.Normal, true, PathFormat.LongFullPath); goto startRemoveDirectory; } // MSDN: .NET 3.5+: IOException: The directory is read-only. throw new DirectoryReadOnlyException(pathLp); } } if (dataInitialised == Win32Errors.ERROR_SUCCESS) { // MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission. NativeError.ThrowException(lastError, pathLp); } break; } // MSDN: .NET 3.5+: IOException: // A file with the same name and location specified by path exists. // The directory specified by path is read-only, or recursive is false and path is not an empty directory. // The directory is the application's current working directory. // The directory contains a read-only file. // The directory is being used by another process. NativeError.ThrowException(lastError, pathLp); } #endregion // Remove }
internal static IEnumerable <FileIdBothDirectoryInfo> EnumerateFileIdBothDirectoryInfoCore(KernelTransaction transaction, SafeFileHandle safeFileHandle, string path, FileShare shareMode, bool continueOnException, PathFormat pathFormat) { if (!NativeMethods.IsAtLeastWindowsVista) { throw new PlatformNotSupportedException(new Win32Exception((int)Win32Errors.ERROR_OLD_WIN_VERSION).Message); } var pathLp = path; var callerHandle = null != safeFileHandle; if (!callerHandle) { if (Utils.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("path"); } pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck); safeFileHandle = File.CreateFileCore(transaction, pathLp, ExtendedFileAttributes.BackupSemantics, null, FileMode.Open, FileSystemRights.ReadData, shareMode, true, false, PathFormat.LongFullPath); } try { if (!NativeMethods.IsValidHandle(safeFileHandle, Marshal.GetLastWin32Error(), !continueOnException)) { yield break; } var fileNameOffset = (int)Marshal.OffsetOf(typeof(NativeMethods.FILE_ID_BOTH_DIR_INFO), "FileName"); using (var safeBuffer = new SafeGlobalMemoryBufferHandle(NativeMethods.DefaultFileBufferSize)) { while (true) { var success = NativeMethods.GetFileInformationByHandleEx(safeFileHandle, NativeMethods.FILE_INFO_BY_HANDLE_CLASS.FILE_ID_BOTH_DIR_INFO, safeBuffer, (uint)safeBuffer.Capacity); var lastError = Marshal.GetLastWin32Error(); if (!success) { switch ((uint)lastError) { case Win32Errors.ERROR_SUCCESS: case Win32Errors.ERROR_NO_MORE_FILES: case Win32Errors.ERROR_HANDLE_EOF: yield break; case Win32Errors.ERROR_MORE_DATA: continue; default: NativeError.ThrowException(lastError, pathLp); // Keep the compiler happy as we never get here. yield break; } } var offset = 0; NativeMethods.FILE_ID_BOTH_DIR_INFO fibdi; do { fibdi = safeBuffer.PtrToStructure <NativeMethods.FILE_ID_BOTH_DIR_INFO>(offset); var fileName = safeBuffer.PtrToStringUni(offset + fileNameOffset, (int)(fibdi.FileNameLength / UnicodeEncoding.CharSize)); offset += fibdi.NextEntryOffset; if (File.IsDirectory(fibdi.FileAttributes) && (fileName.Equals(Path.CurrentDirectoryPrefix, StringComparison.Ordinal) || fileName.Equals(Path.ParentDirectoryPrefix, StringComparison.Ordinal))) { continue; } yield return(new FileIdBothDirectoryInfo(fibdi, fileName)); //offset += fibdi.NextEntryOffset; } while (fibdi.NextEntryOffset != 0); } } } finally { // Handle is ours, dispose. if (!callerHandle && null != safeFileHandle) { safeFileHandle.Close(); } } }
private CopyMoveResult CopyToMoveToCore(string destinationPath, bool preserveDates, CopyOptions?copyOptions, MoveOptions?moveOptions, CopyMoveProgressRoutine progressHandler, object userProgressData, out string longFullPath, PathFormat pathFormat) { longFullPath = Path.GetExtendedLengthPathCore(Transaction, destinationPath, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck); return(Directory.CopyMoveCore(Transaction, LongFullName, longFullPath, preserveDates, copyOptions, moveOptions, progressHandler, userProgressData, null, PathFormat.LongFullPath)); }
internal static T GetAccessControlCore <T>(bool isFolder, string path, AccessControlSections includeSections, PathFormat pathFormat) { SecurityInformation securityInfo = 0; PrivilegeEnabler privilegeEnabler = null; if ((includeSections & AccessControlSections.Access) != 0) { securityInfo |= SecurityInformation.Dacl; } if ((includeSections & AccessControlSections.Group) != 0) { securityInfo |= SecurityInformation.Group; } if ((includeSections & AccessControlSections.Owner) != 0) { securityInfo |= SecurityInformation.Owner; } if ((includeSections & AccessControlSections.Audit) != 0) { // We need the SE_SECURITY_NAME privilege enabled to be able to get the // SACL descriptor. So we enable it here for the remainder of this function. privilegeEnabler = new PrivilegeEnabler(Privilege.Security); securityInfo |= SecurityInformation.Sacl; } using (privilegeEnabler) { string pathLp = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck); IntPtr pSidOwner, pSidGroup, pDacl, pSacl; SafeGlobalMemoryBufferHandle pSecurityDescriptor; ObjectSecurity objectSecurity; uint lastError = Security.NativeMethods.GetNamedSecurityInfo(pathLp, ObjectType.FileObject, securityInfo, out pSidOwner, out pSidGroup, out pDacl, out pSacl, out pSecurityDescriptor); try { if (lastError == Win32Errors.ERROR_FILE_NOT_FOUND || lastError == Win32Errors.ERROR_PATH_NOT_FOUND) { lastError = (isFolder ? Win32Errors.ERROR_PATH_NOT_FOUND : Win32Errors.ERROR_FILE_NOT_FOUND); } // If the function fails, the return value is zero. if (lastError != Win32Errors.ERROR_SUCCESS) { NativeError.ThrowException(lastError, pathLp); } if (!NativeMethods.IsValidHandle(pSecurityDescriptor, false)) { throw new IOException(Resources.Returned_Invalid_Security_Descriptor); } uint length = Security.NativeMethods.GetSecurityDescriptorLength(pSecurityDescriptor); // Seems not to work: Method .CopyTo: length > Capacity, so an Exception is thrown. //byte[] managedBuffer = new byte[length]; //pSecurityDescriptor.CopyTo(managedBuffer, 0, (int) length); byte[] managedBuffer = pSecurityDescriptor.ToByteArray(0, (int)length); objectSecurity = (isFolder) ? (ObjectSecurity) new DirectorySecurity() : new FileSecurity(); objectSecurity.SetSecurityDescriptorBinaryForm(managedBuffer); } finally { if (pSecurityDescriptor != null) { pSecurityDescriptor.Close(); } } return((T)(object)objectSecurity); } }
internal static string GetHashCore(KernelTransaction transaction, string fileFullPath, HashType hashType, PathFormat pathFormat) { var options = GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck; var fileNameLp = Path.GetExtendedLengthPathCore(transaction, fileFullPath, pathFormat, options); byte[] hash = null; using (var fs = OpenCore(transaction, fileNameLp, FileMode.Open, FileAccess.Read, FileShare.Read, ExtendedFileAttributes.Normal, null, null, PathFormat.LongFullPath)) { switch (hashType) { case HashType.CRC32: using (var hType = new Crc32()) hash = hType.ComputeHash(fs); break; case HashType.CRC64ISO3309: using (var hType = new Crc64()) hash = hType.ComputeHash(fs); break; case HashType.MD5: using (var hType = System.Security.Cryptography.MD5.Create()) hash = hType.ComputeHash(fs); break; case HashType.RIPEMD160: using (var hType = System.Security.Cryptography.RIPEMD160.Create()) hash = hType.ComputeHash(fs); break; case HashType.SHA1: using (var hType = System.Security.Cryptography.SHA1.Create()) hash = hType.ComputeHash(fs); break; case HashType.SHA256: using (var hType = System.Security.Cryptography.SHA256.Create()) hash = hType.ComputeHash(fs); break; case HashType.SHA384: using (var hType = System.Security.Cryptography.SHA384.Create()) hash = hType.ComputeHash(fs); break; case HashType.SHA512: using (var hType = System.Security.Cryptography.SHA512.Create()) hash = hType.ComputeHash(fs); break; } } if (null != hash) { var sb = new StringBuilder(hash.Length); foreach (byte b in hash) { sb.Append(b.ToString("X2", CultureInfo.InvariantCulture)); } return(sb.ToString().ToUpperInvariant()); } return(string.Empty); }
internal static IEnumerable <FileIdBothDirectoryInfo> EnumerateFileIdBothDirectoryInfoCore(KernelTransaction transaction, SafeFileHandle safeHandle, string path, FileShare shareMode, bool continueOnException, PathFormat pathFormat) { if (!NativeMethods.IsAtLeastWindowsVista) { throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher); } bool callerHandle = safeHandle != null; if (!callerHandle) { if (Utils.IsNullOrWhiteSpace(path)) { throw new ArgumentNullException("path"); } string pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck); safeHandle = File.CreateFileCore(transaction, pathLp, ExtendedFileAttributes.BackupSemantics, null, FileMode.Open, FileSystemRights.ReadData, shareMode, true, PathFormat.LongFullPath); } try { if (!NativeMethods.IsValidHandle(safeHandle, Marshal.GetLastWin32Error(), !continueOnException)) { yield break; } var fileNameOffset = (int)Marshal.OffsetOf(typeof(NativeMethods.FILE_ID_BOTH_DIR_INFO), "FileName"); using (var safeBuffer = new SafeGlobalMemoryBufferHandle(NativeMethods.DefaultFileBufferSize)) { while (true) { if (!NativeMethods.GetFileInformationByHandleEx(safeHandle, NativeMethods.FileInfoByHandleClass.FileIdBothDirectoryInfo, safeBuffer, (uint)safeBuffer.Capacity)) { uint lastError = (uint)Marshal.GetLastWin32Error(); switch (lastError) { case Win32Errors.ERROR_SUCCESS: case Win32Errors.ERROR_NO_MORE_FILES: case Win32Errors.ERROR_HANDLE_EOF: yield break; case Win32Errors.ERROR_MORE_DATA: continue; default: NativeError.ThrowException(lastError, path); yield break; // we should never get to this yield break. } } int offset = 0; NativeMethods.FILE_ID_BOTH_DIR_INFO fibdi; do { fibdi = safeBuffer.PtrToStructure <NativeMethods.FILE_ID_BOTH_DIR_INFO>(offset); string fileName = safeBuffer.PtrToStringUni(offset + fileNameOffset, (int)(fibdi.FileNameLength / 2)); if (!fileName.Equals(Path.CurrentDirectoryPrefix, StringComparison.OrdinalIgnoreCase) && !fileName.Equals(Path.ParentDirectoryPrefix, StringComparison.OrdinalIgnoreCase)) { yield return(new FileIdBothDirectoryInfo(fibdi, fileName)); } offset += fibdi.NextEntryOffset; }while (fibdi.NextEntryOffset != 0); } } } finally { // Handle is ours, dispose. if (!callerHandle && safeHandle != null) { safeHandle.Close(); } } }
internal static SafeFileHandle CreateFileCore(KernelTransaction transaction, string path, ExtendedFileAttributes attributes, FileSecurity fileSecurity, FileMode fileMode, FileSystemRights fileSystemRights, FileShare fileShare, bool checkPath, bool continueOnException, PathFormat pathFormat) { if (checkPath && pathFormat == PathFormat.RelativePath) { Path.CheckSupportedPathFormat(path, true, true); } // When isFile == null, we're working with a device. // When opening a VOLUME or removable media drive (for example, a floppy disk drive or flash memory thumb drive), // the path string should be the following form: "\\.\X:" // Do not use a trailing backslash ('\'), which indicates the root. var pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator); // CreateFileXxx() does not support FileMode.Append mode. var isAppend = fileMode == FileMode.Append; if (isAppend) { fileMode = FileMode.OpenOrCreate; fileSystemRights |= FileSystemRights.AppendData; } if (null != fileSecurity) { fileSystemRights |= (FileSystemRights)SECURITY_INFORMATION.UNPROTECTED_SACL_SECURITY_INFORMATION; } using ((fileSystemRights & (FileSystemRights)SECURITY_INFORMATION.UNPROTECTED_SACL_SECURITY_INFORMATION) != 0 || (fileSystemRights & (FileSystemRights)SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION) != 0 ? new PrivilegeEnabler(Privilege.Security) : null) using (var securityAttributes = new Security.NativeMethods.SecurityAttributes(fileSecurity)) { var safeHandle = transaction == null || !NativeMethods.IsAtLeastWindowsVista // CreateFile() / CreateFileTransacted() // 2013-01-13: MSDN confirms LongPath usage. ? NativeMethods.CreateFile(pathLp, fileSystemRights, fileShare, securityAttributes, fileMode, attributes, IntPtr.Zero) : NativeMethods.CreateFileTransacted(pathLp, fileSystemRights, fileShare, securityAttributes, fileMode, attributes, IntPtr.Zero, transaction.SafeHandle, IntPtr.Zero, IntPtr.Zero); var lastError = Marshal.GetLastWin32Error(); NativeMethods.IsValidHandle(safeHandle, lastError, pathLp, !continueOnException); if (isAppend) { var success = NativeMethods.SetFilePointerEx(safeHandle, 0, IntPtr.Zero, SeekOrigin.End); lastError = Marshal.GetLastWin32Error(); if (!success) { if (!safeHandle.IsClosed) { safeHandle.Close(); } NativeError.ThrowException(lastError, path); } } return(safeHandle); } }
internal static void DeleteEmptySubdirectoriesCore(FileSystemEntryInfo fileSystemEntryInfo, KernelTransaction transaction, string path, bool recursive, bool ignoreReadOnly, bool initialize, PathFormat pathFormat) { #region Setup if (pathFormat == PathFormat.RelativePath) { Path.CheckSupportedPathFormat(path, true, true); } if (fileSystemEntryInfo == null) { if (!File.ExistsCore(true, transaction, path, pathFormat)) { NativeError.ThrowException(Win32Errors.ERROR_PATH_NOT_FOUND, path); } fileSystemEntryInfo = File.GetFileSystemEntryInfoCore(true, transaction, Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck), false, pathFormat); } if (fileSystemEntryInfo == null) { throw new ArgumentNullException("path"); } string pathLp = fileSystemEntryInfo.LongFullPath; #endregion // Setup // Ensure path is a directory. if (!fileSystemEntryInfo.IsDirectory) { throw new IOException(string.Format(CultureInfo.CurrentCulture, Resources.Target_Directory_Is_A_File, pathLp)); } var dirEnumOptions = DirectoryEnumerationOptions.Folders; if (recursive) { dirEnumOptions |= DirectoryEnumerationOptions.Recursive; } foreach (var fsei in EnumerateFileSystemEntryInfosCore <FileSystemEntryInfo>(transaction, pathLp, Path.WildcardStarMatchAll, dirEnumOptions, PathFormat.LongFullPath)) { DeleteEmptySubdirectoriesCore(fsei, transaction, null, recursive, ignoreReadOnly, false, PathFormat.LongFullPath); } if (!EnumerateFileSystemEntryInfosCore <string>(transaction, pathLp, Path.WildcardStarMatchAll, DirectoryEnumerationOptions.FilesAndFolders, PathFormat.LongFullPath).Any()) { // Prevent deleting path itself. if (!initialize) { DeleteDirectoryCore(fileSystemEntryInfo, transaction, null, false, ignoreReadOnly, true, PathFormat.LongFullPath); } } }
internal static void DeleteDirectoryCore(KernelTransaction transaction, FileSystemEntryInfo fsEntryInfo, string path, bool recursive, bool ignoreReadOnly, bool continueOnNotFound, PathFormat pathFormat) { if (null == fsEntryInfo) { if (null == path) { throw new ArgumentNullException("path"); } // MSDN: .NET 3.5+: DirectoryNotFoundException: // Path does not exist or could not be found. // Path refers to a file instead of a directory. // The specified path is invalid (for example, it is on an unmapped drive). if (pathFormat == PathFormat.RelativePath) { Path.CheckSupportedPathFormat(path, true, true); } fsEntryInfo = File.GetFileSystemEntryInfoCore(transaction, true, Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator), continueOnNotFound, pathFormat); if (null == fsEntryInfo) { return; } } pathFormat = PathFormat.LongFullPath; // Do not follow mount points nor symbolic links, but do delete the reparse point itself. // If directory is reparse point, disable recursion. if (recursive && !fsEntryInfo.IsReparsePoint) { var dirs = new Stack <string>(1000); foreach (var fsei in EnumerateFileSystemEntryInfosCore <FileSystemEntryInfo>(null, transaction, fsEntryInfo.LongFullPath, Path.WildcardStarMatchAll, SearchOption.AllDirectories, null, null, pathFormat)) { if (fsei.IsDirectory) { // Check to see if this is a mount point, and unmount it. // Now it is safe to delete the actual directory. if (fsei.IsMountPoint) { DeleteJunctionCore(transaction, fsei, null, false, pathFormat); } //Volume.DeleteVolumeMountPointCore(transaction, fsei.LongFullPath, false, true, pathFormat); dirs.Push(fsei.LongFullPath); } else { File.DeleteFileCore(transaction, fsei.LongFullPath, ignoreReadOnly, pathFormat); } } while (dirs.Count > 0) { DeleteDirectoryCore(transaction, dirs.Pop(), ignoreReadOnly, continueOnNotFound); } } // Check to see if this is a mount point, and unmount it. // Now it is safe to delete the actual directory. if (fsEntryInfo.IsMountPoint) { DeleteJunctionCore(transaction, fsEntryInfo, null, false, pathFormat); } //Volume.DeleteVolumeMountPointCore(transaction, fsEntryInfo.LongFullPath, false, true, pathFormat); DeleteDirectoryCore(transaction, fsEntryInfo.LongFullPath, ignoreReadOnly, continueOnNotFound); }
internal static void SetAccessControlCore(string path, SafeFileHandle handle, ObjectSecurity objectSecurity, AccessControlSections includeSections, PathFormat pathFormat) { if (pathFormat == PathFormat.RelativePath) { Path.CheckSupportedPathFormat(path, true, true); } if (objectSecurity == null) { throw new ArgumentNullException("objectSecurity"); } var managedDescriptor = objectSecurity.GetSecurityDescriptorBinaryForm(); using (var safeBuffer = new SafeGlobalMemoryBufferHandle(managedDescriptor.Length)) { var pathLp = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.CheckInvalidPathChars); safeBuffer.CopyFrom(managedDescriptor, 0, managedDescriptor.Length); SECURITY_DESCRIPTOR_CONTROL control; uint revision; var success = Security.NativeMethods.GetSecurityDescriptorControl(safeBuffer, out control, out revision); var lastError = Marshal.GetLastWin32Error(); if (!success) { NativeError.ThrowException(lastError, pathLp); } PrivilegeEnabler privilegeEnabler = null; try { var securityInfo = SECURITY_INFORMATION.None; var pDacl = IntPtr.Zero; if ((includeSections & AccessControlSections.Access) != 0) { bool daclDefaulted, daclPresent; success = Security.NativeMethods.GetSecurityDescriptorDacl(safeBuffer, out daclPresent, out pDacl, out daclDefaulted); lastError = Marshal.GetLastWin32Error(); if (!success) { NativeError.ThrowException(lastError, pathLp); } if (daclPresent) { securityInfo |= SECURITY_INFORMATION.DACL_SECURITY_INFORMATION; securityInfo |= (control & SECURITY_DESCRIPTOR_CONTROL.SE_DACL_PROTECTED) != 0 ? SECURITY_INFORMATION.PROTECTED_DACL_SECURITY_INFORMATION : SECURITY_INFORMATION.UNPROTECTED_DACL_SECURITY_INFORMATION; } } var pSacl = IntPtr.Zero; if ((includeSections & AccessControlSections.Audit) != 0) { bool saclDefaulted, saclPresent; success = Security.NativeMethods.GetSecurityDescriptorSacl(safeBuffer, out saclPresent, out pSacl, out saclDefaulted); lastError = Marshal.GetLastWin32Error(); if (!success) { NativeError.ThrowException(lastError, pathLp); } if (saclPresent) { securityInfo |= SECURITY_INFORMATION.SACL_SECURITY_INFORMATION; securityInfo |= (control & SECURITY_DESCRIPTOR_CONTROL.SE_SACL_PROTECTED) != 0 ? SECURITY_INFORMATION.PROTECTED_SACL_SECURITY_INFORMATION : SECURITY_INFORMATION.UNPROTECTED_SACL_SECURITY_INFORMATION; privilegeEnabler = new PrivilegeEnabler(Privilege.Security); } } var pOwner = IntPtr.Zero; if ((includeSections & AccessControlSections.Owner) != 0) { bool ownerDefaulted; success = Security.NativeMethods.GetSecurityDescriptorOwner(safeBuffer, out pOwner, out ownerDefaulted); lastError = Marshal.GetLastWin32Error(); if (!success) { NativeError.ThrowException(lastError, pathLp); } if (pOwner != IntPtr.Zero) { securityInfo |= SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION; } } var pGroup = IntPtr.Zero; if ((includeSections & AccessControlSections.Group) != 0) { bool groupDefaulted; success = Security.NativeMethods.GetSecurityDescriptorGroup(safeBuffer, out pGroup, out groupDefaulted); lastError = Marshal.GetLastWin32Error(); if (!success) { NativeError.ThrowException(lastError, pathLp); } if (pGroup != IntPtr.Zero) { securityInfo |= SECURITY_INFORMATION.GROUP_SECURITY_INFORMATION; } } if (!Utils.IsNullOrWhiteSpace(pathLp)) { // SetNamedSecurityInfo() // 2013-01-13: MSDN does not confirm LongPath usage but a Unicode version of this function exists. lastError = (int)Security.NativeMethods.SetNamedSecurityInfo(pathLp, SE_OBJECT_TYPE.SE_FILE_OBJECT, securityInfo, pOwner, pGroup, pDacl, pSacl); if (lastError != Win32Errors.ERROR_SUCCESS) { NativeError.ThrowException(lastError, pathLp); } } else { if (NativeMethods.IsValidHandle(handle)) { lastError = (int)Security.NativeMethods.SetSecurityInfo(handle, SE_OBJECT_TYPE.SE_FILE_OBJECT, securityInfo, pOwner, pGroup, pDacl, pSacl); if (lastError != Win32Errors.ERROR_SUCCESS) { NativeError.ThrowException(lastError); } } } } finally { if (null != privilegeEnabler) { privilegeEnabler.Dispose(); } } } }
/// <summary>[AlphaFS] Creates an enumeration of all the hard links to the specified <paramref name="path"/>.</summary> /// <exception cref="PlatformNotSupportedException"/> /// <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> EnumerateHardlinksCore(KernelTransaction transaction, string path, PathFormat pathFormat) { if (!NativeMethods.IsAtLeastWindowsVista) { throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher); } string pathLp = Path.GetExtendedLengthPathCore(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)) { int lastError = Marshal.GetLastWin32Error(); if (handle.IsInvalid) { handle.Close(); switch ((uint)lastError) { case Win32Errors.ERROR_MORE_DATA: builder = new StringBuilder((int)length); 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)) { 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); } }
internal static string CreateJunctionCore(KernelTransaction transaction, string junctionPath, string directoryPath, bool overwrite, bool copyTargetTimestamps, PathFormat pathFormat) { if (pathFormat != PathFormat.LongFullPath) { Path.CheckSupportedPathFormat(directoryPath, true, true); Path.CheckSupportedPathFormat(junctionPath, true, true); directoryPath = Path.GetExtendedLengthPathCore(transaction, directoryPath, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator); junctionPath = Path.GetExtendedLengthPathCore(transaction, junctionPath, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator); pathFormat = PathFormat.LongFullPath; } // Directory Junction logic. // Check if drive letter is a mapped network drive. if (new DriveInfo(directoryPath).IsUnc) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Network_Path_Not_Allowed, directoryPath), "directoryPath"); } if (new DriveInfo(junctionPath).IsUnc) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.Network_Path_Not_Allowed, junctionPath), "junctionPath"); } // Check for existing file. File.ThrowIOExceptionIfFsoExist(transaction, false, directoryPath, pathFormat); File.ThrowIOExceptionIfFsoExist(transaction, false, junctionPath, pathFormat); // Check for existing directory junction folder. if (File.ExistsCore(transaction, true, junctionPath, pathFormat)) { if (overwrite) { DeleteDirectoryCore(transaction, null, junctionPath, true, true, true, pathFormat); CreateDirectoryCore(transaction, junctionPath, null, null, false, pathFormat); } else { // Ensure the folder is empty. if (!IsEmptyCore(transaction, junctionPath, pathFormat)) { throw new DirectoryNotEmptyException(junctionPath, true); } throw new AlreadyExistsException(junctionPath, true); } } // Create the folder and convert it to a directory junction. CreateDirectoryCore(transaction, junctionPath, null, null, false, pathFormat); using (var safeHandle = OpenDirectoryJunction(transaction, junctionPath, pathFormat)) Device.CreateDirectoryJunction(safeHandle, directoryPath); // Copy the target date and time stamps to the directory junction. if (copyTargetTimestamps) { File.CopyTimestampsCore(transaction, directoryPath, junctionPath, true, pathFormat); } return(junctionPath); }
internal static void DeleteFileCore(KernelTransaction transaction, string path, bool ignoreReadOnly, PathFormat pathFormat) { #region Setup if (pathFormat == PathFormat.RelativePath) { Path.CheckSupportedPathFormat(path, true, true); } string pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator); // If the path points to a symbolic link, the symbolic link is deleted, not the target. #endregion // Setup startDeleteFile: if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista // DeleteFile() / DeleteFileTransacted() // 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.DeleteFile(pathLp) : NativeMethods.DeleteFileTransacted(pathLp, transaction.SafeHandle))) { int lastError = Marshal.GetLastWin32Error(); switch ((uint)lastError) { case Win32Errors.ERROR_FILE_NOT_FOUND: // MSDN: .NET 3.5+: If the file to be deleted does not exist, no exception is thrown. return; case Win32Errors.ERROR_PATH_NOT_FOUND: // MSDN: .NET 3.5+: DirectoryNotFoundException: The specified path is invalid (for example, it is on an unmapped drive). NativeError.ThrowException(lastError, pathLp); return; case Win32Errors.ERROR_SHARING_VIOLATION: // MSDN: .NET 3.5+: IOException: The specified file is in use or there is an open handle on the file. NativeError.ThrowException(lastError, pathLp); break; case Win32Errors.ERROR_ACCESS_DENIED: var data = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA(); int dataInitialised = FillAttributeInfoCore(transaction, pathLp, ref data, false, true); if (data.dwFileAttributes != (FileAttributes)(-1)) { if ((data.dwFileAttributes & FileAttributes.Directory) != 0) { // MSDN: .NET 3.5+: UnauthorizedAccessException: Path is a directory. throw new UnauthorizedAccessException(string.Format(CultureInfo.CurrentCulture, "({0}) {1}", Win32Errors.ERROR_INVALID_PARAMETER, string.Format(CultureInfo.CurrentCulture, Resources.Target_File_Is_A_Directory, pathLp))); } if ((data.dwFileAttributes & FileAttributes.ReadOnly) != 0) { if (ignoreReadOnly) { // Reset file attributes. SetAttributesCore(false, transaction, pathLp, FileAttributes.Normal, PathFormat.LongFullPath); goto startDeleteFile; } // MSDN: .NET 3.5+: UnauthorizedAccessException: Path specified a read-only file. throw new FileReadOnlyException(pathLp); } } if (dataInitialised == Win32Errors.ERROR_SUCCESS) { // MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission. NativeError.ThrowException(lastError, pathLp); } break; } // MSDN: .NET 3.5+: IOException: // The specified file is in use. // There is an open handle on the file, and the operating system is Windows XP or earlier. NativeError.ThrowException(lastError, pathLp); } }
internal static void ImportExportEncryptedFileDirectoryRawCore(bool isExport, bool isFolder, Stream stream, string destinationPath, PathFormat pathFormat, bool overwriteHidden) { string destinationPathLp = Path.GetExtendedLengthPathCore(null, destinationPath, pathFormat, GetFullPathOptions.FullCheck | GetFullPathOptions.TrimEnd); NativeMethods.EncryptedFileRawMode mode = isExport ? NativeMethods.EncryptedFileRawMode.CreateForExport : NativeMethods.EncryptedFileRawMode.CreateForImport; if (isFolder) { mode = mode | NativeMethods.EncryptedFileRawMode.CreateForDir; } if (overwriteHidden) { mode = mode | NativeMethods.EncryptedFileRawMode.OverwriteHidden; } // OpenEncryptedFileRaw() // 2015-08-02: MSDN does not confirm LongPath usage but a Unicode version of this function exists. SafeEncryptedFileRawHandle context; var lastError = NativeMethods.OpenEncryptedFileRaw(destinationPathLp, mode, out context); try { if (lastError != Win32Errors.ERROR_SUCCESS) { NativeError.ThrowException(lastError, destinationPathLp); } lastError = isExport ? NativeMethods.ReadEncryptedFileRaw((pbData, pvCallbackContext, length) => { try { var data = new byte[length]; Marshal.Copy(pbData, data, 0, (int)length); stream.Write(data, 0, (int)length); } catch (Exception ex) { return(Marshal.GetHRForException(ex) & NativeMethods.OverflowExceptionBitShift); } return((int)Win32Errors.ERROR_SUCCESS); }, IntPtr.Zero, context) : NativeMethods.WriteEncryptedFileRaw((IntPtr pbData, IntPtr pvCallbackContext, ref uint length) => { try { var data = new byte[length]; length = (uint)stream.Read(data, 0, (int)length); if (length == 0) { return((int)Win32Errors.ERROR_SUCCESS); } Marshal.Copy(data, 0, pbData, (int)length); } catch (Exception ex) { return(Marshal.GetHRForException(ex) & NativeMethods.OverflowExceptionBitShift); } return((int)Win32Errors.ERROR_SUCCESS); }, IntPtr.Zero, context); if (lastError != Win32Errors.ERROR_SUCCESS) { NativeError.ThrowException(lastError, destinationPathLp); } } finally { if (context != null) { context.Dispose(); } } }
internal static void SetAccessControlCore(string path, SafeFileHandle handle, ObjectSecurity objectSecurity, AccessControlSections includeSections, PathFormat pathFormat) { if (pathFormat == PathFormat.RelativePath) { Path.CheckSupportedPathFormat(path, true, true); } if (objectSecurity == null) { throw new ArgumentNullException("objectSecurity"); } byte[] managedDescriptor = objectSecurity.GetSecurityDescriptorBinaryForm(); using (var safeBuffer = new SafeGlobalMemoryBufferHandle(managedDescriptor.Length)) { string pathLp = Path.GetExtendedLengthPathCore(null, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.CheckInvalidPathChars); safeBuffer.CopyFrom(managedDescriptor, 0, managedDescriptor.Length); SecurityDescriptorControl control; uint revision; if (!Security.NativeMethods.GetSecurityDescriptorControl(safeBuffer, out control, out revision)) { NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp); } PrivilegeEnabler privilegeEnabler = null; try { var securityInfo = SecurityInformation.None; IntPtr pDacl = IntPtr.Zero; if ((includeSections & AccessControlSections.Access) != 0) { bool daclDefaulted, daclPresent; if (!Security.NativeMethods.GetSecurityDescriptorDacl(safeBuffer, out daclPresent, out pDacl, out daclDefaulted)) { NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp); } if (daclPresent) { securityInfo |= SecurityInformation.Dacl; securityInfo |= (control & SecurityDescriptorControl.DaclProtected) != 0 ? SecurityInformation.ProtectedDacl : SecurityInformation.UnprotectedDacl; } } IntPtr pSacl = IntPtr.Zero; if ((includeSections & AccessControlSections.Audit) != 0) { bool saclDefaulted, saclPresent; if (!Security.NativeMethods.GetSecurityDescriptorSacl(safeBuffer, out saclPresent, out pSacl, out saclDefaulted)) { NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp); } if (saclPresent) { securityInfo |= SecurityInformation.Sacl; securityInfo |= (control & SecurityDescriptorControl.SaclProtected) != 0 ? SecurityInformation.ProtectedSacl : SecurityInformation.UnprotectedSacl; privilegeEnabler = new PrivilegeEnabler(Privilege.Security); } } IntPtr pOwner = IntPtr.Zero; if ((includeSections & AccessControlSections.Owner) != 0) { bool ownerDefaulted; if (!Security.NativeMethods.GetSecurityDescriptorOwner(safeBuffer, out pOwner, out ownerDefaulted)) { NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp); } if (pOwner != IntPtr.Zero) { securityInfo |= SecurityInformation.Owner; } } IntPtr pGroup = IntPtr.Zero; if ((includeSections & AccessControlSections.Group) != 0) { bool groupDefaulted; if (!Security.NativeMethods.GetSecurityDescriptorGroup(safeBuffer, out pGroup, out groupDefaulted)) { NativeError.ThrowException(Marshal.GetLastWin32Error(), pathLp); } if (pGroup != IntPtr.Zero) { securityInfo |= SecurityInformation.Group; } } uint lastError; if (!Utils.IsNullOrWhiteSpace(pathLp)) { // SetNamedSecurityInfo() // 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. lastError = Security.NativeMethods.SetNamedSecurityInfo(pathLp, ObjectType.FileObject, securityInfo, pOwner, pGroup, pDacl, pSacl); if (lastError != Win32Errors.ERROR_SUCCESS) { NativeError.ThrowException(lastError, pathLp); } } else { if (NativeMethods.IsValidHandle(handle)) { lastError = Security.NativeMethods.SetSecurityInfo(handle, ObjectType.FileObject, securityInfo, pOwner, pGroup, pDacl, pSacl); if (lastError != Win32Errors.ERROR_SUCCESS) { NativeError.ThrowException((int)lastError); } } } } finally { if (privilegeEnabler != null) { privilegeEnabler.Dispose(); } } } }
internal static SafeFileHandle CreateFileCore(KernelTransaction transaction, string path, ExtendedFileAttributes attributes, FileSecurity fileSecurity, FileMode fileMode, FileSystemRights fileSystemRights, FileShare fileShare, bool checkPath, PathFormat pathFormat) { if (checkPath && pathFormat == PathFormat.RelativePath) { Path.CheckSupportedPathFormat(path, true, true); } // When isFile == null, we're working with a device. // When opening a VOLUME or removable media drive (for example, a floppy disk drive or flash memory thumb drive), // the path string should be the following form: "\\.\X:" // Do not use a trailing backslash (\), which indicates the root. var pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator); PrivilegeEnabler privilegeEnabler = null; var isAppend = fileMode == FileMode.Append; // CreateFileXxx() does not support FileMode.Append mode. if (isAppend) { fileMode = FileMode.OpenOrCreate; fileSystemRights &= FileSystemRights.AppendData; // Add right. } if (fileSecurity != null) { fileSystemRights |= (FileSystemRights)0x1000000; // Set right. } // AccessSystemSecurity = 0x1000000 AccessSystemAcl access type. // MaximumAllowed = 0x2000000 MaximumAllowed access type. if ((fileSystemRights & (FileSystemRights)0x1000000) != 0 || (fileSystemRights & (FileSystemRights)0x2000000) != 0) { privilegeEnabler = new PrivilegeEnabler(Privilege.Security); } using (privilegeEnabler) using (var securityAttributes = new Security.NativeMethods.SecurityAttributes(fileSecurity)) { var handle = transaction == null || !NativeMethods.IsAtLeastWindowsVista // CreateFile() / CreateFileTransacted() // 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.CreateFile(pathLp, fileSystemRights, fileShare, securityAttributes, fileMode, attributes, IntPtr.Zero) : NativeMethods.CreateFileTransacted(pathLp, fileSystemRights, fileShare, securityAttributes, fileMode, attributes, IntPtr.Zero, transaction.SafeHandle, IntPtr.Zero, IntPtr.Zero); var lastError = Marshal.GetLastWin32Error(); if (handle.IsInvalid) { handle.Close(); NativeError.ThrowException(lastError, pathLp); } if (isAppend) { var stream = new FileStream(handle, FileAccess.Write, NativeMethods.DefaultFileBufferSize, (attributes & ExtendedFileAttributes.Overlapped) != 0); stream.Seek(0, SeekOrigin.End); } return(handle); } }
internal static Collection <Process> GetProcessForFileLockCore(KernelTransaction transaction, Collection <string> filePaths, PathFormat pathFormat) { if (!NativeMethods.IsAtLeastWindowsVista) { throw new PlatformNotSupportedException(new Win32Exception((int)Win32Errors.ERROR_OLD_WIN_VERSION).Message); } if (null == filePaths) { throw new ArgumentNullException("filePaths"); } if (filePaths.Count == 0) { throw new ArgumentOutOfRangeException("filePaths", "No paths specified."); } var isLongPath = pathFormat == PathFormat.LongFullPath; var allPaths = isLongPath ? new Collection <string>(filePaths) : new Collection <string>(); if (!isLongPath) { foreach (var path in filePaths) { allPaths.Add(Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck)); } } uint sessionHandle; var success = NativeMethods.RmStartSession(out sessionHandle, 0, Guid.NewGuid().ToString()) == Win32Errors.ERROR_SUCCESS; var lastError = Marshal.GetLastWin32Error(); if (!success) { NativeError.ThrowException(lastError); } var processes = new Collection <Process>(); try { // A snapshot count of all running processes. var processesFound = (uint)Process.GetProcesses().Length; uint lpdwRebootReasons = 0; success = NativeMethods.RmRegisterResources(sessionHandle, (uint)allPaths.Count, allPaths.ToArray(), 0, null, 0, null) == Win32Errors.ERROR_SUCCESS; lastError = Marshal.GetLastWin32Error(); if (!success) { NativeError.ThrowException(lastError); } GetList: var processInfo = new NativeMethods.RM_PROCESS_INFO[processesFound]; var processesTotal = processesFound; lastError = NativeMethods.RmGetList(sessionHandle, out processesFound, ref processesTotal, processInfo, ref lpdwRebootReasons); // There would be no need for this because we already have a/the total number of running processes. if (lastError == Win32Errors.ERROR_MORE_DATA) { goto GetList; } if (lastError != Win32Errors.ERROR_SUCCESS) { NativeError.ThrowException(lastError); } for (var i = 0; i < processesTotal; i++) { try { processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId)); } // MSDN: The process specified by the processId parameter is not running. The identifier might be expired. catch (ArgumentException) {} } } finally { NativeMethods.RmEndSession(sessionHandle); } return(processes.Count == 0 ? null : processes); }