public void NativeWin32ExceptionIncludesSystemFormattedString() { const int ErrorAccessDenied = 5; var ex = new NativeWin32Exception(ErrorAccessDenied, "Prefix"); XAssert.IsTrue(ex.Message.Contains("Access is denied")); XAssert.IsTrue(ex.Message.Contains("Prefix")); XAssert.AreEqual(ErrorAccessDenied, ex.NativeErrorCode); }
/// <summary> /// Describes the operation that cause this reported file access, including all parameter value, except the path /// </summary> public string Describe() { using (PooledObjectWrapper <StringBuilder> wrapper = Pools.GetStringBuilder()) { StringBuilder sb = wrapper.Instance; sb.Append('['); sb.Append(Process.Path); sb.Append(':'); sb.Append(Process.ProcessId); sb.Append(']'); if (RequestedAccess != RequestedAccess.None) { sb.AppendFormat("({0:G})", RequestedAccess); } sb.Append(' '); switch (Operation) { case ReportedFileOperation.ZwCreateFile: case ReportedFileOperation.ZwOpenFile: case ReportedFileOperation.NtCreateFile: case ReportedFileOperation.CreateFile: case ReportedFileOperation.Unknown: { sb.Append(Operation.ToString()); sb.Append("(..., "); UInt32FlagsFormatter <DesiredAccess> .Append(sb, (uint)DesiredAccess); sb.Append(", "); UInt32FlagsFormatter <ShareMode> .Append(sb, (uint)ShareMode); sb.Append(", , "); UInt32EnumFormatter <CreationDisposition> .Append(sb, (uint)CreationDisposition); sb.Append(", "); UInt32FlagsFormatter <FlagsAndAttributes> .Append(sb, (uint)FlagsAndAttributes); sb.Append(")"); break; } case ReportedFileOperation.CopyFileSource: { sb.Append("CopyFile([Source], ...)"); break; } case ReportedFileOperation.CopyFileDestination: { sb.Append("CopyFile(..., [Destination])"); break; } case ReportedFileOperation.CreateHardLinkSource: { sb.Append("CreateHardLink(..., [ExistingFile)"); break; } case ReportedFileOperation.CreateHardLinkDestination: { sb.Append("CreateHardLink([NewLink], ...)"); break; } case ReportedFileOperation.MoveFileSource: { sb.Append("MoveFile([Source], ...)"); break; } case ReportedFileOperation.MoveFileDestination: { sb.Append("MoveFile(..., [Destination])"); break; } case ReportedFileOperation.SetFileInformationByHandleSource: { sb.Append("SetFileInformationByHandle([Source], ...)"); break; } case ReportedFileOperation.SetFileInformationByHandleDest: { sb.Append("SetFileInformationByHandle(..., [Destination])"); break; } case ReportedFileOperation.ZwSetRenameInformationFileSource: { sb.Append("ZwSetRenameInformationFile([Source], ...)"); break; } case ReportedFileOperation.ZwSetRenameInformationFileDest: { sb.Append("ZwSetRenameInformationFile(..., [Destination])"); break; } case ReportedFileOperation.ZwSetFileNameInformationFileSource: { sb.Append("ZwSetFileNameInformationFile([Source], ...)"); break; } case ReportedFileOperation.ZwSetFileNameInformationFileDest: { sb.Append("ZwSetFileNameInformationFile(..., [Destination])"); break; } case ReportedFileOperation.MoveFileWithProgressSource: { sb.Append("MoveFileWithProgress([Source]...)"); break; } case ReportedFileOperation.MoveFileWithProgressDest: { sb.Append("MoveFileWithProgress([Dest]...)"); break; } case ReportedFileOperation.FindFirstFileEx: { sb.Append("FindFirstFileEx(...)"); if (RequestedAccess == RequestedAccess.Enumerate) { sb.Append(", "); sb.Append("Enumerate Pattern:" + EnumeratePattern); } break; } default: { sb.Append(Enum.GetName(typeof(ReportedFileOperation), Operation)).Append("(...)"); break; } } if (Error != 0) { sb.AppendFormat(CultureInfo.InvariantCulture, " => (0x{0:X8}) ", Error); sb.Append(NativeWin32Exception.GetFormattedMessageForNativeErrorCode(unchecked ((int)Error))); } if (Usn != NoUsn) { sb.AppendFormat(CultureInfo.InvariantCulture, " (USN 0x{0:X8}) ", Usn); } // If the status was Denied, don't include it in the description, // because an access that was denied by manifest may have been // allowed in practice (no failure injection), and the message // would be confusing. if (Status != FileAccessStatus.Denied) { // Other modes are interesting and should be logged sb.Append(" => "); sb.Append(Status); } return(sb.ToString()); } }
private static void ConfigureWciFilter(IntPtr hJob, IReadOnlyCollection <ExpandedAbsolutePath> sourcePaths, string destinationPath, List <string> wciRetries) { var layerDescriptors = new NativeContainerUtilities.WC_LAYER_DESCRIPTOR[sourcePaths.Count]; int i = 0; foreach (ExpandedAbsolutePath sourcePath in sourcePaths) { var layerDescriptor = new NativeContainerUtilities.WC_LAYER_DESCRIPTOR { // By default we always set the layer so it inherits the descriptor. This // makes hardlinks (ACLed for deny-write) and exposed via copy-on-write writable // The sparse flag is not set explicitly since we use the general sparse isolation mode // which implies that each layer will be sparse Flags = NativeContainerUtilities.LayerDescriptorFlags.InheritSecurity, LayerId = NativeContainerUtilities.ToGuid(Guid.NewGuid()), Path = sourcePath.ExpandedPath, }; layerDescriptors[i] = layerDescriptor; i++; } var reparsePointData = new NativeContainerUtilities.WC_REPARSE_POINT_DATA { Flags = 0, LayerId = layerDescriptors[0].LayerId, NameLength = 0, Name = string.Empty }; var hresult = -1; hresult = NativeContainerUtilities.WciSetReparsePointData( destinationPath, ref reparsePointData, (UInt16)Marshal.OffsetOf(typeof(NativeContainerUtilities.WC_REPARSE_POINT_DATA), "Name")); if (hresult != 0) { throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Unable to setup the reparse point data for '{destinationPath}'.")); } hresult = -1; // We try to setup the WCI filter on a retry loop to workaround an existing issue // in the driver behavior, where the setup sometimes fails. var retries = s_wciRetries; while (hresult != 0 && retries > 0) { // Isolation is set to hard because we want the virtualized source path to be // completely isolated (e.g. with 'hard' we will get copy-on-write behavior and // tombstones when any deletion happens inside the container). // It is also set as sparse so all layers recursively merge without needing an explicit reparse point // for each of them hresult = NativeContainerUtilities.WciSetupFilter( hJob, NativeContainerUtilities.WC_ISOLATION_MODE.IsolationModeSparseHard, destinationPath, layerDescriptors, (uint)layerDescriptors.Length, NativeContainerUtilities.WC_NESTING_MODE.WcNestingModeInner); retries--; if (hresult != 0) { wciRetries.Add(I($"Error setting WCI filter for {hJob} from '{string.Join(Environment.NewLine, sourcePaths)}' to '{destinationPath}'. Retries left: {retries}. Details: {NativeWin32Exception.GetFormattedMessageForNativeErrorCode(hresult)}")); } } if (hresult != 0) { throw new NativeWin32Exception(Marshal.GetLastWin32Error(), I($"Unable to setup the WCI filter for source paths '{string.Join(Environment.NewLine, sourcePaths)}' to destination path '{destinationPath}'.")); } }
/// <summary><see cref="ProcessUtilities.TryCleanUpContainer"/></summary> public bool TryCleanUpContainer(IntPtr hJob, out IEnumerable <string> errors) { var cleanUpErrors = new List <string>(); var result = NativeContainerUtilities.WcCleanupContainer(hJob, null); if (result != 0) { cleanUpErrors.Add(I($"Cannot clean up container for job object {hJob}. Details: {NativeWin32Exception.GetFormattedMessageForNativeErrorCode(result)}")); } errors = cleanUpErrors; return(cleanUpErrors.Count == 0); }
/// <inheritdoc /> public override string Describe() { return(NativeWin32Exception.GetFormattedMessageForNativeErrorCode(NativeErrorCode, messagePrefix: Message)); }
public static NativeFailure CreateFromException(NativeWin32Exception exception) { return(new NativeFailure(exception.NativeErrorCode, exception.Message)); }