1
0

write shit

This commit is contained in:
2025-10-09 15:32:22 +08:00
parent 682be6ab58
commit 2c8cb26ebf
4 changed files with 279 additions and 19 deletions

178
Cargo.lock generated
View File

@ -61,6 +61,12 @@ dependencies = [
"windows-sys 0.60.2", "windows-sys 0.60.2",
] ]
[[package]]
name = "bitflags"
version = "2.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.19.0" version = "3.19.0"
@ -119,6 +125,59 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "comfy-table"
version = "7.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b03b7db8e0b4b2fdad6c551e634134e99ec000e5c8c3b6856c65e8bbaded7a3b"
dependencies = [
"crossterm",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "crossterm"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
dependencies = [
"bitflags",
"crossterm_winapi",
"document-features",
"parking_lot",
"rustix",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "document-features"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
dependencies = [
"litrs",
]
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.60.2",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.5.0" version = "0.5.0"
@ -141,6 +200,33 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "libc"
version = "0.2.176"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "litrs"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.28" version = "0.4.28"
@ -165,6 +251,29 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.101" version = "1.0.101"
@ -183,6 +292,15 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.11.3" version = "1.11.3"
@ -212,12 +330,37 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
[[package]]
name = "rustix"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.60.2",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
version = "1.0.22" version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@ -261,6 +404,18 @@ version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d"
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
@ -360,10 +515,33 @@ name = "wfassoc_exec"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap",
"comfy-table",
"thiserror", "thiserror",
"wfassoc", "wfassoc",
] ]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "windows-link" name = "windows-link"
version = "0.2.0" version = "0.2.0"

View File

@ -1,6 +1,9 @@
//! This crate provide utilities fetching and manilupating Windows file association. //! This crate provide utilities fetching and manilupating Windows file association.
//! All code under crate are following Microsoft document: https://learn.microsoft.com/en-us/windows/win32/shell/customizing-file-types-bumper //! All code under crate are following Microsoft document: https://learn.microsoft.com/en-us/windows/win32/shell/customizing-file-types-bumper
#[cfg(not(target_os = "windows"))]
compile_error!("Crate wfassoc is only supported on Windows.");
use regex::Regex; use regex::Regex;
use std::fmt::Display; use std::fmt::Display;
use std::path::PathBuf; use std::path::PathBuf;
@ -8,9 +11,6 @@ use std::str::FromStr;
use std::sync::LazyLock; use std::sync::LazyLock;
use thiserror::Error as TeError; use thiserror::Error as TeError;
#[cfg(not(target_os = "windows"))]
compile_error!("Crate wfassoc is only supported on Windows.");
// region: Error Types // region: Error Types
/// All possible error occurs in this crate. /// All possible error occurs in this crate.
@ -29,6 +29,7 @@ pub enum Error {
// endregion // endregion
/// The scope where wfassoc will operate. /// The scope where wfassoc will operate.
#[derive(Debug, Copy, Clone)]
pub enum Scope { pub enum Scope {
/// Scope for current user. /// Scope for current user.
User, User,
@ -40,17 +41,17 @@ pub enum Scope {
/// ///
/// It usually means that checking whether current process is running as Administrator. /// It usually means that checking whether current process is running as Administrator.
/// Return true if it is, otherwise false. /// Return true if it is, otherwise false.
/// ///
/// Reference: https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-checktokenmembership /// Reference: https://learn.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-checktokenmembership
pub fn has_privilege() -> bool { pub fn has_privilege() -> bool {
use windows_sys::core::BOOL;
use windows_sys::Win32::Foundation::HANDLE; use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Security::{ use windows_sys::Win32::Security::{
SECURITY_NT_AUTHORITY, PSID, AllocateAndInitializeSid, CheckTokenMembership, FreeSid AllocateAndInitializeSid, CheckTokenMembership, FreeSid, PSID, SECURITY_NT_AUTHORITY,
}; };
use windows_sys::Win32::System::SystemServices:: { use windows_sys::Win32::System::SystemServices::{
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS DOMAIN_ALIAS_RID_ADMINS, SECURITY_BUILTIN_DOMAIN_RID,
}; };
use windows_sys::core::BOOL;
let nt_authority = SECURITY_NT_AUTHORITY.clone(); let nt_authority = SECURITY_NT_AUTHORITY.clone();
let mut administrators_group: PSID = PSID::default(); let mut administrators_group: PSID = PSID::default();
@ -75,13 +76,8 @@ pub fn has_privilege() -> bool {
} }
let mut is_member: BOOL = BOOL::default(); let mut is_member: BOOL = BOOL::default();
let success: BOOL = unsafe { let success: BOOL =
CheckTokenMembership( unsafe { CheckTokenMembership(HANDLE::default(), administrators_group, &mut is_member) };
HANDLE::default(),
administrators_group,
&mut is_member,
)
};
unsafe { unsafe {
FreeSid(administrators_group); FreeSid(administrators_group);
@ -90,7 +86,7 @@ pub fn has_privilege() -> bool {
if success == 0 { if success == 0 {
panic!("Win32 CheckTokenMembership() failed"); panic!("Win32 CheckTokenMembership() failed");
} }
is_member != 0 is_member != 0
} }
@ -113,6 +109,10 @@ impl FileExt {
None => Err(ParseFileExtError::new()), None => Err(ParseFileExtError::new()),
} }
} }
pub fn query(&self, scope: Scope) -> Option<FileExtAssoc> {
FileExtAssoc::new(self, scope)
}
} }
/// The error occurs when try parsing string into FileExt. /// The error occurs when try parsing string into FileExt.
@ -140,6 +140,55 @@ impl FromStr for FileExt {
} }
} }
/// The association infomations of specific file extension.
pub struct FileExtAssoc {
default: String,
open_with_progids: Vec<String>,
}
impl FileExtAssoc {
fn new(file_ext: &FileExt, scope: Scope) -> Option<Self> {
let hk = match scope {
Scope::User => winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER),
Scope::System => winreg::RegKey::predef(winreg::enums::HKEY_LOCAL_MACHINE),
};
let classes = hk
.open_subkey_with_flags("Software\\Classes", winreg::enums::KEY_READ)
.unwrap();
let thisext =
match classes.open_subkey_with_flags(file_ext.to_string(), winreg::enums::KEY_READ) {
Ok(v) => v,
Err(e) => return None,
};
let default = thisext.get_value("").unwrap_or(String::new());
let open_with_progids = if let Ok(progids) =
thisext.open_subkey_with_flags("OpenWithProdIds", winreg::enums::KEY_READ)
{
progids.enum_keys().map(|x| x.unwrap()).collect()
} else {
Vec::new()
};
Some(Self {
default,
open_with_progids,
})
}
pub fn get_default(&self) -> &str {
&self.default
}
pub fn len_open_with_progid(&self) -> usize {
self.open_with_progids.len()
}
pub fn iter_open_with_progids(&self) -> impl Iterator<Item = &str> {
self.open_with_progids.iter().map(|s| s.as_str())
}
}
// endregion // endregion
// region: Executable Resource // region: Executable Resource

View File

@ -10,3 +10,4 @@ license = "SPDX:MIT"
thiserror = { workspace = true } thiserror = { workspace = true }
wfassoc = { path="../wfassoc" } wfassoc = { path="../wfassoc" }
clap = { version="4.5.48", features=["derive"]} clap = { version="4.5.48", features=["derive"]}
comfy-table = "7.2.1"

View File

@ -1,7 +1,8 @@
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use comfy_table::Table;
use std::process; use std::process;
use wfassoc::{Error as WfError};
use thiserror::Error as TeError; use thiserror::Error as TeError;
use wfassoc::{Error as WfError, FileExt, Scope};
// region: Basic Types // region: Basic Types
@ -10,7 +11,7 @@ use thiserror::Error as TeError;
enum Error { enum Error {
/// Error from wfassoc core. /// Error from wfassoc core.
#[error("{0}")] #[error("{0}")]
Core(#[from] WfError) Core(#[from] WfError),
} }
/// Result type used in this executable. /// Result type used in this executable.
@ -89,9 +90,40 @@ fn run_unregister(cli: Cli) -> Result<()> {
} }
fn run_query(cli: Cli) -> Result<()> { fn run_query(cli: Cli) -> Result<()> {
let exts = [
".jpg", ".jfif", ".gif", ".bmp", ".png", ".ico", ".jpeg", ".tif", ".tiff", ".webp", ".svg",
".kra", ".xcf", ".avif", ".qoi", ".apng", ".exr",
];
let mut table = Table::new();
table.set_header(["Extension", "Default Open", "Open With"]);
for ext in exts.iter().map(|e| FileExt::new(e).unwrap()) {
if let Some(ext_assoc) = ext.query(Scope::User) {
if ext_assoc.len_open_with_progid() == 0 {
table.add_row([ext.to_string().as_str(), ext_assoc.get_default(), ""]);
} else {
for (i, open_with_entry) in ext_assoc.iter_open_with_progids().enumerate() {
if i == 0 {
table.add_row([
ext.to_string().as_str(),
ext_assoc.get_default(),
open_with_entry,
]);
} else {
table.add_row(["", "", open_with_entry]);
}
}
}
} else {
table.add_row([ext.to_string().as_str(), "", ""]);
}
}
println!("{table}");
// let program = Program::new(); // let program = Program::new();
// program.query()?; // program.query()?;
println!("Has privilege: {}", wfassoc::has_privilege()); //println!("Has privilege: {}", wfassoc::has_privilege());
Ok(()) Ok(())
} }