1use std::borrow::Cow;
4use std::fmt;
5
6pub type Result<T> = std::result::Result<T, Error>;
8
9#[derive(Debug)]
11pub enum Error {
12 WindowsApi(WindowsApiError),
14
15 AccessDenied(AccessDeniedError),
17
18 NotFound(NotFoundError),
20
21 InvalidParameter(InvalidParameterError),
23
24 Registry(RegistryError),
26
27 Process(ProcessError),
29
30 Service(ServiceError),
32
33 Thread(ThreadError),
35
36 EventLog(EventLogError),
38
39 Etw(EtwError),
41
42 Mitigation(MitigationError),
44
45 Proxy(ProxyError),
47
48 Security(SecurityError),
50
51 FileOperation(FileOperationError),
53
54 Pipe(PipeError),
56
57 Desktop(DesktopError),
59
60 Other(OtherError),
62}
63
64impl fmt::Display for Error {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 match self {
67 Error::WindowsApi(e) => write!(f, "{}", e),
68 Error::AccessDenied(e) => write!(f, "{}", e),
69 Error::NotFound(e) => write!(f, "{}", e),
70 Error::InvalidParameter(e) => write!(f, "{}", e),
71 Error::Registry(e) => write!(f, "{}", e),
72 Error::Process(e) => write!(f, "{}", e),
73 Error::Service(e) => write!(f, "{}", e),
74 Error::Thread(e) => write!(f, "{}", e),
75 Error::EventLog(e) => write!(f, "{}", e),
76 Error::Etw(e) => write!(f, "{}", e),
77 Error::Mitigation(e) => write!(f, "{}", e),
78 Error::Proxy(e) => write!(f, "{}", e),
79 Error::Security(e) => write!(f, "{}", e),
80 Error::FileOperation(e) => write!(f, "{}", e),
81 Error::Pipe(e) => write!(f, "{}", e),
82 Error::Desktop(e) => write!(f, "{}", e),
83 Error::Other(e) => write!(f, "{}", e),
84 }
85 }
86}
87
88impl std::error::Error for Error {}
89
90impl From<windows::core::Error> for Error {
91 fn from(err: windows::core::Error) -> Self {
92 Error::WindowsApi(WindowsApiError {
93 inner: err,
94 context: None,
95 })
96 }
97}
98
99#[derive(Debug)]
105pub struct WindowsApiError {
106 pub inner: windows::core::Error,
108 pub context: Option<Cow<'static, str>>,
110}
111
112impl WindowsApiError {
113 pub fn new(inner: windows::core::Error) -> Self {
115 WindowsApiError {
116 inner,
117 context: None,
118 }
119 }
120
121 pub fn with_context(
123 inner: windows::core::Error,
124 context: impl Into<Cow<'static, str>>,
125 ) -> Self {
126 WindowsApiError {
127 inner,
128 context: Some(context.into()),
129 }
130 }
131
132 pub fn code(&self) -> i32 {
134 self.inner.code().0
135 }
136}
137
138impl fmt::Display for WindowsApiError {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 if let Some(context) = &self.context {
141 write!(f, "Windows API error in {}: {}", context, self.inner)
142 } else {
143 write!(f, "Windows API error: {}", self.inner)
144 }
145 }
146}
147
148impl std::error::Error for WindowsApiError {}
149
150#[derive(Debug)]
152pub struct AccessDeniedError {
153 pub resource: Cow<'static, str>,
155 pub operation: Cow<'static, str>,
157 pub reason: Option<Cow<'static, str>>,
159}
160
161impl AccessDeniedError {
162 pub fn new(
164 resource: impl Into<Cow<'static, str>>,
165 operation: impl Into<Cow<'static, str>>,
166 ) -> Self {
167 AccessDeniedError {
168 resource: resource.into(),
169 operation: operation.into(),
170 reason: None,
171 }
172 }
173
174 pub fn with_reason(
176 resource: impl Into<Cow<'static, str>>,
177 operation: impl Into<Cow<'static, str>>,
178 reason: impl Into<Cow<'static, str>>,
179 ) -> Self {
180 AccessDeniedError {
181 resource: resource.into(),
182 operation: operation.into(),
183 reason: Some(reason.into()),
184 }
185 }
186}
187
188impl fmt::Display for AccessDeniedError {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 if let Some(reason) = &self.reason {
191 write!(
192 f,
193 "Access denied: cannot {} '{}' ({})",
194 self.operation, self.resource, reason
195 )
196 } else {
197 write!(
198 f,
199 "Access denied: cannot {} '{}'",
200 self.operation, self.resource
201 )
202 }
203 }
204}
205
206impl std::error::Error for AccessDeniedError {}
207
208#[derive(Debug)]
210pub struct NotFoundError {
211 pub resource_type: Cow<'static, str>,
213 pub identifier: Cow<'static, str>,
215}
216
217impl NotFoundError {
218 pub fn new(
220 resource_type: impl Into<Cow<'static, str>>,
221 identifier: impl Into<Cow<'static, str>>,
222 ) -> Self {
223 NotFoundError {
224 resource_type: resource_type.into(),
225 identifier: identifier.into(),
226 }
227 }
228}
229
230impl fmt::Display for NotFoundError {
231 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232 write!(f, "{} not found: {}", self.resource_type, self.identifier)
233 }
234}
235
236impl std::error::Error for NotFoundError {}
237
238#[derive(Debug)]
240pub struct InvalidParameterError {
241 pub parameter: Cow<'static, str>,
243 pub reason: Cow<'static, str>,
245}
246
247impl InvalidParameterError {
248 pub fn new(
250 parameter: impl Into<Cow<'static, str>>,
251 reason: impl Into<Cow<'static, str>>,
252 ) -> Self {
253 InvalidParameterError {
254 parameter: parameter.into(),
255 reason: reason.into(),
256 }
257 }
258}
259
260impl fmt::Display for InvalidParameterError {
261 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262 write!(f, "Invalid parameter '{}': {}", self.parameter, self.reason)
263 }
264}
265
266impl std::error::Error for InvalidParameterError {}
267
268#[derive(Debug)]
270pub struct FileOperationError {
271 pub path: Cow<'static, str>,
273 pub operation: Cow<'static, str>,
275 pub error_code: Option<i32>,
277}
278
279impl FileOperationError {
280 pub fn new(
282 path: impl Into<Cow<'static, str>>,
283 operation: impl Into<Cow<'static, str>>,
284 ) -> Self {
285 FileOperationError {
286 path: path.into(),
287 operation: operation.into(),
288 error_code: None,
289 }
290 }
291
292 pub fn with_code(
294 path: impl Into<Cow<'static, str>>,
295 operation: impl Into<Cow<'static, str>>,
296 error_code: i32,
297 ) -> Self {
298 FileOperationError {
299 path: path.into(),
300 operation: operation.into(),
301 error_code: Some(error_code),
302 }
303 }
304}
305
306impl fmt::Display for FileOperationError {
307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308 if let Some(code) = self.error_code {
309 write!(
310 f,
311 "File operation '{}' failed on '{}' (error code: 0x{:08X})",
312 self.operation, self.path, code
313 )
314 } else {
315 write!(
316 f,
317 "File operation '{}' failed on '{}'",
318 self.operation, self.path
319 )
320 }
321 }
322}
323
324impl std::error::Error for FileOperationError {}
325
326#[derive(Debug)]
332pub enum PipeError {
333 Create(PipeCreateError),
335
336 Connect(PipeConnectError),
338
339 Io(PipeIoError),
341
342 Timeout(PipeTimeoutError),
344
345 InvalidState(PipeInvalidStateError),
347}
348
349impl fmt::Display for PipeError {
350 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
351 match self {
352 PipeError::Create(e) => write!(f, "{}", e),
353 PipeError::Connect(e) => write!(f, "{}", e),
354 PipeError::Io(e) => write!(f, "{}", e),
355 PipeError::Timeout(e) => write!(f, "{}", e),
356 PipeError::InvalidState(e) => write!(f, "{}", e),
357 }
358 }
359}
360
361impl std::error::Error for PipeError {}
362
363#[derive(Debug)]
365pub struct PipeCreateError {
366 pub pipe_name: Cow<'static, str>,
368 pub operation: Cow<'static, str>,
370 pub error_code: Option<i32>,
372}
373
374impl PipeCreateError {
375 pub fn new(
377 pipe_name: impl Into<Cow<'static, str>>,
378 operation: impl Into<Cow<'static, str>>,
379 ) -> Self {
380 PipeCreateError {
381 pipe_name: pipe_name.into(),
382 operation: operation.into(),
383 error_code: None,
384 }
385 }
386
387 pub fn with_code(
389 pipe_name: impl Into<Cow<'static, str>>,
390 operation: impl Into<Cow<'static, str>>,
391 error_code: i32,
392 ) -> Self {
393 PipeCreateError {
394 pipe_name: pipe_name.into(),
395 operation: operation.into(),
396 error_code: Some(error_code),
397 }
398 }
399}
400
401impl fmt::Display for PipeCreateError {
402 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403 if let Some(code) = self.error_code {
404 write!(
405 f,
406 "Pipe creation '{}' failed for '{}' (error code: 0x{:08X})",
407 self.operation, self.pipe_name, code
408 )
409 } else {
410 write!(
411 f,
412 "Pipe creation '{}' failed for '{}'",
413 self.operation, self.pipe_name
414 )
415 }
416 }
417}
418
419impl std::error::Error for PipeCreateError {}
420
421#[derive(Debug)]
423pub struct PipeConnectError {
424 pub pipe_name: Cow<'static, str>,
426 pub context: Option<Cow<'static, str>>,
428 pub error_code: Option<i32>,
430}
431
432impl PipeConnectError {
433 pub fn new(pipe_name: impl Into<Cow<'static, str>>) -> Self {
435 PipeConnectError {
436 pipe_name: pipe_name.into(),
437 context: None,
438 error_code: None,
439 }
440 }
441
442 pub fn with_context(mut self, context: impl Into<Cow<'static, str>>) -> Self {
444 self.context = Some(context.into());
445 self
446 }
447
448 pub fn with_code(mut self, error_code: i32) -> Self {
450 self.error_code = Some(error_code);
451 self
452 }
453}
454
455impl fmt::Display for PipeConnectError {
456 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457 match (&self.context, self.error_code) {
458 (Some(context), Some(code)) => write!(
459 f,
460 "Pipe connect failed for '{}' ({}, error code: 0x{:08X})",
461 self.pipe_name, context, code
462 ),
463 (Some(context), None) => {
464 write!(
465 f,
466 "Pipe connect failed for '{}' ({})",
467 self.pipe_name, context
468 )
469 }
470 (None, Some(code)) => write!(
471 f,
472 "Pipe connect failed for '{}' (error code: 0x{:08X})",
473 self.pipe_name, code
474 ),
475 (None, None) => write!(f, "Pipe connect failed for '{}'", self.pipe_name),
476 }
477 }
478}
479
480impl std::error::Error for PipeConnectError {}
481
482#[derive(Debug)]
484pub struct PipeIoError {
485 pub pipe_name: Cow<'static, str>,
487 pub operation: Cow<'static, str>,
489 pub error_code: Option<i32>,
491}
492
493impl PipeIoError {
494 pub fn new(
496 pipe_name: impl Into<Cow<'static, str>>,
497 operation: impl Into<Cow<'static, str>>,
498 ) -> Self {
499 PipeIoError {
500 pipe_name: pipe_name.into(),
501 operation: operation.into(),
502 error_code: None,
503 }
504 }
505
506 pub fn with_code(
508 pipe_name: impl Into<Cow<'static, str>>,
509 operation: impl Into<Cow<'static, str>>,
510 error_code: i32,
511 ) -> Self {
512 PipeIoError {
513 pipe_name: pipe_name.into(),
514 operation: operation.into(),
515 error_code: Some(error_code),
516 }
517 }
518}
519
520impl fmt::Display for PipeIoError {
521 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522 if let Some(code) = self.error_code {
523 write!(
524 f,
525 "Pipe I/O '{}' failed for '{}' (error code: 0x{:08X})",
526 self.operation, self.pipe_name, code
527 )
528 } else {
529 write!(
530 f,
531 "Pipe I/O '{}' failed for '{}'",
532 self.operation, self.pipe_name
533 )
534 }
535 }
536}
537
538impl std::error::Error for PipeIoError {}
539
540#[derive(Debug)]
542pub struct PipeTimeoutError {
543 pub pipe_name: Cow<'static, str>,
545 pub operation: Cow<'static, str>,
547}
548
549impl PipeTimeoutError {
550 pub fn new(
552 pipe_name: impl Into<Cow<'static, str>>,
553 operation: impl Into<Cow<'static, str>>,
554 ) -> Self {
555 PipeTimeoutError {
556 pipe_name: pipe_name.into(),
557 operation: operation.into(),
558 }
559 }
560}
561
562impl fmt::Display for PipeTimeoutError {
563 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
564 write!(
565 f,
566 "Pipe operation '{}' timed out for '{}'",
567 self.operation, self.pipe_name
568 )
569 }
570}
571
572impl std::error::Error for PipeTimeoutError {}
573
574#[derive(Debug)]
576pub struct PipeInvalidStateError {
577 pub operation: Cow<'static, str>,
579 pub reason: Cow<'static, str>,
581}
582
583impl PipeInvalidStateError {
584 pub fn new(
586 operation: impl Into<Cow<'static, str>>,
587 reason: impl Into<Cow<'static, str>>,
588 ) -> Self {
589 PipeInvalidStateError {
590 operation: operation.into(),
591 reason: reason.into(),
592 }
593 }
594}
595
596impl fmt::Display for PipeInvalidStateError {
597 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
598 write!(
599 f,
600 "Pipe operation '{}' is invalid in current state: {}",
601 self.operation, self.reason
602 )
603 }
604}
605
606impl std::error::Error for PipeInvalidStateError {}
607
608#[derive(Debug)]
610pub struct OtherError {
611 pub message: Cow<'static, str>,
613}
614
615impl OtherError {
616 pub fn new(message: impl Into<Cow<'static, str>>) -> Self {
618 OtherError {
619 message: message.into(),
620 }
621 }
622}
623
624impl fmt::Display for OtherError {
625 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
626 write!(f, "{}", self.message)
627 }
628}
629
630impl std::error::Error for OtherError {}
631
632#[derive(Debug)]
638pub enum DesktopError {
639 OperationFailed(DesktopOperationError),
641
642 WindowNotFound(WindowNotFoundError),
644}
645
646impl fmt::Display for DesktopError {
647 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
648 match self {
649 DesktopError::OperationFailed(e) => write!(f, "{}", e),
650 DesktopError::WindowNotFound(e) => write!(f, "{}", e),
651 }
652 }
653}
654
655impl std::error::Error for DesktopError {}
656
657#[derive(Debug)]
659pub struct DesktopOperationError {
660 pub operation: Cow<'static, str>,
662 pub target: Cow<'static, str>,
664 pub error_code: Option<i32>,
666}
667
668impl DesktopOperationError {
669 pub fn new(
671 operation: impl Into<Cow<'static, str>>,
672 target: impl Into<Cow<'static, str>>,
673 ) -> Self {
674 DesktopOperationError {
675 operation: operation.into(),
676 target: target.into(),
677 error_code: None,
678 }
679 }
680
681 pub fn with_code(
683 operation: impl Into<Cow<'static, str>>,
684 target: impl Into<Cow<'static, str>>,
685 error_code: i32,
686 ) -> Self {
687 DesktopOperationError {
688 operation: operation.into(),
689 target: target.into(),
690 error_code: Some(error_code),
691 }
692 }
693}
694
695impl fmt::Display for DesktopOperationError {
696 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
697 if let Some(code) = self.error_code {
698 write!(
699 f,
700 "Desktop operation '{}' failed for '{}' (error code: 0x{:08X})",
701 self.operation, self.target, code
702 )
703 } else {
704 write!(
705 f,
706 "Desktop operation '{}' failed for '{}'",
707 self.operation, self.target
708 )
709 }
710 }
711}
712
713impl std::error::Error for DesktopOperationError {}
714
715#[derive(Debug)]
717pub struct WindowNotFoundError {
718 pub identifier: Cow<'static, str>,
720}
721
722impl WindowNotFoundError {
723 pub fn new(identifier: impl Into<Cow<'static, str>>) -> Self {
725 WindowNotFoundError {
726 identifier: identifier.into(),
727 }
728 }
729}
730
731impl fmt::Display for WindowNotFoundError {
732 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
733 write!(f, "Window not found: {}", self.identifier)
734 }
735}
736
737impl std::error::Error for WindowNotFoundError {}
738
739#[derive(Debug)]
745pub enum SecurityError {
746 SidParse(SidParseError),
748
749 PermissionEdit(PermissionEditError),
751
752 Unsupported(SecurityUnsupportedError),
754}
755
756impl fmt::Display for SecurityError {
757 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
758 match self {
759 SecurityError::SidParse(e) => write!(f, "{}", e),
760 SecurityError::PermissionEdit(e) => write!(f, "{}", e),
761 SecurityError::Unsupported(e) => write!(f, "{}", e),
762 }
763 }
764}
765
766impl std::error::Error for SecurityError {}
767
768#[derive(Debug)]
770pub struct SidParseError {
771 pub input: Cow<'static, str>,
773 pub reason: Cow<'static, str>,
775}
776
777impl SidParseError {
778 pub fn new(input: impl Into<Cow<'static, str>>, reason: impl Into<Cow<'static, str>>) -> Self {
780 SidParseError {
781 input: input.into(),
782 reason: reason.into(),
783 }
784 }
785}
786
787impl fmt::Display for SidParseError {
788 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
789 write!(f, "SID parse error for '{}': {}", self.input, self.reason)
790 }
791}
792
793impl std::error::Error for SidParseError {}
794
795#[derive(Debug)]
797pub struct PermissionEditError {
798 pub operation: Cow<'static, str>,
800 pub reason: Cow<'static, str>,
802}
803
804impl PermissionEditError {
805 pub fn new(
807 operation: impl Into<Cow<'static, str>>,
808 reason: impl Into<Cow<'static, str>>,
809 ) -> Self {
810 PermissionEditError {
811 operation: operation.into(),
812 reason: reason.into(),
813 }
814 }
815}
816
817impl fmt::Display for PermissionEditError {
818 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
819 write!(
820 f,
821 "Permission edit '{}' failed: {}",
822 self.operation, self.reason
823 )
824 }
825}
826
827impl std::error::Error for PermissionEditError {}
828
829#[derive(Debug)]
831pub struct SecurityUnsupportedError {
832 pub target: Cow<'static, str>,
834 pub operation: Cow<'static, str>,
836 pub reason: Option<Cow<'static, str>>,
838}
839
840impl SecurityUnsupportedError {
841 pub fn new(
843 target: impl Into<Cow<'static, str>>,
844 operation: impl Into<Cow<'static, str>>,
845 ) -> Self {
846 SecurityUnsupportedError {
847 target: target.into(),
848 operation: operation.into(),
849 reason: None,
850 }
851 }
852
853 pub fn with_reason(
855 target: impl Into<Cow<'static, str>>,
856 operation: impl Into<Cow<'static, str>>,
857 reason: impl Into<Cow<'static, str>>,
858 ) -> Self {
859 SecurityUnsupportedError {
860 target: target.into(),
861 operation: operation.into(),
862 reason: Some(reason.into()),
863 }
864 }
865}
866
867impl fmt::Display for SecurityUnsupportedError {
868 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
869 if let Some(reason) = &self.reason {
870 write!(
871 f,
872 "Security operation '{}' is not supported for '{}': {}",
873 self.operation, self.target, reason
874 )
875 } else {
876 write!(
877 f,
878 "Security operation '{}' is not supported for '{}'",
879 self.operation, self.target
880 )
881 }
882 }
883}
884
885impl std::error::Error for SecurityUnsupportedError {}
886
887#[derive(Debug)]
893pub enum ProxyError {
894 InvalidConfig(ProxyConfigError),
896
897 DiscoveryFailed(ProxyConfigError),
899
900 ResolutionFailed(ProxyResolutionError),
902}
903
904impl fmt::Display for ProxyError {
905 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
906 match self {
907 ProxyError::InvalidConfig(e) => write!(f, "{}", e),
908 ProxyError::DiscoveryFailed(e) => write!(f, "{}", e),
909 ProxyError::ResolutionFailed(e) => write!(f, "{}", e),
910 }
911 }
912}
913
914impl std::error::Error for ProxyError {}
915
916#[derive(Debug)]
918pub struct ProxyConfigError {
919 pub setting: Cow<'static, str>,
921 pub reason: Cow<'static, str>,
923}
924
925impl ProxyConfigError {
926 pub fn new(
928 setting: impl Into<Cow<'static, str>>,
929 reason: impl Into<Cow<'static, str>>,
930 ) -> Self {
931 ProxyConfigError {
932 setting: setting.into(),
933 reason: reason.into(),
934 }
935 }
936}
937
938impl fmt::Display for ProxyConfigError {
939 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
940 write!(
941 f,
942 "Proxy configuration error for '{}': {}",
943 self.setting, self.reason
944 )
945 }
946}
947
948impl std::error::Error for ProxyConfigError {}
949
950#[derive(Debug)]
952pub struct ProxyResolutionError {
953 pub url: Cow<'static, str>,
955 pub reason: Cow<'static, str>,
957}
958
959impl ProxyResolutionError {
960 pub fn new(url: impl Into<Cow<'static, str>>, reason: impl Into<Cow<'static, str>>) -> Self {
962 ProxyResolutionError {
963 url: url.into(),
964 reason: reason.into(),
965 }
966 }
967}
968
969impl fmt::Display for ProxyResolutionError {
970 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
971 write!(
972 f,
973 "Proxy resolution failed for '{}': {}",
974 self.url, self.reason
975 )
976 }
977}
978
979impl std::error::Error for ProxyResolutionError {}
980
981#[derive(Debug)]
987pub enum RegistryError {
988 KeyNotFound(RegistryKeyNotFoundError),
990
991 ValueNotFound(RegistryValueNotFoundError),
993
994 InvalidType(RegistryInvalidTypeError),
996
997 ConversionError(RegistryConversionError),
999}
1000
1001impl fmt::Display for RegistryError {
1002 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1003 match self {
1004 RegistryError::KeyNotFound(e) => write!(f, "{}", e),
1005 RegistryError::ValueNotFound(e) => write!(f, "{}", e),
1006 RegistryError::InvalidType(e) => write!(f, "{}", e),
1007 RegistryError::ConversionError(e) => write!(f, "{}", e),
1008 }
1009 }
1010}
1011
1012impl std::error::Error for RegistryError {}
1013
1014#[derive(Debug)]
1016pub struct RegistryKeyNotFoundError {
1017 pub key_path: Cow<'static, str>,
1019 pub error_code: Option<i32>,
1021}
1022
1023impl RegistryKeyNotFoundError {
1024 pub fn new(key_path: impl Into<Cow<'static, str>>) -> Self {
1026 RegistryKeyNotFoundError {
1027 key_path: key_path.into(),
1028 error_code: None,
1029 }
1030 }
1031
1032 pub fn with_code(key_path: impl Into<Cow<'static, str>>, error_code: i32) -> Self {
1034 RegistryKeyNotFoundError {
1035 key_path: key_path.into(),
1036 error_code: Some(error_code),
1037 }
1038 }
1039}
1040
1041impl fmt::Display for RegistryKeyNotFoundError {
1042 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1043 if let Some(code) = self.error_code {
1044 write!(
1045 f,
1046 "Registry key not found: {} (error code: 0x{:08X})",
1047 self.key_path, code
1048 )
1049 } else {
1050 write!(f, "Registry key not found: {}", self.key_path)
1051 }
1052 }
1053}
1054
1055impl std::error::Error for RegistryKeyNotFoundError {}
1056
1057#[derive(Debug)]
1059pub struct RegistryValueNotFoundError {
1060 pub value_name: Cow<'static, str>,
1062 pub key_path: Option<Cow<'static, str>>,
1064}
1065
1066impl RegistryValueNotFoundError {
1067 pub fn new(value_name: impl Into<Cow<'static, str>>) -> Self {
1069 RegistryValueNotFoundError {
1070 value_name: value_name.into(),
1071 key_path: None,
1072 }
1073 }
1074
1075 pub fn with_key(
1077 value_name: impl Into<Cow<'static, str>>,
1078 key_path: impl Into<Cow<'static, str>>,
1079 ) -> Self {
1080 RegistryValueNotFoundError {
1081 value_name: value_name.into(),
1082 key_path: Some(key_path.into()),
1083 }
1084 }
1085}
1086
1087impl fmt::Display for RegistryValueNotFoundError {
1088 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1089 if let Some(key) = &self.key_path {
1090 write!(
1091 f,
1092 "Registry value '{}' not found in key '{}'",
1093 self.value_name, key
1094 )
1095 } else {
1096 write!(f, "Registry value not found: {}", self.value_name)
1097 }
1098 }
1099}
1100
1101impl std::error::Error for RegistryValueNotFoundError {}
1102
1103#[derive(Debug)]
1105pub struct RegistryInvalidTypeError {
1106 pub expected: Cow<'static, str>,
1108 pub found: Cow<'static, str>,
1110 pub value_name: Option<Cow<'static, str>>,
1112}
1113
1114impl RegistryInvalidTypeError {
1115 pub fn new(
1117 expected: impl Into<Cow<'static, str>>,
1118 found: impl Into<Cow<'static, str>>,
1119 ) -> Self {
1120 RegistryInvalidTypeError {
1121 expected: expected.into(),
1122 found: found.into(),
1123 value_name: None,
1124 }
1125 }
1126
1127 pub fn with_name(
1129 expected: impl Into<Cow<'static, str>>,
1130 found: impl Into<Cow<'static, str>>,
1131 value_name: impl Into<Cow<'static, str>>,
1132 ) -> Self {
1133 RegistryInvalidTypeError {
1134 expected: expected.into(),
1135 found: found.into(),
1136 value_name: Some(value_name.into()),
1137 }
1138 }
1139}
1140
1141impl fmt::Display for RegistryInvalidTypeError {
1142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1143 if let Some(name) = &self.value_name {
1144 write!(
1145 f,
1146 "Invalid registry type for '{}': expected {}, found {}",
1147 name, self.expected, self.found
1148 )
1149 } else {
1150 write!(
1151 f,
1152 "Invalid registry type: expected {}, found {}",
1153 self.expected, self.found
1154 )
1155 }
1156 }
1157}
1158
1159impl std::error::Error for RegistryInvalidTypeError {}
1160
1161#[derive(Debug)]
1163pub struct RegistryConversionError {
1164 pub conversion: Cow<'static, str>,
1166 pub reason: Cow<'static, str>,
1168}
1169
1170impl RegistryConversionError {
1171 pub fn new(
1173 conversion: impl Into<Cow<'static, str>>,
1174 reason: impl Into<Cow<'static, str>>,
1175 ) -> Self {
1176 RegistryConversionError {
1177 conversion: conversion.into(),
1178 reason: reason.into(),
1179 }
1180 }
1181}
1182
1183impl fmt::Display for RegistryConversionError {
1184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1185 write!(
1186 f,
1187 "Registry conversion error ({}): {}",
1188 self.conversion, self.reason
1189 )
1190 }
1191}
1192
1193impl std::error::Error for RegistryConversionError {}
1194
1195#[derive(Debug)]
1201pub enum ServiceError {
1202 ManagerError(ServiceManagerError),
1204
1205 NotFound(ServiceNotFoundError),
1207
1208 OperationFailed(ServiceOperationError),
1210
1211 InvalidState(ServiceInvalidStateError),
1213}
1214
1215impl fmt::Display for ServiceError {
1216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1217 match self {
1218 ServiceError::ManagerError(e) => write!(f, "{}", e),
1219 ServiceError::NotFound(e) => write!(f, "{}", e),
1220 ServiceError::OperationFailed(e) => write!(f, "{}", e),
1221 ServiceError::InvalidState(e) => write!(f, "{}", e),
1222 }
1223 }
1224}
1225
1226impl std::error::Error for ServiceError {}
1227
1228#[derive(Debug)]
1230pub struct ServiceManagerError {
1231 pub operation: Cow<'static, str>,
1233 pub reason: Cow<'static, str>,
1235 pub error_code: Option<i32>,
1237}
1238
1239impl ServiceManagerError {
1240 pub fn new(
1242 operation: impl Into<Cow<'static, str>>,
1243 reason: impl Into<Cow<'static, str>>,
1244 ) -> Self {
1245 ServiceManagerError {
1246 operation: operation.into(),
1247 reason: reason.into(),
1248 error_code: None,
1249 }
1250 }
1251
1252 pub fn with_code(
1254 operation: impl Into<Cow<'static, str>>,
1255 reason: impl Into<Cow<'static, str>>,
1256 error_code: i32,
1257 ) -> Self {
1258 ServiceManagerError {
1259 operation: operation.into(),
1260 reason: reason.into(),
1261 error_code: Some(error_code),
1262 }
1263 }
1264}
1265
1266impl fmt::Display for ServiceManagerError {
1267 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1268 if let Some(code) = self.error_code {
1269 write!(
1270 f,
1271 "Service manager operation '{}' failed: {} (error code: 0x{:08X})",
1272 self.operation, self.reason, code
1273 )
1274 } else {
1275 write!(
1276 f,
1277 "Service manager operation '{}' failed: {}",
1278 self.operation, self.reason
1279 )
1280 }
1281 }
1282}
1283
1284impl std::error::Error for ServiceManagerError {}
1285
1286#[derive(Debug)]
1288pub struct ServiceNotFoundError {
1289 pub name: Cow<'static, str>,
1291 pub error_code: Option<i32>,
1293}
1294
1295impl ServiceNotFoundError {
1296 pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
1298 ServiceNotFoundError {
1299 name: name.into(),
1300 error_code: None,
1301 }
1302 }
1303
1304 pub fn with_code(name: impl Into<Cow<'static, str>>, error_code: i32) -> Self {
1306 ServiceNotFoundError {
1307 name: name.into(),
1308 error_code: Some(error_code),
1309 }
1310 }
1311}
1312
1313impl fmt::Display for ServiceNotFoundError {
1314 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1315 if let Some(code) = self.error_code {
1316 write!(
1317 f,
1318 "Service '{}' not found (error code: 0x{:08X})",
1319 self.name, code
1320 )
1321 } else {
1322 write!(f, "Service '{}' not found", self.name)
1323 }
1324 }
1325}
1326
1327impl std::error::Error for ServiceNotFoundError {}
1328
1329#[derive(Debug)]
1331pub struct ServiceOperationError {
1332 pub name: Cow<'static, str>,
1334 pub operation: Cow<'static, str>,
1336 pub reason: Cow<'static, str>,
1338 pub error_code: Option<i32>,
1340}
1341
1342impl ServiceOperationError {
1343 pub fn new(
1345 name: impl Into<Cow<'static, str>>,
1346 operation: impl Into<Cow<'static, str>>,
1347 reason: impl Into<Cow<'static, str>>,
1348 ) -> Self {
1349 ServiceOperationError {
1350 name: name.into(),
1351 operation: operation.into(),
1352 reason: reason.into(),
1353 error_code: None,
1354 }
1355 }
1356
1357 pub fn with_code(
1359 name: impl Into<Cow<'static, str>>,
1360 operation: impl Into<Cow<'static, str>>,
1361 reason: impl Into<Cow<'static, str>>,
1362 error_code: i32,
1363 ) -> Self {
1364 ServiceOperationError {
1365 name: name.into(),
1366 operation: operation.into(),
1367 reason: reason.into(),
1368 error_code: Some(error_code),
1369 }
1370 }
1371}
1372
1373impl fmt::Display for ServiceOperationError {
1374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1375 if let Some(code) = self.error_code {
1376 write!(
1377 f,
1378 "Service '{}' operation '{}' failed: {} (error code: 0x{:08X})",
1379 self.name, self.operation, self.reason, code
1380 )
1381 } else {
1382 write!(
1383 f,
1384 "Service '{}' operation '{}' failed: {}",
1385 self.name, self.operation, self.reason
1386 )
1387 }
1388 }
1389}
1390
1391impl std::error::Error for ServiceOperationError {}
1392
1393#[derive(Debug)]
1395pub struct ServiceInvalidStateError {
1396 pub name: Cow<'static, str>,
1398 pub expected: Cow<'static, str>,
1400 pub reason: Cow<'static, str>,
1402}
1403
1404impl ServiceInvalidStateError {
1405 pub fn new(
1407 name: impl Into<Cow<'static, str>>,
1408 expected: impl Into<Cow<'static, str>>,
1409 reason: impl Into<Cow<'static, str>>,
1410 ) -> Self {
1411 ServiceInvalidStateError {
1412 name: name.into(),
1413 expected: expected.into(),
1414 reason: reason.into(),
1415 }
1416 }
1417}
1418
1419impl fmt::Display for ServiceInvalidStateError {
1420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1421 write!(
1422 f,
1423 "Service '{}' is not in expected state '{}': {}",
1424 self.name, self.expected, self.reason
1425 )
1426 }
1427}
1428
1429impl std::error::Error for ServiceInvalidStateError {}
1430
1431#[derive(Debug)]
1437pub enum ProcessError {
1438 NotFound(ProcessNotFoundError),
1440
1441 AlreadyTerminated(ProcessTerminatedError),
1443
1444 OpenFailed(ProcessOpenError),
1446
1447 SpawnFailed(ProcessSpawnError),
1449
1450 InvalidProcessId,
1452
1453 InjectionFailed(InjectionFailedError),
1455
1456 AlreadyInjected(AlreadyInjectedError),
1458}
1459
1460impl fmt::Display for ProcessError {
1461 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1462 match self {
1463 ProcessError::NotFound(e) => write!(f, "{}", e),
1464 ProcessError::AlreadyTerminated(e) => write!(f, "{}", e),
1465 ProcessError::OpenFailed(e) => write!(f, "{}", e),
1466 ProcessError::SpawnFailed(e) => write!(f, "{}", e),
1467 ProcessError::InvalidProcessId => write!(f, "Invalid process ID"),
1468 ProcessError::InjectionFailed(e) => write!(f, "{}", e),
1469 ProcessError::AlreadyInjected(e) => write!(f, "{}", e),
1470 }
1471 }
1472}
1473
1474impl std::error::Error for ProcessError {}
1475
1476#[derive(Debug)]
1478pub struct ProcessNotFoundError {
1479 pub pid: u32,
1481}
1482
1483impl ProcessNotFoundError {
1484 pub fn new(pid: u32) -> Self {
1486 ProcessNotFoundError { pid }
1487 }
1488}
1489
1490impl fmt::Display for ProcessNotFoundError {
1491 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1492 write!(f, "Process {} not found", self.pid)
1493 }
1494}
1495
1496impl std::error::Error for ProcessNotFoundError {}
1497
1498#[derive(Debug)]
1500pub struct ProcessTerminatedError {
1501 pub pid: u32,
1503 pub exit_code: Option<u32>,
1505}
1506
1507impl ProcessTerminatedError {
1508 pub fn new(pid: u32) -> Self {
1510 ProcessTerminatedError {
1511 pid,
1512 exit_code: None,
1513 }
1514 }
1515
1516 pub fn with_exit_code(pid: u32, exit_code: u32) -> Self {
1518 ProcessTerminatedError {
1519 pid,
1520 exit_code: Some(exit_code),
1521 }
1522 }
1523}
1524
1525impl fmt::Display for ProcessTerminatedError {
1526 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1527 if let Some(code) = self.exit_code {
1528 write!(
1529 f,
1530 "Process {} already terminated (exit code: {})",
1531 self.pid, code
1532 )
1533 } else {
1534 write!(f, "Process {} already terminated", self.pid)
1535 }
1536 }
1537}
1538
1539impl std::error::Error for ProcessTerminatedError {}
1540
1541#[derive(Debug)]
1543pub struct ProcessOpenError {
1544 pub pid: u32,
1546 pub reason: Cow<'static, str>,
1548 pub error_code: Option<i32>,
1550}
1551
1552impl ProcessOpenError {
1553 pub fn new(pid: u32, reason: impl Into<Cow<'static, str>>) -> Self {
1555 ProcessOpenError {
1556 pid,
1557 reason: reason.into(),
1558 error_code: None,
1559 }
1560 }
1561
1562 pub fn with_code(pid: u32, reason: impl Into<Cow<'static, str>>, error_code: i32) -> Self {
1564 ProcessOpenError {
1565 pid,
1566 reason: reason.into(),
1567 error_code: Some(error_code),
1568 }
1569 }
1570}
1571
1572impl fmt::Display for ProcessOpenError {
1573 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1574 if let Some(code) = self.error_code {
1575 write!(
1576 f,
1577 "Failed to open process {}: {} (error code: 0x{:08X})",
1578 self.pid, self.reason, code
1579 )
1580 } else {
1581 write!(f, "Failed to open process {}: {}", self.pid, self.reason)
1582 }
1583 }
1584}
1585
1586impl std::error::Error for ProcessOpenError {}
1587
1588#[derive(Debug)]
1590pub struct ProcessSpawnError {
1591 pub command: Cow<'static, str>,
1593 pub reason: Cow<'static, str>,
1595 pub error_code: Option<i32>,
1597}
1598
1599impl ProcessSpawnError {
1600 pub fn new(
1602 command: impl Into<Cow<'static, str>>,
1603 reason: impl Into<Cow<'static, str>>,
1604 ) -> Self {
1605 ProcessSpawnError {
1606 command: command.into(),
1607 reason: reason.into(),
1608 error_code: None,
1609 }
1610 }
1611
1612 pub fn with_code(
1614 command: impl Into<Cow<'static, str>>,
1615 reason: impl Into<Cow<'static, str>>,
1616 error_code: i32,
1617 ) -> Self {
1618 ProcessSpawnError {
1619 command: command.into(),
1620 reason: reason.into(),
1621 error_code: Some(error_code),
1622 }
1623 }
1624}
1625
1626impl fmt::Display for ProcessSpawnError {
1627 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1628 if let Some(code) = self.error_code {
1629 write!(
1630 f,
1631 "Failed to spawn process '{}': {} (error code: 0x{:08X})",
1632 self.command, self.reason, code
1633 )
1634 } else {
1635 write!(
1636 f,
1637 "Failed to spawn process '{}': {}",
1638 self.command, self.reason
1639 )
1640 }
1641 }
1642}
1643
1644impl std::error::Error for ProcessSpawnError {}
1645
1646#[derive(Debug)]
1648pub struct InjectionFailedError {
1649 pub pid: u32,
1651 pub reason: Cow<'static, str>,
1653 pub error_code: Option<i32>,
1655}
1656
1657impl InjectionFailedError {
1658 pub fn new(pid: u32, reason: impl Into<Cow<'static, str>>) -> Self {
1660 InjectionFailedError {
1661 pid,
1662 reason: reason.into(),
1663 error_code: None,
1664 }
1665 }
1666
1667 pub fn with_code(pid: u32, reason: impl Into<Cow<'static, str>>, error_code: i32) -> Self {
1669 InjectionFailedError {
1670 pid,
1671 reason: reason.into(),
1672 error_code: Some(error_code),
1673 }
1674 }
1675}
1676
1677impl fmt::Display for InjectionFailedError {
1678 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1679 if let Some(code) = self.error_code {
1680 write!(
1681 f,
1682 "DLL injection into process {} failed: {} (error code: 0x{:08X})",
1683 self.pid, self.reason, code
1684 )
1685 } else {
1686 write!(
1687 f,
1688 "DLL injection into process {} failed: {}",
1689 self.pid, self.reason
1690 )
1691 }
1692 }
1693}
1694
1695impl std::error::Error for InjectionFailedError {}
1696
1697#[derive(Debug)]
1699pub struct AlreadyInjectedError {
1700 pub pid: u32,
1702 pub dll_name: Cow<'static, str>,
1704}
1705
1706impl AlreadyInjectedError {
1707 pub fn new(pid: u32, dll_name: impl Into<Cow<'static, str>>) -> Self {
1709 AlreadyInjectedError {
1710 pid,
1711 dll_name: dll_name.into(),
1712 }
1713 }
1714}
1715
1716impl fmt::Display for AlreadyInjectedError {
1717 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1718 write!(
1719 f,
1720 "DLL '{}' is already loaded in process {}",
1721 self.dll_name, self.pid
1722 )
1723 }
1724}
1725
1726impl std::error::Error for AlreadyInjectedError {}
1727
1728#[derive(Debug)]
1734pub enum ThreadError {
1735 NotFound(ThreadNotFoundError),
1737
1738 OpenFailed(ThreadOpenError),
1740}
1741
1742impl fmt::Display for ThreadError {
1743 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1744 match self {
1745 ThreadError::NotFound(e) => write!(f, "{}", e),
1746 ThreadError::OpenFailed(e) => write!(f, "{}", e),
1747 }
1748 }
1749}
1750
1751impl std::error::Error for ThreadError {}
1752
1753#[derive(Debug)]
1755pub struct ThreadNotFoundError {
1756 pub tid: u32,
1758}
1759
1760impl ThreadNotFoundError {
1761 pub fn new(tid: u32) -> Self {
1763 ThreadNotFoundError { tid }
1764 }
1765}
1766
1767impl fmt::Display for ThreadNotFoundError {
1768 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1769 write!(f, "Thread {} not found", self.tid)
1770 }
1771}
1772
1773impl std::error::Error for ThreadNotFoundError {}
1774
1775#[derive(Debug)]
1777pub struct ThreadOpenError {
1778 pub tid: u32,
1780 pub reason: Cow<'static, str>,
1782 pub error_code: Option<i32>,
1784}
1785
1786impl ThreadOpenError {
1787 pub fn new(tid: u32, reason: impl Into<Cow<'static, str>>) -> Self {
1789 ThreadOpenError {
1790 tid,
1791 reason: reason.into(),
1792 error_code: None,
1793 }
1794 }
1795
1796 pub fn with_code(tid: u32, reason: impl Into<Cow<'static, str>>, error_code: i32) -> Self {
1798 ThreadOpenError {
1799 tid,
1800 reason: reason.into(),
1801 error_code: Some(error_code),
1802 }
1803 }
1804}
1805
1806impl fmt::Display for ThreadOpenError {
1807 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1808 if let Some(code) = self.error_code {
1809 write!(
1810 f,
1811 "Failed to open thread {}: {} (error code: 0x{:08X})",
1812 self.tid, self.reason, code
1813 )
1814 } else {
1815 write!(f, "Failed to open thread {}: {}", self.tid, self.reason)
1816 }
1817 }
1818}
1819
1820impl std::error::Error for ThreadOpenError {}
1821
1822#[derive(Debug)]
1828pub enum EventLogError {
1829 LogNotFound(EventLogNotFoundError),
1831
1832 QueryFailed(EventLogQueryError),
1834
1835 ParseFailed(EventLogParseError),
1837}
1838
1839impl fmt::Display for EventLogError {
1840 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1841 match self {
1842 EventLogError::LogNotFound(e) => write!(f, "{}", e),
1843 EventLogError::QueryFailed(e) => write!(f, "{}", e),
1844 EventLogError::ParseFailed(e) => write!(f, "{}", e),
1845 }
1846 }
1847}
1848
1849impl std::error::Error for EventLogError {}
1850
1851#[derive(Debug)]
1853pub struct EventLogNotFoundError {
1854 pub log_name: Cow<'static, str>,
1856}
1857
1858impl EventLogNotFoundError {
1859 pub fn new(log_name: impl Into<Cow<'static, str>>) -> Self {
1861 EventLogNotFoundError {
1862 log_name: log_name.into(),
1863 }
1864 }
1865}
1866
1867impl fmt::Display for EventLogNotFoundError {
1868 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1869 write!(f, "Event log not found: {}", self.log_name)
1870 }
1871}
1872
1873impl std::error::Error for EventLogNotFoundError {}
1874
1875#[derive(Debug)]
1877pub struct EventLogQueryError {
1878 pub log_name: Cow<'static, str>,
1880 pub reason: Cow<'static, str>,
1882 pub error_code: Option<i32>,
1884}
1885
1886impl EventLogQueryError {
1887 pub fn new(
1889 log_name: impl Into<Cow<'static, str>>,
1890 reason: impl Into<Cow<'static, str>>,
1891 ) -> Self {
1892 EventLogQueryError {
1893 log_name: log_name.into(),
1894 reason: reason.into(),
1895 error_code: None,
1896 }
1897 }
1898
1899 pub fn with_code(
1901 log_name: impl Into<Cow<'static, str>>,
1902 reason: impl Into<Cow<'static, str>>,
1903 error_code: i32,
1904 ) -> Self {
1905 EventLogQueryError {
1906 log_name: log_name.into(),
1907 reason: reason.into(),
1908 error_code: Some(error_code),
1909 }
1910 }
1911}
1912
1913impl fmt::Display for EventLogQueryError {
1914 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1915 if let Some(code) = self.error_code {
1916 write!(
1917 f,
1918 "Failed to query event log '{}': {} (error code: 0x{:08X})",
1919 self.log_name, self.reason, code
1920 )
1921 } else {
1922 write!(
1923 f,
1924 "Failed to query event log '{}': {}",
1925 self.log_name, self.reason
1926 )
1927 }
1928 }
1929}
1930
1931impl std::error::Error for EventLogQueryError {}
1932
1933#[derive(Debug)]
1935pub struct EventLogParseError {
1936 pub component: Cow<'static, str>,
1938 pub reason: Cow<'static, str>,
1940}
1941
1942impl EventLogParseError {
1943 pub fn new(
1945 component: impl Into<Cow<'static, str>>,
1946 reason: impl Into<Cow<'static, str>>,
1947 ) -> Self {
1948 EventLogParseError {
1949 component: component.into(),
1950 reason: reason.into(),
1951 }
1952 }
1953}
1954
1955impl fmt::Display for EventLogParseError {
1956 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1957 write!(f, "Failed to parse {}: {}", self.component, self.reason)
1958 }
1959}
1960
1961impl std::error::Error for EventLogParseError {}
1962
1963#[derive(Debug)]
1969pub enum EtwError {
1970 SessionStartFailed(EtwSessionError),
1972
1973 ProviderEnableFailed(EtwProviderError),
1975
1976 ConsumeFailed(EtwConsumeError),
1978}
1979
1980impl fmt::Display for EtwError {
1981 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1982 match self {
1983 EtwError::SessionStartFailed(e) => write!(f, "{}", e),
1984 EtwError::ProviderEnableFailed(e) => write!(f, "{}", e),
1985 EtwError::ConsumeFailed(e) => write!(f, "{}", e),
1986 }
1987 }
1988}
1989
1990impl std::error::Error for EtwError {}
1991
1992#[derive(Debug)]
1994pub struct EtwSessionError {
1995 pub session_name: Cow<'static, str>,
1997 pub reason: Cow<'static, str>,
1999 pub error_code: Option<i32>,
2001}
2002
2003impl EtwSessionError {
2004 pub fn new(
2006 session_name: impl Into<Cow<'static, str>>,
2007 reason: impl Into<Cow<'static, str>>,
2008 ) -> Self {
2009 EtwSessionError {
2010 session_name: session_name.into(),
2011 reason: reason.into(),
2012 error_code: None,
2013 }
2014 }
2015
2016 pub fn with_code(
2018 session_name: impl Into<Cow<'static, str>>,
2019 reason: impl Into<Cow<'static, str>>,
2020 error_code: i32,
2021 ) -> Self {
2022 EtwSessionError {
2023 session_name: session_name.into(),
2024 reason: reason.into(),
2025 error_code: Some(error_code),
2026 }
2027 }
2028
2029 pub fn already_exists(session_name: impl Into<Cow<'static, str>>) -> Self {
2031 EtwSessionError {
2032 session_name: session_name.into(),
2033 reason: Cow::Borrowed("Session already exists"),
2034 error_code: Some(-2147024713), }
2036 }
2037
2038 pub fn invalid_config(
2040 session_name: impl Into<Cow<'static, str>>,
2041 field: &'static str,
2042 issue: impl Into<Cow<'static, str>>,
2043 ) -> Self {
2044 EtwSessionError {
2045 session_name: session_name.into(),
2046 reason: Cow::Owned(format!("Invalid {}: {}", field, issue.into())),
2047 error_code: None,
2048 }
2049 }
2050}
2051
2052impl fmt::Display for EtwSessionError {
2053 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2054 if let Some(code) = self.error_code {
2055 write!(
2056 f,
2057 "Failed to start ETW session '{}': {} (error code: 0x{:08X})",
2058 self.session_name, self.reason, code
2059 )
2060 } else {
2061 write!(
2062 f,
2063 "Failed to start ETW session '{}': {}",
2064 self.session_name, self.reason
2065 )
2066 }
2067 }
2068}
2069
2070impl std::error::Error for EtwSessionError {}
2071
2072#[derive(Debug)]
2074pub struct EtwProviderError {
2075 pub provider: Cow<'static, str>,
2077 pub reason: Cow<'static, str>,
2079 pub error_code: Option<i32>,
2081}
2082
2083impl EtwProviderError {
2084 pub fn new(
2086 provider: impl Into<Cow<'static, str>>,
2087 reason: impl Into<Cow<'static, str>>,
2088 ) -> Self {
2089 EtwProviderError {
2090 provider: provider.into(),
2091 reason: reason.into(),
2092 error_code: None,
2093 }
2094 }
2095
2096 pub fn with_code(
2098 provider: impl Into<Cow<'static, str>>,
2099 reason: impl Into<Cow<'static, str>>,
2100 error_code: i32,
2101 ) -> Self {
2102 EtwProviderError {
2103 provider: provider.into(),
2104 reason: reason.into(),
2105 error_code: Some(error_code),
2106 }
2107 }
2108
2109 pub fn not_found(provider: impl Into<Cow<'static, str>>) -> Self {
2111 EtwProviderError {
2112 provider: provider.into(),
2113 reason: Cow::Borrowed("Provider not registered"),
2114 error_code: Some(0x00000490), }
2116 }
2117}
2118
2119impl fmt::Display for EtwProviderError {
2120 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2121 if let Some(code) = self.error_code {
2122 write!(
2123 f,
2124 "Failed to enable ETW provider '{}': {} (error code: 0x{:08X})",
2125 self.provider, self.reason, code
2126 )
2127 } else {
2128 write!(
2129 f,
2130 "Failed to enable ETW provider '{}': {}",
2131 self.provider, self.reason
2132 )
2133 }
2134 }
2135}
2136
2137impl std::error::Error for EtwProviderError {}
2138
2139#[derive(Debug)]
2141pub struct EtwConsumeError {
2142 pub reason: Cow<'static, str>,
2144 pub error_code: Option<i32>,
2146}
2147
2148impl EtwConsumeError {
2149 pub fn new(reason: impl Into<Cow<'static, str>>) -> Self {
2151 EtwConsumeError {
2152 reason: reason.into(),
2153 error_code: None,
2154 }
2155 }
2156
2157 pub fn with_code(reason: impl Into<Cow<'static, str>>, error_code: i32) -> Self {
2159 EtwConsumeError {
2160 reason: reason.into(),
2161 error_code: Some(error_code),
2162 }
2163 }
2164}
2165
2166impl fmt::Display for EtwConsumeError {
2167 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2168 if let Some(code) = self.error_code {
2169 write!(
2170 f,
2171 "Failed to consume ETW events: {} (error code: 0x{:08X})",
2172 self.reason, code
2173 )
2174 } else {
2175 write!(f, "Failed to consume ETW events: {}", self.reason)
2176 }
2177 }
2178}
2179
2180impl std::error::Error for EtwConsumeError {}
2181
2182#[derive(Debug)]
2188pub enum MitigationError {
2189 ApplyFailed(MitigationOperationError),
2191
2192 QueryFailed(MitigationOperationError),
2194}
2195
2196impl fmt::Display for MitigationError {
2197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2198 match self {
2199 MitigationError::ApplyFailed(e) => write!(f, "{}", e),
2200 MitigationError::QueryFailed(e) => write!(f, "{}", e),
2201 }
2202 }
2203}
2204
2205impl std::error::Error for MitigationError {}
2206
2207#[derive(Debug)]
2209pub struct MitigationOperationError {
2210 pub operation: Cow<'static, str>,
2212 pub policy: Cow<'static, str>,
2214 pub process_id: Option<u32>,
2216 pub reason: Option<Cow<'static, str>>,
2218 pub error_code: Option<i32>,
2220}
2221
2222impl MitigationOperationError {
2223 pub fn new(
2225 operation: impl Into<Cow<'static, str>>,
2226 policy: impl Into<Cow<'static, str>>,
2227 ) -> Self {
2228 MitigationOperationError {
2229 operation: operation.into(),
2230 policy: policy.into(),
2231 process_id: None,
2232 reason: None,
2233 error_code: None,
2234 }
2235 }
2236
2237 pub fn with_process_id(mut self, process_id: u32) -> Self {
2239 self.process_id = Some(process_id);
2240 self
2241 }
2242
2243 pub fn with_reason(mut self, reason: impl Into<Cow<'static, str>>) -> Self {
2245 self.reason = Some(reason.into());
2246 self
2247 }
2248
2249 pub fn with_code(mut self, error_code: i32) -> Self {
2251 self.error_code = Some(error_code);
2252 self
2253 }
2254}
2255
2256impl fmt::Display for MitigationOperationError {
2257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2258 match (self.process_id, &self.reason, self.error_code) {
2259 (Some(pid), Some(reason), Some(code)) => write!(
2260 f,
2261 "Mitigation {} failed for policy '{}' on process {}: {} (error code: 0x{:08X})",
2262 self.operation, self.policy, pid, reason, code
2263 ),
2264 (Some(pid), Some(reason), None) => write!(
2265 f,
2266 "Mitigation {} failed for policy '{}' on process {}: {}",
2267 self.operation, self.policy, pid, reason
2268 ),
2269 (Some(pid), None, Some(code)) => write!(
2270 f,
2271 "Mitigation {} failed for policy '{}' on process {} (error code: 0x{:08X})",
2272 self.operation, self.policy, pid, code
2273 ),
2274 (Some(pid), None, None) => write!(
2275 f,
2276 "Mitigation {} failed for policy '{}' on process {}",
2277 self.operation, self.policy, pid
2278 ),
2279 (None, Some(reason), Some(code)) => write!(
2280 f,
2281 "Mitigation {} failed for policy '{}': {} (error code: 0x{:08X})",
2282 self.operation, self.policy, reason, code
2283 ),
2284 (None, Some(reason), None) => write!(
2285 f,
2286 "Mitigation {} failed for policy '{}': {}",
2287 self.operation, self.policy, reason
2288 ),
2289 (None, None, Some(code)) => write!(
2290 f,
2291 "Mitigation {} failed for policy '{}' (error code: 0x{:08X})",
2292 self.operation, self.policy, code
2293 ),
2294 (None, None, None) => write!(
2295 f,
2296 "Mitigation {} failed for policy '{}'",
2297 self.operation, self.policy
2298 ),
2299 }
2300 }
2301}
2302
2303impl std::error::Error for MitigationOperationError {}
2304
2305#[cfg(test)]
2306mod tests {
2307 use super::{EtwConsumeError, EtwProviderError, EtwSessionError, MitigationOperationError};
2308 use std::borrow::Cow;
2309
2310 #[test]
2311 fn etw_session_error_invalid_config_message_contains_field() {
2312 let err = EtwSessionError::invalid_config(
2313 Cow::Borrowed("MySession"),
2314 "providers",
2315 Cow::Borrowed("cannot mix kernel and user providers"),
2316 );
2317
2318 assert_eq!(err.session_name, "MySession");
2319 assert!(err.reason.contains("Invalid providers"));
2320 assert!(err.reason.contains("cannot mix kernel and user providers"));
2321 assert!(err.error_code.is_none());
2322 }
2323
2324 #[test]
2325 fn etw_provider_error_not_found_has_expected_code() {
2326 let err = EtwProviderError::not_found(Cow::Borrowed("{provider-guid}"));
2327
2328 assert_eq!(err.provider, "{provider-guid}");
2329 assert_eq!(err.error_code, Some(0x00000490));
2330 assert!(err.reason.contains("Provider not registered"));
2331 }
2332
2333 #[test]
2334 fn etw_consume_error_display_with_code_contains_hex() {
2335 let err = EtwConsumeError::with_code(Cow::Borrowed("OpenTraceW failed"), 0x57);
2336 let rendered = err.to_string();
2337
2338 assert!(rendered.contains("OpenTraceW failed"));
2339 assert!(rendered.contains("0x00000057"));
2340 }
2341
2342 #[test]
2343 fn mitigation_operation_error_display_includes_policy_pid_and_code() {
2344 let err = MitigationOperationError::new("apply", "dynamic_code")
2345 .with_process_id(1234)
2346 .with_reason("Access denied")
2347 .with_code(5);
2348
2349 let rendered = err.to_string();
2350 assert!(rendered.contains("dynamic_code"));
2351 assert!(rendered.contains("1234"));
2352 assert!(rendered.contains("0x00000005"));
2353 }
2354}