Skip to content

Instantly share code, notes, and snippets.

@ktwrd
Created March 4, 2025 02:08
Show Gist options
  • Save ktwrd/acac55f1979cdb3af9d98517de3d79a3 to your computer and use it in GitHub Desktop.
Save ktwrd/acac55f1979cdb3af9d98517de3d79a3 to your computer and use it in GitHub Desktop.
Remove "read-only" attribute on files in Windows (for Rust)
[package]
name = "windows-unmark-readonly-rs"
version = "0.1.0"
edition = "2024"
license = "MIT"
authors = ["Kate Ward <[email protected]>"]
[dependencies]
bitflags = "2.9.0"
widestring = "1.1.0"
windows = { version = "0.60.0", features = ["Win32_System_IO", "Win32_Storage_FileSystem"]}
/* Copyright 2025 Kate Ward
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
* and associated documentation files (the “Software”), to deal in the Software without
* restriction, including without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
use bitflags::bitflags;
use std::os::windows::fs::MetadataExt;
use windows::{
Win32::Storage::FileSystem::*,
core::*
};
use widestring::U16String;
use std::ffi::OsStr;
bitflags!{
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct WindowsFileAttribute : u32 {
const ReadOnly = 0x1;
const Hidden = 0x2;
const System = 0x4;
const Archive = 0x20;
const Normal = 0x80;
const Temporary = 0x100;
const Offline = 0x1000;
const NonContentIndexed = 0x2000;
}
}
// set this location to any location that exists on your drive.
const TARGET_LOCATION: &'static str = "C:\\Program Files (x86)\\Steam\\steamapps\\sourcemods\\open_fortress\\gameinfo.txt";
fn main() {
println!("=== testing file {TARGET_LOCATION:}");
let previous = get_windows_file_attributes(&TARGET_LOCATION).unwrap();
println!("previous attrs: {:#?}", previous);
if previous.contains(WindowsFileAttribute::ReadOnly) {
println!("removing read-only attribute");
let new_attr = previous - WindowsFileAttribute::ReadOnly;
set_file_attributes_win(&TARGET_LOCATION, new_attr).unwrap();
let new = get_windows_file_attributes(&TARGET_LOCATION);
if let Ok(new_d) = new {
println!("new attrs: {:#?}", new_d);
} else {
println!("failed to get file attributes: {:#?}", new);
}
} else {
println!("no read-only attribute found");
}
}
fn set_file_attributes_win<P: AsRef<OsStr>>(location: P, attr: WindowsFileAttribute)
-> windows::core::Result<()>
{
if let Some(location_str) = location.as_ref().to_str() {
let s = U16String::from_str(location_str);
let win32_attr = FILE_FLAGS_AND_ATTRIBUTES(attr.bits());
unsafe {
let win32_loc = PCWSTR(s.as_ptr());
SetFileAttributesW(win32_loc, win32_attr)?;
}
}
Ok(())
}
fn get_windows_file_attributes<P: AsRef<std::path::Path>>(location: &P) -> std::io::Result<WindowsFileAttribute>
{
let metadata = std::fs::metadata(location)?;
let attr = metadata.file_attributes();
if let Some(flags) = WindowsFileAttribute::from_bits(attr) {
return Ok(flags);
} else {
return Ok(WindowsFileAttribute::empty());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment