diff --git a/Cargo.lock b/Cargo.lock index 04eed17..2c40b27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "atty" version = "0.2.14" @@ -19,9 +21,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cfg-if" @@ -30,27 +32,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "chrono" -version = "0.4.19" +name = "clap" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "d17bf219fcd37199b9a29e00ba65dfb8cd5b2688b7297ec14ff829c40ac50ca9" dependencies = [ - "libc", - "num-integer", - "num-traits", - "time", - "winapi", + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", ] [[package]] -name = "clap" -version = "2.33.3" +name = "clap_derive" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "e1b9752c030a14235a0bd5ef3ad60a1dcac8468c30921327fc8af36b20c790b9" dependencies = [ - "bitflags", - "textwrap", - "unicode-width", + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -64,6 +72,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "eyre" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "221239d1d5ea86bf5d6f91c9d6bc3646ffe471b08ff9b0f91c44f115ac969d2b" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fern" version = "0.6.0" @@ -74,24 +92,52 @@ dependencies = [ "log", ] +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + [[package]] name = "heck" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "lazy_static" version = "1.4.0" @@ -100,9 +146,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.91" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "log" @@ -113,6 +159,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + [[package]] name = "ntapi" version = "0.3.6" @@ -123,51 +175,20 @@ dependencies = [ ] [[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "paw" -version = "1.0.0" +name = "once_cell" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" -dependencies = [ - "paw-attributes", - "paw-raw", -] +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] -name = "paw-attributes" -version = "1.0.2" +name = "os_str_bytes" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" dependencies = [ - "proc-macro2", - "quote", - "syn", + "memchr", ] -[[package]] -name = "paw-raw" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -194,94 +215,101 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d" dependencies = [ "proc-macro2", ] [[package]] name = "serde" -version = "1.0.125" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a" [[package]] -name = "structopt" -version = "0.3.21" +name = "strsim" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" -dependencies = [ - "clap", - "lazy_static", - "paw", - "structopt-derive", -] +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] -name = "structopt-derive" -version = "0.4.14" +name = "syn" +version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b" dependencies = [ - "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "unicode-xid", ] [[package]] -name = "syn" -version = "1.0.64" +name = "termcolor" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "winapi-util", ] [[package]] name = "textwrap" -version = "0.11.0" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" + +[[package]] +name = "thiserror" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ - "unicode-width", + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "time" -version = "0.1.44" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" dependencies = [ + "itoa", "libc", - "wasi", - "winapi", ] [[package]] name = "timerset" -version = "0.4.0" +version = "0.4.1" dependencies = [ - "chrono", + "clap", + "eyre", "fern", "log", "ntapi", - "paw", - "structopt", + "thiserror", + "time", "winapi", "winreg", "winres", @@ -298,33 +326,21 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" - -[[package]] -name = "unicode-width" -version = "0.1.8" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "version_check" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "winapi" @@ -342,6 +358,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -350,18 +375,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winreg" -version = "0.8.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d107f8c6e916235c4c01cabb3e8acf7bea8ef6a63ca2e7fa0527c049badfc48c" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] [[package]] name = "winres" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4fb510bbfe5b8992ff15f77a2e6fe6cf062878f0eda00c0f44963a807ca5dc" +checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" dependencies = [ "toml", ] diff --git a/Cargo.toml b/Cargo.toml index bd698b4..c53110b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "timerset" -version = "0.4.0" +version = "0.4.1" authors = ["Mathieu Amiot "] -edition = "2018" +edition = "2021" [package.metadata.winres] OriginalFileName = "TimerSet.exe" @@ -14,15 +14,12 @@ default = [] [dependencies] log = "0.4" -paw = "1.0" -winreg = "0.8" fern = { version = "0.6", features = ["colored"] } -chrono = "0.4" - -[dependencies.structopt] -version = "0.3" -default-features = false -features = ["paw"] +clap = { version = "3.0", features = ["derive"] } +thiserror = "1.0" +eyre = "0.6" +time = { version = "0.3", features = ["formatting"] } +winreg = "0.10" [dependencies.ntapi] version = "0.3" diff --git a/README.md b/README.md index 628e940..5dcb67c 100644 --- a/README.md +++ b/README.md @@ -13,39 +13,68 @@ The program should be run from an elevated (ie. cmd => run as administrator) ter Obviously, it only works on Windows. Confirmed to work on Windows 10 2004, but should run on pretty much any version of Windows since the used APIs are so old. ```text -timerset 0.3.0 +timerset 0.4.1 Mathieu Amiot -TimerSet allows you to change your NT Kernel system timer -Also allows you to monitor Windows Standby List and clean it up when needed +TimerSet allows you to change your NT Kernel system timer Also allows you to monitor Windows Standby +List and clean it up when needed USAGE: - timerset.exe [FLAGS] [OPTIONS] - -FLAGS: - --islc Enables Windows Standby List periodic cleaning. It is akin to how ISLC by Wagnard works. Please - note that when enabling this, the program will **NOT** be idle at all times and will periodically - poll the system memory to check whether a cleanup is needed or not - -h, --help Prints help information - -i, --install Installs TimerSet to your system and runs it on startup - -u, --uninstall Uninstalls TimerSet from your system - -v, --values Prints the possible timer value range for your system. Please note that it can depend on many - factors such as HPET or dynamic/synthetic timers enabled or disabled - -V, --version Prints version information + timerset.exe [OPTIONS] OPTIONS: - --islc-timer - Standby List periodic cleaning poll interval. Defaults to 10 seconds which should be enough for most systems - without impacting performance [default: 10] - --cscm - Cached memory threshold where the Windows Standby List will be cleared (in MB) Defaults to 1024MB (1GB) + --cscm + Cached memory threshold where the Windows Standby List will be cleared (in MB) Defaults + to 1024MB (1GB) + [default: 1024] - --csfm - Free memory threshold where the Windows Standby List will be cleared (in MB) Defaults to 1024MB (1GB) + + --csfm + Free memory threshold where the Windows Standby List will be cleared (in MB) Defaults to + 1024MB (1GB) + [default: 1024] - -t, --timer - Allows to set a custom timer value in μs. Will be clamped between the bounds of allowed timer values. Also - note that sometimes, setting high timer values are rejected by the system and will be lowered down depending - on which clock source your system is using (TSC tends to lower values by 5μs, HPET does not for instance) + + -h, --help + Print help information + + -i, --install + Installs TimerSet to your system and runs it on startup + + --islc + Enables Windows Standby List periodic cleaning. It is akin to how ISLC by Wagnard works + + --islc-timer + Standby List anti-kernel DOS throttle timer It exists because + CreateMemoryResourceNotification can trigger LowMemoryResourceNotifications thousands of + times per second when they happen (i.e. every system page allocation in a high memory + pressure situation, often 4KB) resulting in the memory list cleaning paralyzing the + system with thousands of tries per second + + Defaults to 10 seconds which should be enough for most systems without impacting + performance. + + [default: 10] + + -p, --pretend + Shows the actions taken but do not modify anything on the system; Also known as a dry + run + + -t, --timer + Allows to set a custom timer value in μs. Will be clamped between the bounds of allowed + timer values. Also note that sometimes, setting high timer values are rejected by the + system and will be lowered down depending on which clock source your system is using + (TSC tends to lower values by ~5μs, HPET does not for instance) + + -u, --uninstall + Uninstalls TimerSet from your system + + -v, --values + Prints the possible timer value range for your system. Please note that it can depend on + many factors such as HPET or dynamic/synthetic timers enabled or disabled + + -V, --version + Print version information + ``` ## Examples diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..278af79 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,23 @@ +#[derive(Debug, thiserror::Error)] +pub enum TimersetError { + #[error(transparent)] + TaskSchedulerError(#[from] crate::task_scheduler::TaskSchedulerError), + #[error(transparent)] + EnvVarError(#[from] std::env::VarError), + #[error(transparent)] + SetLoggerError(#[from] log::SetLoggerError), + #[error(transparent)] + IoError(#[from] std::io::Error), + #[error("WindowsError: {0}")] + WindowsError(std::io::Error), + #[error(transparent)] + Other(#[from] eyre::Report), +} + +impl TimersetError { + pub fn windows_error() -> Self { + Self::WindowsError(std::io::Error::last_os_error()) + } +} + +pub type TimersetResult = Result; diff --git a/src/install.rs b/src/install.rs index 07b5b80..fee4df9 100644 --- a/src/install.rs +++ b/src/install.rs @@ -1,13 +1,9 @@ -use crate::task_scheduler::{ExecAction, WindowsTaskScheduler}; +use crate::task_scheduler::{ExecAction, RegisterTaskDefinitionArgs, WindowsTaskScheduler}; +use crate::TimersetResult; use crate::{ task_scheduler::{ - LogonTrigger, - TaskActionType, - TaskCompatibility, - TaskInstancesPolicy, - TaskTriggerType, - TaskLogonType, - TaskRunlevel + LogonTrigger, TaskActionType, TaskCompatibility, TaskInstancesPolicy, TaskLogonType, + TaskRunlevel, TaskTriggerType, }, utils::StartArgs, }; @@ -19,12 +15,12 @@ const TASK_NAME: &str = "Start TimerSet [DEV]"; #[cfg(not(debug))] const TASK_NAME: &str = "Start TimerSet"; -pub fn install(args: &crate::Opts) -> std::io::Result<()> { +pub fn install(args: &crate::Opts) -> crate::TimersetResult<()> { // Copy exe to %ProgramFiles%\TimerSet\TimerSet.exe let current_exe_path = std::env::current_exe()?; debug!("Current exe path: {:?}", current_exe_path); - let mut dest_path: std::path::PathBuf = std::env::var("PROGRAMFILES").unwrap().into(); + let mut dest_path: std::path::PathBuf = std::env::var("PROGRAMFILES")?.into(); dest_path.push("TimerSet"); info!("Installing TimerSet at: {:?}", dest_path); debug!("Creating app folder"); @@ -60,7 +56,8 @@ pub fn install(args: &crate::Opts) -> std::io::Result<()> { let task_reginfo = task.registration_info()?; task_reginfo.set_author("Mathieu \"OtaK_\" Amiot")?; - task_reginfo.set_description("Start TimerSet at logon of any user with admin permissions")?; + task_reginfo + .set_description("Start TimerSet at logon of any user with admin permissions")?; let task_settings = task.settings()?; task_settings.set_start_when_available(true)?; @@ -87,15 +84,15 @@ pub fn install(args: &crate::Opts) -> std::io::Result<()> { exec_action.set_working_directory(start_location)?; } - let _ = folder.register_task_definition( - TASK_NAME, - task, - TASK_CREATE_OR_UPDATE as _, - None, - None, - TaskLogonType::InteractiveToken, - None, - )?; + let _ = folder.register_task_definition(RegisterTaskDefinitionArgs { + task_name: TASK_NAME, + task_definition: task, + flags: TASK_CREATE_OR_UPDATE as _, + user_id: None, + password: None, + logon_type: TaskLogonType::InteractiveToken, + sddl: None, + })?; } info!("Installation complete"); @@ -103,7 +100,7 @@ pub fn install(args: &crate::Opts) -> std::io::Result<()> { Ok(()) } -pub fn uninstall(args: &crate::Opts) -> std::io::Result<()> { +pub fn uninstall(args: &crate::Opts) -> TimersetResult<()> { let scheduler = WindowsTaskScheduler::new()?; scheduler.connect()?; @@ -113,7 +110,7 @@ pub fn uninstall(args: &crate::Opts) -> std::io::Result<()> { } // Delete files - let mut dest_path: std::path::PathBuf = std::env::var("PROGRAMFILES").unwrap().into(); + let mut dest_path: std::path::PathBuf = std::env::var("PROGRAMFILES")?.into(); dest_path.push("TimerSet"); debug!("Installation path to be removed: {:?}", dest_path); if !args.pretend { diff --git a/src/logger.rs b/src/logger.rs index 64209b6..017c8c1 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -7,27 +7,26 @@ pub struct Logger { impl Logger { pub fn new() -> Self { - Self { - has_init: false, - } + Self { has_init: false } } - pub fn init(&mut self) { + pub fn init(&mut self) -> crate::TimersetResult<()> { if self.has_init { - return; + return Ok(()); } fern::Dispatch::new() - .chain(stdout()) - .chain(filelog()) - .apply() - .unwrap(); + .chain(stdout()?) + .chain(filelog()?) + .apply()?; self.has_init = true; + + Ok(()) } } -fn stdout() -> fern::Dispatch { +fn stdout() -> crate::TimersetResult { let colors = ColoredLevelConfig::new() .error(Color::Red) .warn(Color::Yellow) @@ -36,33 +35,46 @@ fn stdout() -> fern::Dispatch { .trace(Color::BrightBlack) .info(Color::Green); - fern::Dispatch::new() + let time_format = time::format_description::well_known::Rfc3339; + + let dispatcher = fern::Dispatch::new() .format(move |out, message, record| { out.finish(format_args!( - "[{target}] {level} > {message}", - level = colors.color(record.level()), + "[{time}][{target}] {level} > {message}", + time = time::OffsetDateTime::now_utc() + .format(&time_format) + .unwrap(), target = record.target(), + level = colors.color(record.level()), message = message, )) }) .level(log::LevelFilter::Info) - .chain(std::io::stdout()) + .chain(std::io::stdout()); + + Ok(dispatcher) } -fn filelog() -> fern::Dispatch { - let mut logpath = std::env::current_exe().unwrap(); +fn filelog() -> crate::TimersetResult { + let mut logpath = std::env::current_exe()?; let _ = logpath.set_extension("log"); - fern::Dispatch::new() - .format(|out, message, record| { + let time_format = time::format_description::well_known::Rfc3339; + + let dispatcher = fern::Dispatch::new() + .format(move |out, message, record| { out.finish(format_args!( - "[{}][{}][{}] > {}", - chrono::Local::now().format("%Y-%m-%dT%H:%M:%S"), - record.level(), - record.target(), - message, + "[{time}][{level}][{target}] > {message}", + time = time::OffsetDateTime::now_utc() + .format(&time_format) + .unwrap(), + level = record.level(), + target = record.target(), + message = message, )) }) .level(log::LevelFilter::Debug) - .chain(fern::log_file(logpath).unwrap()) + .chain(fern::log_file(logpath)?); + + Ok(dispatcher) } diff --git a/src/main.rs b/src/main.rs index dc90ea8..c25ce81 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,61 +7,65 @@ use log::{error, info}; mod utils; +mod error; mod install; +mod logger; mod macros; mod standby; mod task_scheduler; mod timer; -mod logger; +pub use self::error::*; -#[derive(Debug, structopt::StructOpt)] -#[structopt(author = "Mathieu Amiot ")] /// TimerSet allows you to change your NT Kernel system timer /// Also allows you to monitor Windows Standby List and clean it up when needed +#[derive(Debug, clap::Parser)] +#[clap(about, version, author)] pub struct Opts { - #[structopt(short, long)] /// Shows the actions taken but do not modify anything on the system; Also known as a dry run. + #[clap(short, long)] pretend: bool, - #[structopt(short, long)] /// Installs TimerSet to your system and runs it on startup + #[clap(short, long)] install: bool, - #[structopt(short, long)] /// Uninstalls TimerSet from your system + #[clap(short, long)] uninstall: bool, - #[structopt(short, long)] /// Allows to set a custom timer value in μs. Will be clamped between the bounds of allowed timer values. /// Also note that sometimes, setting high timer values are rejected by the system and will be lowered down depending - /// on which clock source your system is using (TSC tends to lower values by 5μs, HPET does not for instance) + /// on which clock source your system is using (TSC tends to lower values by ~5μs, HPET does not for instance) + #[clap(short, long)] timer: Option, - #[structopt(long = "islc")] /// Enables Windows Standby List periodic cleaning. /// It is akin to how ISLC by Wagnard works. - /// Please note that when enabling this, the program will **NOT** be idle at all times and will periodically - /// poll the system memory to check whether a cleanup is needed or not. + #[clap(long = "islc")] clean_standby_list: bool, - #[structopt(long = "islc-timer", default_value = "10")] - /// Standby List periodic cleaning poll interval. + /// Standby List anti-kernel DOS throttle timer + /// It exists because CreateMemoryResourceNotification can trigger LowMemoryResourceNotifications + /// thousands of times per second when they happen (i.e. every system page allocation in a high memory pressure situation, often 4KB) + /// resulting in the memory list cleaning paralyzing the system with thousands of tries per second + /// /// Defaults to 10 seconds which should be enough for most systems without impacting performance. + #[clap(long = "islc-timer", default_value = "10")] clean_standby_list_poll_freq: u64, - #[structopt(long = "cscm", default_value = "1024")] /// Cached memory threshold where the Windows Standby List will be cleared (in MB) /// Defaults to 1024MB (1GB) + #[clap(long = "cscm", default_value = "1024")] clear_standby_cached_mem: u32, - #[structopt(long = "csfm", default_value = "1024")] /// Free memory threshold where the Windows Standby List will be cleared (in MB) /// Defaults to 1024MB (1GB) + #[clap(long = "csfm", default_value = "1024")] clear_standby_free_mem: u32, - #[structopt(short, long)] /// Prints the possible timer value range for your system. /// Please note that it can depend on many factors such as HPET or dynamic/synthetic timers enabled or disabled. + #[clap(short, long)] values: bool, } @@ -71,10 +75,12 @@ fn main() { } #[cfg(windows)] -#[paw::main] -fn main(mut args: Opts) -> std::io::Result<()> { +fn main() -> TimersetResult<()> { let mut logger = logger::Logger::new(); - logger.init(); + logger.init()?; + + use clap::Parser as _; + let mut args = Opts::parse(); if args.pretend { info!("--pretend enabled, no action will be taken on the system") diff --git a/src/standby.rs b/src/standby.rs index 6ad8231..b68beb1 100644 --- a/src/standby.rs +++ b/src/standby.rs @@ -85,7 +85,7 @@ impl StandbyListCleaner { self } - fn setup_cmrn(&mut self) -> std::io::Result<()> { + fn setup_cmrn(&mut self) -> crate::TimersetResult<()> { let mm_reg = winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE) .open_subkey_with_flags( "System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", @@ -105,7 +105,7 @@ impl StandbyListCleaner { Ok(()) } - fn cleanup_cmrn(&mut self) -> std::io::Result<()> { + fn cleanup_cmrn(&mut self) -> crate::TimersetResult<()> { debug!("Cleaning up memory handle"); unsafe { CloseHandle(self.memory_hwnd) }; @@ -119,7 +119,7 @@ impl StandbyListCleaner { Ok(()) } - fn upgrade_security_token(&self) -> std::io::Result<()> { + fn upgrade_security_token(&self) -> crate::TimersetResult<()> { debug!("Beginning to upgrade security token..."); let process_hwnd = unsafe { GetCurrentProcess() }; let mut token_hwnd = winapi::shared::ntdef::NULL; @@ -181,7 +181,7 @@ impl StandbyListCleaner { /// Starts the monitoring loop. /// Note that this is a blocking function that will not exit unless there's an error. - pub fn monitor_and_clean(&mut self) -> std::io::Result<()> { + pub fn monitor_and_clean(&mut self) -> crate::TimersetResult<()> { self.upgrade_security_token()?; self.setup_cmrn()?; @@ -259,7 +259,7 @@ impl StandbyListCleaner { } } - fn wait_on_cmrn(&mut self) -> std::io::Result<()> { + fn wait_on_cmrn(&mut self) -> crate::TimersetResult<()> { if let Some(elapsed) = self .last_memory_wait .as_ref() @@ -279,7 +279,7 @@ impl StandbyListCleaner { let result = unsafe { WaitForSingleObject(self.memory_hwnd, winapi::um::winbase::INFINITE) }; match result { - WAIT_FAILED => Err(std::io::Error::last_os_error()), + WAIT_FAILED => Err(crate::TimersetError::windows_error()), WAIT_OBJECT_0 | WAIT_ABANDONED => Ok(()), _ => unreachable!(), } diff --git a/src/task_scheduler/action.rs b/src/task_scheduler/action.rs index 6c8387c..99081e1 100644 --- a/src/task_scheduler/action.rs +++ b/src/task_scheduler/action.rs @@ -44,12 +44,12 @@ impl Into<*mut IActionCollection> for ActionCollection { #[allow(dead_code)] impl ActionCollection { - pub fn clear(&self) -> std::io::Result<()> { + pub fn clear(&self) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).Clear())?; Ok(()) } - pub fn count(&self) -> std::io::Result { + pub fn count(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut count = 0; crate::w32_ok!((*self.0).get_Count(&mut count))?; Ok(count as usize) @@ -68,7 +68,7 @@ impl ActionCollection { variant } - pub fn remove(&self, index: usize) -> std::io::Result<()> { + pub fn remove(&self, index: usize) -> crate::task_scheduler::TaskSchedulerResult<()> { let count = self.count()?; if index == 0 || index > count { return Err(std::io::ErrorKind::InvalidInput.into()); @@ -79,7 +79,7 @@ impl ActionCollection { Ok(()) } - pub fn get(&self, index: usize) -> std::io::Result { + pub fn get(&self, index: usize) -> crate::task_scheduler::TaskSchedulerResult { let count = self.count()?; if index == 0 || index > count { return Err(std::io::ErrorKind::InvalidInput.into()); @@ -90,7 +90,10 @@ impl ActionCollection { Ok(action.into()) } - pub fn create(&self, trigger_type: TaskActionType) -> std::io::Result { + pub fn create( + &self, + trigger_type: TaskActionType, + ) -> crate::task_scheduler::TaskSchedulerResult { let mut trigger: *mut IAction = std::ptr::null_mut(); crate::w32_ok!((*self.0).Create(trigger_type as _, &mut trigger))?; Ok(trigger.into()) @@ -126,18 +129,18 @@ impl std::ops::DerefMut for Action { #[allow(dead_code)] impl Action { - pub fn id(&self) -> std::io::Result { + pub fn id(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!(self.get_Id(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_id>(&self, id: S) -> std::io::Result<()> { + pub fn set_id>(&self, id: S) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!(self.put_Id(crate::wstr!(id.as_ref())))?; Ok(()) } - pub fn get_type(&self) -> std::io::Result { + pub fn get_type(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut action_type = 0u32; crate::w32_ok!(self.get_Type(&mut action_type))?; Ok(action_type.into()) @@ -147,7 +150,7 @@ impl Action { crate::generate_action_type!(TaskActionType::Exec, IExecAction, ExecAction); pub trait SubAction { - fn new(action: Action) -> std::io::Result + fn new(action: Action) -> crate::task_scheduler::TaskSchedulerResult where Self: Sized; fn uuid() -> GUID; @@ -177,7 +180,7 @@ macro_rules! generate_action_type { } impl SubAction for $newt { - fn new(action: Action) -> std::io::Result { + fn new(action: Action) -> crate::task_scheduler::TaskSchedulerResult { let mut ret_action: *mut $target = std::ptr::null_mut(); use winapi::Interface as _; crate::w32_ok!(action @@ -206,29 +209,35 @@ macro_rules! generate_action_type { #[allow(dead_code)] impl ExecAction { - pub fn path(&self) -> std::io::Result { + pub fn path(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut delay_bstr: BSTR = std::ptr::null_mut(); crate::w32_ok!(self.get_Path(&mut delay_bstr))?; super::bstr_to_string(delay_bstr) } - pub fn set_path>(&self, path: S) -> std::io::Result<()> { + pub fn set_path>( + &self, + path: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!(self.put_Path(crate::wstr!(path.as_ref())))?; Ok(()) } - pub fn arguments(&self) -> std::io::Result { + pub fn arguments(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut delay_bstr: BSTR = std::ptr::null_mut(); crate::w32_ok!(self.get_Arguments(&mut delay_bstr))?; super::bstr_to_string(delay_bstr) } - pub fn set_arguments>(&self, arguments: S) -> std::io::Result<()> { + pub fn set_arguments>( + &self, + arguments: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!(self.put_Arguments(crate::wstr!(arguments.as_ref())))?; Ok(()) } - pub fn working_directory(&self) -> std::io::Result { + pub fn working_directory(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut delay_bstr: BSTR = std::ptr::null_mut(); crate::w32_ok!(self.get_WorkingDirectory(&mut delay_bstr))?; super::bstr_to_string(delay_bstr) @@ -237,7 +246,7 @@ impl ExecAction { pub fn set_working_directory>( &self, working_directory: S, - ) -> std::io::Result<()> { + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!(self.put_WorkingDirectory(crate::wstr!(working_directory.as_ref())))?; Ok(()) } diff --git a/src/task_scheduler/error.rs b/src/task_scheduler/error.rs new file mode 100644 index 0000000..bfa5098 --- /dev/null +++ b/src/task_scheduler/error.rs @@ -0,0 +1,15 @@ +#[derive(Debug, thiserror::Error)] +pub enum TaskSchedulerError { + #[error(transparent)] + IoError(#[from] std::io::Error), + #[error(transparent)] + Other(#[from] eyre::Report), +} + +impl From for TaskSchedulerError { + fn from(ek: std::io::ErrorKind) -> Self { + std::io::Error::from(ek).into() + } +} + +pub type TaskSchedulerResult = Result; diff --git a/src/task_scheduler/mod.rs b/src/task_scheduler/mod.rs index 98987f5..211fdf1 100644 --- a/src/task_scheduler/mod.rs +++ b/src/task_scheduler/mod.rs @@ -1,3 +1,8 @@ +#![allow(clippy::from_over_into)] + +mod error; +pub use error::*; + mod task_folder; pub use task_folder::*; @@ -81,11 +86,13 @@ impl> std::ops::DerefMut for IUnknownWrapper { } #[inline(always)] -pub(crate) fn bstr_to_string(bstr: winapi::shared::wtypes::BSTR) -> std::io::Result { +pub(crate) fn bstr_to_string( + bstr: winapi::shared::wtypes::BSTR, +) -> crate::task_scheduler::TaskSchedulerResult { let raw_str = unsafe { std::slice::from_raw_parts(bstr, *bstr as _) }; use std::os::windows::ffi::OsStringExt as _; let os_str = std::ffi::OsString::from_wide(raw_str); - os_str + Ok(os_str .into_string() - .map_err(|_| std::io::Error::from(std::io::ErrorKind::InvalidData)) + .map_err(|_| std::io::Error::from(std::io::ErrorKind::InvalidData))?) } diff --git a/src/task_scheduler/principal.rs b/src/task_scheduler/principal.rs index d6d3826..d69d306 100644 --- a/src/task_scheduler/principal.rs +++ b/src/task_scheduler/principal.rs @@ -65,68 +65,83 @@ impl Into<*mut IPrincipal> for Principal { #[allow(dead_code)] impl Principal { - pub fn id(&self) -> std::io::Result { + pub fn id(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Id(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_id>(&self, id: S) -> std::io::Result<()> { + pub fn set_id>(&self, id: S) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Id(crate::wstr!(id.as_ref())))?; Ok(()) } - pub fn display_name(&self) -> std::io::Result { + pub fn display_name(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_DisplayName(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_display_name>(&self, display_name: S) -> std::io::Result<()> { + pub fn set_display_name>( + &self, + display_name: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_DisplayName(crate::wstr!(display_name.as_ref())))?; Ok(()) } - pub fn user_id(&self) -> std::io::Result { + pub fn user_id(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_UserId(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_user_id>(&self, user_id: S) -> std::io::Result<()> { + pub fn set_user_id>( + &self, + user_id: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_DisplayName(crate::wstr!(user_id.as_ref())))?; Ok(()) } - pub fn group_id(&self) -> std::io::Result { + pub fn group_id(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_GroupId(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_group_id>(&self, group_id: S) -> std::io::Result<()> { + pub fn set_group_id>( + &self, + group_id: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_DisplayName(crate::wstr!(group_id.as_ref())))?; Ok(()) } - pub fn logon_type(&self) -> std::io::Result { + pub fn logon_type(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: u32 = 0; crate::w32_ok!((*self.0).get_LogonType(&mut ret))?; Ok(ret.into()) } - pub fn set_logon_type(&self, logon_type: TaskLogonType) -> std::io::Result<()> { + pub fn set_logon_type( + &self, + logon_type: TaskLogonType, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_LogonType(logon_type as u32))?; Ok(()) } - pub fn runlevel(&self) -> std::io::Result { + pub fn runlevel(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: u32 = 0; crate::w32_ok!((*self.0).get_RunLevel(&mut ret))?; Ok(ret.into()) } - pub fn set_runlevel(&self, runlevel: TaskRunlevel) -> std::io::Result<()> { + pub fn set_runlevel( + &self, + runlevel: TaskRunlevel, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_LogonType(runlevel as u32))?; Ok(()) } diff --git a/src/task_scheduler/task_definition.rs b/src/task_scheduler/task_definition.rs index dc199cf..bfc7879 100644 --- a/src/task_scheduler/task_definition.rs +++ b/src/task_scheduler/task_definition.rs @@ -1,6 +1,15 @@ -use winapi::{shared::wtypes::BSTR, um::taskschd::{IActionCollection, IPrincipal, IRegistrationInfo, ITaskDefinition, ITaskSettings, ITriggerCollection}}; - -use super::{action::ActionCollection, IUnknownWrapper, Principal, TaskRegistrationInfo, TaskSettings, TriggerCollection}; +use winapi::{ + shared::wtypes::BSTR, + um::taskschd::{ + IActionCollection, IPrincipal, IRegistrationInfo, ITaskDefinition, ITaskSettings, + ITriggerCollection, + }, +}; + +use super::{ + action::ActionCollection, IUnknownWrapper, Principal, TaskRegistrationInfo, TaskSettings, + TriggerCollection, +}; pub struct TaskDefinition(IUnknownWrapper); impl From<*mut ITaskDefinition> for TaskDefinition { @@ -17,53 +26,67 @@ impl Into<*mut ITaskDefinition> for TaskDefinition { #[allow(dead_code)] impl TaskDefinition { - pub fn xml_text(&self) -> std::io::Result { + pub fn xml_text(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!(self.0.get_XmlText(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_xml_text>(&self, xml: S) -> std::io::Result<()> { + pub fn set_xml_text>( + &self, + xml: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!(self.0.put_XmlText(crate::wstr!(xml.as_ref())))?; Ok(()) } - pub fn data(&self) -> std::io::Result { + pub fn data(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!(self.0.get_Data(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_data>(&self, data: S) -> std::io::Result<()> { + pub fn set_data>( + &self, + data: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!(self.0.put_Data(crate::wstr!(data.as_ref())))?; Ok(()) } - pub fn principal(&self) -> std::io::Result { + pub fn principal(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut principal: *mut IPrincipal = std::ptr::null_mut(); crate::w32_ok!(self.0.get_Principal(&mut principal as *mut *mut _ as _))?; Ok(principal.into()) } - pub fn set_principal(&self, principal: Principal) -> std::io::Result<()> { + pub fn set_principal( + &self, + principal: Principal, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { let ptr: *mut IPrincipal = principal.into(); crate::w32_ok!(self.0.put_Principal(ptr))?; Ok(()) } - pub fn actions(&self) -> std::io::Result { + pub fn actions(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut actions: *mut IActionCollection = std::ptr::null_mut(); crate::w32_ok!(self.0.get_Actions(&mut actions as *mut *mut _ as _))?; Ok(actions.into()) } - pub fn set_actions(&self, actions: ActionCollection) -> std::io::Result<()> { + pub fn set_actions( + &self, + actions: ActionCollection, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { let ptr: *mut IActionCollection = actions.into(); crate::w32_ok!(self.0.put_Actions(ptr))?; Ok(()) } - pub fn registration_info(&self) -> std::io::Result { + pub fn registration_info( + &self, + ) -> crate::task_scheduler::TaskSchedulerResult { let mut registration_info: *mut IRegistrationInfo = std::ptr::null_mut(); crate::w32_ok!(self .0 @@ -74,31 +97,37 @@ impl TaskDefinition { pub fn set_registration_info( &self, registration_info: TaskRegistrationInfo, - ) -> std::io::Result<()> { + ) -> crate::task_scheduler::TaskSchedulerResult<()> { let ptr: *mut IRegistrationInfo = registration_info.into(); crate::w32_ok!(self.0.put_RegistrationInfo(ptr))?; Ok(()) } - pub fn settings(&self) -> std::io::Result { + pub fn settings(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut settings: *mut ITaskSettings = std::ptr::null_mut(); crate::w32_ok!(self.0.get_Settings(&mut settings as *mut *mut _ as _))?; Ok(settings.into()) } - pub fn set_settings(&self, settings: TaskSettings) -> std::io::Result<()> { + pub fn set_settings( + &self, + settings: TaskSettings, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { let ptr: *mut ITaskSettings = settings.into(); crate::w32_ok!(self.0.put_Settings(ptr))?; Ok(()) } - pub fn triggers(&self) -> std::io::Result { + pub fn triggers(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut triggers: *mut ITriggerCollection = std::ptr::null_mut(); crate::w32_ok!(self.0.get_Triggers(&mut triggers as *mut *mut _ as _))?; Ok(triggers.into()) } - pub fn set_triggers(&self, triggers: TriggerCollection) -> std::io::Result<()> { + pub fn set_triggers( + &self, + triggers: TriggerCollection, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { let ptr: *mut ITriggerCollection = triggers.into(); crate::w32_ok!(self.0.put_Triggers(ptr))?; Ok(()) diff --git a/src/task_scheduler/task_folder.rs b/src/task_scheduler/task_folder.rs index 11d9da7..63c495d 100644 --- a/src/task_scheduler/task_folder.rs +++ b/src/task_scheduler/task_folder.rs @@ -1,4 +1,12 @@ -use winapi::{shared::{wtypes::BSTR, ntdef::NULL}, um::{taskschd::ITaskDefinition, oaidl::{VARIANT, VARIANTARG}, oleauto::VariantInit, taskschd::{IRegisteredTask, ITaskFolder, TASK_CREATION}}}; +use winapi::{ + shared::{ntdef::NULL, wtypes::BSTR}, + um::{ + oaidl::{VARIANT, VARIANTARG}, + oleauto::VariantInit, + taskschd::ITaskDefinition, + taskschd::{IRegisteredTask, ITaskFolder, TASK_CREATION}, + }, +}; use super::{IUnknownWrapper, RegisteredTask, TaskDefinition, TaskLogonType}; use log::debug; @@ -27,58 +35,88 @@ impl Into<*mut ITaskFolder> for TaskFolder { } } +pub struct RegisterTaskDefinitionArgs> { + pub task_name: S, + pub task_definition: TaskDefinition, + pub flags: TASK_CREATION, + pub user_id: Option, + pub password: Option, + pub logon_type: TaskLogonType, + pub sddl: Option, +} + #[allow(dead_code)] impl TaskFolder { - pub fn name(&self) -> std::io::Result { + pub fn name(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Name(&mut ret))?; super::bstr_to_string(ret) } - pub fn path(&self) -> std::io::Result { + pub fn path(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Path(&mut ret))?; super::bstr_to_string(ret) } - pub fn delete_folder>(&self, subfolder_name: S) -> std::io::Result<()> { - crate::w32_ok!((*self.0).DeleteFolder(crate::wstr!(subfolder_name.as_ref()), 0)) + pub fn delete_folder>( + &self, + subfolder_name: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { + Ok(crate::w32_ok!( + (*self.0).DeleteFolder(crate::wstr!(subfolder_name.as_ref()), 0) + )?) } - pub fn delete_task>(&self, task_name: S) -> std::io::Result<()> { - crate::w32_ok!((*self.0).DeleteTask(crate::wstr!(task_name.as_ref()), 0)) + pub fn delete_task>( + &self, + task_name: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { + Ok(crate::w32_ok!( + (*self.0).DeleteTask(crate::wstr!(task_name.as_ref()), 0) + )?) } pub fn register_task_definition>( &self, - task_name: S, - task_definition: TaskDefinition, - flags: TASK_CREATION, - user_id: Option, - password: Option, - logon_type: TaskLogonType, - sddl: Option, - ) -> std::io::Result { + args: RegisterTaskDefinitionArgs, + ) -> crate::task_scheduler::TaskSchedulerResult { + let RegisterTaskDefinitionArgs { + task_name, + task_definition, + flags, + user_id, + password, + logon_type, + sddl, + } = args; + let mut registered_task: *mut IRegisteredTask = NULL as _; let task_definition: *mut ITaskDefinition = task_definition.into(); - let uid = user_id.map(|uid| { - let uid_bstr = crate::wstr!(uid.as_ref()); - crate::bstr_variant!(uid_bstr) - }).unwrap_or_else(empty_variant); - - let password = password.map(|passwd| { - let pwd_bstr = crate::wstr!(passwd.as_ref()); - crate::bstr_variant!(pwd_bstr) - }).unwrap_or_else(empty_variant); - - let sddl = sddl.map(|sddl| { - let sddl_bstr = crate::wstr!(sddl.as_ref()); - crate::bstr_variant!(sddl_bstr) - }).unwrap_or_else(|| { - let empty = crate::wstr!(""); - crate::bstr_variant!(empty) - }); + let uid = user_id + .map(|uid| { + let uid_bstr = crate::wstr!(uid.as_ref()); + crate::bstr_variant!(uid_bstr) + }) + .unwrap_or_else(empty_variant); + + let password = password + .map(|passwd| { + let pwd_bstr = crate::wstr!(passwd.as_ref()); + crate::bstr_variant!(pwd_bstr) + }) + .unwrap_or_else(empty_variant); + + let sddl = sddl + .map(|sddl| { + let sddl_bstr = crate::wstr!(sddl.as_ref()); + crate::bstr_variant!(sddl_bstr) + }) + .unwrap_or_else(|| { + let empty = crate::wstr!(""); + crate::bstr_variant!(empty) + }); crate::w32_ok!(self.0.RegisterTaskDefinition( crate::wstr!(task_name.as_ref()), diff --git a/src/task_scheduler/task_registration_info.rs b/src/task_scheduler/task_registration_info.rs index 809eebc..09a1e40 100644 --- a/src/task_scheduler/task_registration_info.rs +++ b/src/task_scheduler/task_registration_info.rs @@ -18,90 +18,111 @@ impl Into<*mut IRegistrationInfo> for TaskRegistrationInfo { #[allow(dead_code)] impl TaskRegistrationInfo { - pub fn description(&self) -> std::io::Result { + pub fn description(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Description(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_description>(&self, description: S) -> std::io::Result<()> { + pub fn set_description>( + &self, + description: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Description(crate::wstr!(description.as_ref())))?; Ok(()) } - pub fn author(&self) -> std::io::Result { + pub fn author(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Author(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_author>(&self, author: S) -> std::io::Result<()> { + pub fn set_author>( + &self, + author: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Author(crate::wstr!(author.as_ref())))?; Ok(()) } - pub fn version(&self) -> std::io::Result { + pub fn version(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Version(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_version>(&self, version: S) -> std::io::Result<()> { + pub fn set_version>( + &self, + version: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Version(crate::wstr!(version.as_ref())))?; Ok(()) } - pub fn date(&self) -> std::io::Result { + pub fn date(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Date(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_date>(&self, date: S) -> std::io::Result<()> { + pub fn set_date>( + &self, + date: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Date(crate::wstr!(date.as_ref())))?; Ok(()) } - pub fn documentation(&self) -> std::io::Result { + pub fn documentation(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Documentation(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_documentation>(&self, documentation: S) -> std::io::Result<()> { + pub fn set_documentation>( + &self, + documentation: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Documentation(crate::wstr!(documentation.as_ref())))?; Ok(()) } - pub fn xml_text(&self) -> std::io::Result { + pub fn xml_text(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_XmlText(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_xml_text>(&self, xml_text: S) -> std::io::Result<()> { + pub fn set_xml_text>( + &self, + xml_text: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_XmlText(crate::wstr!(xml_text.as_ref())))?; Ok(()) } - pub fn uri(&self) -> std::io::Result { + pub fn uri(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_URI(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_uri>(&self, uri: S) -> std::io::Result<()> { + pub fn set_uri>(&self, uri: S) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_URI(crate::wstr!(uri.as_ref())))?; Ok(()) } - pub fn source(&self) -> std::io::Result { + pub fn source(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Source(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_source>(&self, source: S) -> std::io::Result<()> { + pub fn set_source>( + &self, + source: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Source(crate::wstr!(source.as_ref())))?; Ok(()) } diff --git a/src/task_scheduler/task_service.rs b/src/task_scheduler/task_service.rs index 9e7376f..218c632 100644 --- a/src/task_scheduler/task_service.rs +++ b/src/task_scheduler/task_service.rs @@ -37,7 +37,7 @@ pub struct WindowsTaskScheduler { #[allow(dead_code)] impl WindowsTaskScheduler { - pub fn new() -> std::io::Result { + pub fn new() -> crate::task_scheduler::TaskSchedulerResult { let mut ret = Self::default(); crate::w32_ok!(DEBUG CoInitializeEx( NULL, @@ -96,23 +96,23 @@ impl WindowsTaskScheduler { Ok(ret) } - pub fn connect(&self) -> std::io::Result<()> { + pub fn connect(&self) -> crate::task_scheduler::TaskSchedulerResult<()> { if let Some(service) = &self.service { debug!("Service: {:?}", service.lpVtbl); - crate::w32_ok!(DEBUG service.Connect( + Ok(crate::w32_ok!(DEBUG service.Connect( std::mem::zeroed(), std::mem::zeroed(), std::mem::zeroed(), std::mem::zeroed(), ), |result| { debug!("ITaskService::Connect() -> {:#X}", result); - }) + })?) } else { Err(std::io::ErrorKind::NotConnected.into()) } } - pub fn is_connected(&self) -> std::io::Result { + pub fn is_connected(&self) -> crate::task_scheduler::TaskSchedulerResult { if let Some(service) = &self.service { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!(service.get_Connected(&mut ret))?; @@ -122,7 +122,7 @@ impl WindowsTaskScheduler { } } - pub fn connected_domain(&self) -> std::io::Result { + pub fn connected_domain(&self) -> crate::task_scheduler::TaskSchedulerResult { if let Some(service) = &self.service { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!(service.get_ConnectedDomain(&mut ret))?; @@ -132,7 +132,7 @@ impl WindowsTaskScheduler { } } - pub fn connected_user(&self) -> std::io::Result { + pub fn connected_user(&self) -> crate::task_scheduler::TaskSchedulerResult { if let Some(service) = &self.service { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!(service.get_ConnectedUser(&mut ret))?; @@ -142,7 +142,7 @@ impl WindowsTaskScheduler { } } - pub fn target_server(&self) -> std::io::Result { + pub fn target_server(&self) -> crate::task_scheduler::TaskSchedulerResult { if let Some(service) = &self.service { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!(service.get_TargetServer(&mut ret))?; @@ -152,7 +152,10 @@ impl WindowsTaskScheduler { } } - pub fn folder>(&self, folder: T) -> std::io::Result { + pub fn folder>( + &self, + folder: T, + ) -> crate::task_scheduler::TaskSchedulerResult { if let Some(service) = &self.service { let mut task_folder: *mut ITaskFolder = std::ptr::null_mut(); let task_folder_name = crate::wstr!(folder.as_ref()); @@ -172,7 +175,7 @@ impl WindowsTaskScheduler { } } - pub fn new_task(&self) -> std::io::Result { + pub fn new_task(&self) -> crate::task_scheduler::TaskSchedulerResult { if let Some(service) = &self.service { let mut task_definition: *mut ITaskDefinition = std::ptr::null_mut(); crate::w32_ok!(service.NewTask(0, &mut task_definition))?; @@ -182,7 +185,7 @@ impl WindowsTaskScheduler { } } - pub fn highest_version(&self) -> std::io::Result { + pub fn highest_version(&self) -> crate::task_scheduler::TaskSchedulerResult { if let Some(service) = &self.service { let mut ret: u32 = 0; crate::w32_ok!(service.get_HighestVersion(&mut ret))?; diff --git a/src/task_scheduler/task_settings.rs b/src/task_scheduler/task_settings.rs index c4452ab..5a41500 100644 --- a/src/task_scheduler/task_settings.rs +++ b/src/task_scheduler/task_settings.rs @@ -68,13 +68,16 @@ impl Into<*mut ITaskSettings> for TaskSettings { #[allow(dead_code)] impl TaskSettings { - pub fn allow_demand_start(&self) -> std::io::Result { + pub fn allow_demand_start(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_AllowDemandStart(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_allow_demand_start(&self, allow: bool) -> std::io::Result<()> { + pub fn set_allow_demand_start( + &self, + allow: bool, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_AllowDemandStart(if allow { VARIANT_TRUE } else { @@ -83,13 +86,16 @@ impl TaskSettings { Ok(()) } - pub fn start_when_available(&self) -> std::io::Result { + pub fn start_when_available(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_StartWhenAvailable(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_start_when_available(&self, allow: bool) -> std::io::Result<()> { + pub fn set_start_when_available( + &self, + allow: bool, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_StartWhenAvailable(if allow { VARIANT_TRUE } else { @@ -98,13 +104,16 @@ impl TaskSettings { Ok(()) } - pub fn stop_if_going_into_batteries(&self) -> std::io::Result { + pub fn stop_if_going_into_batteries(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_StopIfGoingOnBatteries(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_stop_if_going_into_batteries(&self, allow: bool) -> std::io::Result<()> { + pub fn set_stop_if_going_into_batteries( + &self, + allow: bool, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_StopIfGoingOnBatteries(if allow { VARIANT_TRUE } else { @@ -113,13 +122,18 @@ impl TaskSettings { Ok(()) } - pub fn disallow_start_if_on_batteries(&self) -> std::io::Result { + pub fn disallow_start_if_on_batteries( + &self, + ) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_DisallowStartIfOnBatteries(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_disallow_start_if_on_batteries(&self, allow: bool) -> std::io::Result<()> { + pub fn set_disallow_start_if_on_batteries( + &self, + allow: bool, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_DisallowStartIfOnBatteries(if allow { VARIANT_TRUE } else { @@ -128,13 +142,16 @@ impl TaskSettings { Ok(()) } - pub fn allow_hard_terminate(&self) -> std::io::Result { + pub fn allow_hard_terminate(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_AllowHardTerminate(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_allow_hard_terminate(&self, allow: bool) -> std::io::Result<()> { + pub fn set_allow_hard_terminate( + &self, + allow: bool, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_AllowHardTerminate(if allow { VARIANT_TRUE } else { @@ -143,13 +160,18 @@ impl TaskSettings { Ok(()) } - pub fn run_only_if_network_available(&self) -> std::io::Result { + pub fn run_only_if_network_available( + &self, + ) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_RunOnlyIfNetworkAvailable(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_run_only_if_network_available(&self, allow: bool) -> std::io::Result<()> { + pub fn set_run_only_if_network_available( + &self, + allow: bool, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_RunOnlyIfNetworkAvailable(if allow { VARIANT_TRUE } else { @@ -158,35 +180,38 @@ impl TaskSettings { Ok(()) } - pub fn enabled(&self) -> std::io::Result { + pub fn enabled(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_Enabled(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_enabled(&self, allow: bool) -> std::io::Result<()> { + pub fn set_enabled(&self, allow: bool) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Enabled(if allow { VARIANT_TRUE } else { VARIANT_FALSE }))?; Ok(()) } - pub fn hidden(&self) -> std::io::Result { + pub fn hidden(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_Hidden(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_hidden(&self, allow: bool) -> std::io::Result<()> { + pub fn set_hidden(&self, allow: bool) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Hidden(if allow { VARIANT_TRUE } else { VARIANT_FALSE }))?; Ok(()) } - pub fn run_only_if_idle(&self) -> std::io::Result { + pub fn run_only_if_idle(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_RunOnlyIfIdle(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_run_only_if_idle(&self, allow: bool) -> std::io::Result<()> { + pub fn set_run_only_if_idle( + &self, + allow: bool, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_RunOnlyIfIdle(if allow { VARIANT_TRUE } else { @@ -195,68 +220,85 @@ impl TaskSettings { Ok(()) } - pub fn wake_to_run(&self) -> std::io::Result { + pub fn wake_to_run(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_WakeToRun(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_wake_to_run(&self, allow: bool) -> std::io::Result<()> { + pub fn set_wake_to_run(&self, allow: bool) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_WakeToRun(if allow { VARIANT_TRUE } else { VARIANT_FALSE }))?; Ok(()) } - pub fn execution_time_limit(&self) -> std::io::Result { + pub fn execution_time_limit(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_ExecutionTimeLimit(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_execution_time_limit>(&self, time_limit: S) -> std::io::Result<()> { + pub fn set_execution_time_limit>( + &self, + time_limit: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_ExecutionTimeLimit(crate::wstr!(time_limit.as_ref())))?; Ok(()) } - pub fn restart_interval(&self) -> std::io::Result { + pub fn restart_interval(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_RestartInterval(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_restart_interval>(&self, interval: S) -> std::io::Result<()> { + pub fn set_restart_interval>( + &self, + interval: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_RestartInterval(crate::wstr!(interval.as_ref())))?; Ok(()) } - pub fn xml_text(&self) -> std::io::Result { + pub fn xml_text(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_XmlText(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_xml_text>(&self, xml_text: S) -> std::io::Result<()> { + pub fn set_xml_text>( + &self, + xml_text: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_XmlText(crate::wstr!(xml_text.as_ref())))?; Ok(()) } - pub fn multiple_instances(&self) -> std::io::Result { + pub fn multiple_instances( + &self, + ) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: u32 = 0; crate::w32_ok!((*self.0).get_MultipleInstances(&mut ret))?; Ok(ret.into()) } - pub fn set_multiple_instances(&self, policy: TaskInstancesPolicy) -> std::io::Result<()> { + pub fn set_multiple_instances( + &self, + policy: TaskInstancesPolicy, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_MultipleInstances(policy as u32))?; Ok(()) } - pub fn compatibility(&self) -> std::io::Result { + pub fn compatibility(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: u32 = 0; crate::w32_ok!((*self.0).get_Compatibility(&mut ret))?; Ok(ret.into()) } - pub fn set_compatibility(&self, compat: TaskCompatibility) -> std::io::Result<()> { + pub fn set_compatibility( + &self, + compat: TaskCompatibility, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Compatibility(compat as u32))?; Ok(()) } diff --git a/src/task_scheduler/trigger.rs b/src/task_scheduler/trigger.rs index a9e8caa..6039d55 100644 --- a/src/task_scheduler/trigger.rs +++ b/src/task_scheduler/trigger.rs @@ -63,12 +63,12 @@ impl Into<*mut ITriggerCollection> for TriggerCollection { #[allow(dead_code)] impl TriggerCollection { - pub fn clear(&self) -> std::io::Result<()> { + pub fn clear(&self) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).Clear())?; Ok(()) } - pub fn count(&self) -> std::io::Result { + pub fn count(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut count = 0; crate::w32_ok!((*self.0).get_Count(&mut count))?; Ok(count as usize) @@ -87,7 +87,7 @@ impl TriggerCollection { variant } - pub fn remove(&self, index: usize) -> std::io::Result<()> { + pub fn remove(&self, index: usize) -> crate::task_scheduler::TaskSchedulerResult<()> { let count = self.count()?; if index == 0 || index > count { return Err(std::io::ErrorKind::InvalidInput.into()); @@ -98,7 +98,7 @@ impl TriggerCollection { Ok(()) } - pub fn get(&self, index: usize) -> std::io::Result { + pub fn get(&self, index: usize) -> crate::task_scheduler::TaskSchedulerResult { let count = self.count()?; if index == 0 || index > count { return Err(std::io::ErrorKind::InvalidInput.into()); @@ -109,7 +109,10 @@ impl TriggerCollection { Ok(trigger.into()) } - pub fn create(&self, trigger_type: TaskTriggerType) -> std::io::Result { + pub fn create( + &self, + trigger_type: TaskTriggerType, + ) -> crate::task_scheduler::TaskSchedulerResult { let mut trigger: *mut ITrigger = std::ptr::null_mut(); crate::w32_ok!((*self.0).Create(trigger_type as _, &mut trigger))?; Ok(trigger.into()) @@ -145,57 +148,66 @@ impl std::ops::DerefMut for Trigger { #[allow(dead_code)] impl Trigger { - pub fn id(&self) -> std::io::Result { + pub fn id(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_Id(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_id>(&self, id: S) -> std::io::Result<()> { + pub fn set_id>(&self, id: S) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Id(crate::wstr!(id.as_ref())))?; Ok(()) } - pub fn enabled(&self) -> std::io::Result { + pub fn enabled(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: VARIANT_BOOL = VARIANT_FALSE; crate::w32_ok!((*self.0).get_Enabled(&mut ret))?; Ok(ret == VARIANT_TRUE) } - pub fn set_enabled(&self, allow: bool) -> std::io::Result<()> { + pub fn set_enabled(&self, allow: bool) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_Enabled(if allow { VARIANT_TRUE } else { VARIANT_FALSE }))?; Ok(()) } - pub fn execution_time_limit(&self) -> std::io::Result { + pub fn execution_time_limit(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_ExecutionTimeLimit(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_execution_time_limit>(&self, time_limit: S) -> std::io::Result<()> { + pub fn set_execution_time_limit>( + &self, + time_limit: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_ExecutionTimeLimit(crate::wstr!(time_limit.as_ref())))?; Ok(()) } - pub fn start_boundary(&self) -> std::io::Result { + pub fn start_boundary(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_StartBoundary(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_start_boundary>(&self, boundary: S) -> std::io::Result<()> { + pub fn set_start_boundary>( + &self, + boundary: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_StartBoundary(crate::wstr!(boundary.as_ref())))?; Ok(()) } - pub fn end_boundary(&self) -> std::io::Result { + pub fn end_boundary(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut ret: BSTR = std::ptr::null_mut(); crate::w32_ok!((*self.0).get_EndBoundary(&mut ret))?; super::bstr_to_string(ret) } - pub fn set_end_boundary>(&self, boundary: S) -> std::io::Result<()> { + pub fn set_end_boundary>( + &self, + boundary: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!((*self.0).put_EndBoundary(crate::wstr!(boundary.as_ref())))?; Ok(()) } @@ -204,7 +216,7 @@ impl Trigger { crate::generate_trigger_type!(TaskTriggerType::Logon, ILogonTrigger, LogonTrigger); pub trait SubTrigger { - fn new(trigger: Trigger) -> std::io::Result + fn new(trigger: Trigger) -> crate::task_scheduler::TaskSchedulerResult where Self: Sized; fn uuid() -> GUID; @@ -234,7 +246,7 @@ macro_rules! generate_trigger_type { } impl SubTrigger for $newt { - fn new(trigger: Trigger) -> std::io::Result { + fn new(trigger: Trigger) -> crate::task_scheduler::TaskSchedulerResult { let mut ret_trigger: *mut $target = std::ptr::null_mut(); use winapi::Interface as _; crate::w32_ok!(trigger.QueryInterface( @@ -265,24 +277,30 @@ macro_rules! generate_trigger_type { #[allow(dead_code)] impl LogonTrigger { - pub fn delay(&self) -> std::io::Result { + pub fn delay(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut delay_bstr: BSTR = std::ptr::null_mut(); crate::w32_ok!(self.get_Delay(&mut delay_bstr))?; super::bstr_to_string(delay_bstr) } - pub fn set_delay>(&self, delay: S) -> std::io::Result<()> { + pub fn set_delay>( + &self, + delay: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!(self.put_Delay(crate::wstr!(delay.as_ref())))?; Ok(()) } - pub fn user_id(&self) -> std::io::Result { + pub fn user_id(&self) -> crate::task_scheduler::TaskSchedulerResult { let mut user_id_bstr: BSTR = std::ptr::null_mut(); crate::w32_ok!(self.get_UserId(&mut user_id_bstr))?; super::bstr_to_string(user_id_bstr) } - pub fn set_user_id>(&self, user_id: S) -> std::io::Result<()> { + pub fn set_user_id>( + &self, + user_id: S, + ) -> crate::task_scheduler::TaskSchedulerResult<()> { crate::w32_ok!(self.put_UserId(crate::wstr!(user_id.as_ref())))?; Ok(()) } diff --git a/src/timer.rs b/src/timer.rs index 628ad6d..5e9489a 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -16,7 +16,7 @@ impl std::fmt::Display for TimerResolutionInfo { } impl TimerResolutionInfo { - pub fn fetch() -> std::io::Result { + pub fn fetch() -> crate::TimersetResult { let mut min = 0u32; let mut max = 0u32; let mut cur = 0u32; @@ -28,7 +28,7 @@ impl TimerResolutionInfo { Ok(Self { min, max, cur }) } - pub fn apply_timer(&mut self, value: u32) -> std::io::Result<()> { + pub fn apply_timer(&mut self, value: u32) -> crate::TimersetResult<()> { let value = self.clamp_timer_value(value); // NtSetTimerResolution is an old, undocumented internal NT Kernel API that is very often used by media applications // to raise the kernel's timer and allow lower latencies and higher (= closer to real-time) throughput diff --git a/src/utils/start_args.rs b/src/utils/start_args.rs index 1c2c303..c1e8638 100644 --- a/src/utils/start_args.rs +++ b/src/utils/start_args.rs @@ -6,21 +6,23 @@ pub struct StartArgs { } impl StartArgs { - pub fn args_to_string(args: &Vec) -> String { + pub fn args_to_string(args: &[String]) -> String { args.iter() .enumerate() .fold(String::new(), |mut s, (i, arg)| { if i > 0 { s.push(' '); } - s.push_str(&arg); + s.push_str(arg); s }) } pub fn build_from_args(mut dest_path: std::path::PathBuf, args: &crate::Opts) -> Self { - let mut ret = Self::default(); - ret.target = format!("{}", dest_path.display()); + let mut ret = Self { + target: format!("{}", dest_path.display()), + ..Default::default() + }; if dest_path.pop() { ret.start_location = dest_path.to_str().map(Into::into); } diff --git a/src/utils/win_elevated.rs b/src/utils/win_elevated.rs index 1027104..807dbaf 100644 --- a/src/utils/win_elevated.rs +++ b/src/utils/win_elevated.rs @@ -1,7 +1,3 @@ -// Use std::io::Error::last_os_error for errors. -// NOTE: For this example I'm simple passing on the OS error. -// However, customising the error could provide more context -use std::io::Error; use std::ptr; use winapi::um::handleapi::CloseHandle; @@ -19,7 +15,7 @@ pub fn is_app_elevated() -> bool { /// /// This is unlikely to fail but if it does it's even more unlikely that you have admin permissions anyway. /// Therefore the public function above simply eats the error and returns a bool. -fn _is_app_elevated() -> Result { +fn _is_app_elevated() -> crate::TimersetResult { let token = QueryAccessToken::from_current_process()?; token.is_elevated() } @@ -27,7 +23,7 @@ fn _is_app_elevated() -> Result { /// A safe wrapper around querying Windows access tokens. pub struct QueryAccessToken(HANDLE); impl QueryAccessToken { - pub fn from_current_process() -> Result { + pub fn from_current_process() -> crate::TimersetResult { let mut handle: HANDLE = ptr::null_mut(); crate::w32_ok!(BOOL OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut handle))?; Ok(Self(handle)) @@ -35,7 +31,7 @@ impl QueryAccessToken { /// On success returns a bool indicating if the access token has elevated privilidges. /// Otherwise returns an OS error. - pub fn is_elevated(&self) -> Result { + pub fn is_elevated(&self) -> crate::TimersetResult { let mut elevation = TOKEN_ELEVATION::default(); let size = std::mem::size_of::() as u32; let mut ret_size = size;