Writing a simple windows driver in Rust
scorpiosoftware.net
scorpiosoftware.net
- %userprofile%\.vscode -> %appdata%\vscode
- %CSIDL_MYDOCUMENTS%\Call of Duty -> %userprofile%\Saved Games\Call of Duty
Because my documents and home directories filling up with a bunch of garbage which has a designated place on the filesystem filled me with impotent rage. I scaffolded out a project to write a filter driver in rust, read through the minifilter documentation, realized how much work it was going to be, and gave up.
I have made my peace with the fact that a windows system is just going to be filled with garbage.
> Shortcut to Documents (OneDrive - Personal)
Oh good, now all that garbage is being synced across machines. Lovely.
And better know where they come from, as there is no clean way to safely remove them.
Which one is better - a configuration file in some place or default configuration buried inside binary blob?
I actually really like the way git does it, where it reads each of these in order, last one wins.
- Default configuration compiled in
- Global configuration
- Per-user configuration
- Per-project configuration
You can opt-in to however much configuration complexity you need. Just cloning the occasional thing? Don't bother configuring, the global defaults are probably good enough. Simple commits and pushes? Make a user-level dotfile in your $XDG_CONFIG_HOME to set some basic info. Complex per-project aliases? If you want that, go ahead and opt in.
Contrast that with programs that just dump their whole default config into my home dir on first run. Just filling up with nonsense, often no way to tell what I changed or didn’t.
TO DO. /s
Also no one edits text files by hand, we use tools for that, tools that manipulate what is anyway a stream of bytes, whose meaning is given by whatever tool is used to manipulate such stream of bytes.
Apps are terrible at this on Windows. Sometimes it's in %USERPROFILE%, sometimes in one of the three %appdata% folders, then My Docs, other times in %ProgramData%, and even worse, %PUBLIC%.
There's a registry for a reason, but even Microsoft doesn't use it for x-platform apps.
There are rules when to use what, but usually folks rather code away instead of reading documentation.
cd HKCU:
https://learn.microsoft.com/powershell/scripting/samples/wor...It’s much cleaner and it comes with a more logical and useful split of config and cache stuff, e.g. you can just skip .cache when rsync-ing to a remote storage instead of having a long list of per-app escapes…
As I don't usually remove programs (or install new ones, for that matter) the scheme that works best for me and many others is "storage/app". In an ideal world a hybrid scheme might be possible, but as it stands now it is not an option and one way has to be chosen over the other.
The problem, as usual, is that apps ignore it and do whatever they want. Such as e.g. using dotfiles directly in ~ instead.
Add a cron job to delete them ? /s
Makes me want to run off a read-only DVD.
Or, you know, create a "%USERPROFILE%\Desktop\Actual Documents" folder and set that as the default open/save location in the applications you care about?
The pollution of the "My Documents" folder is unfortunate, yet nothing new, and not exactly limited to Windows (I mean, even on supposedly-perfect MacOS, I have to tolerate various game save crap under 'Documents', not to mention various 'helpful' vendor detritus), and not something that you would want to write a device driver for.
(That being said, hello Rust people, welcome to the Windows kernel! Personally, I've been enjoying the freedom to write C# drivers for years, with a minimal C++ wrapper, and I'm looking forward to the fruits of your creativity!)
That is a fight not worth fighting. Even Microsoft does not give a care in the world when deciding on storage locations and they put files directly in your %USERPROFILE% folder. Often also naming them like Linux/Unix dotfiles. I have opened tickets, pointing them to Microsoft documentation clearly stating that this is not how it should be, but they just don't care.
Still, it is infuriating seeing so much willful ignorance, when choosing the correct location is a decision just as quick as choosing the wrong location.
mklink /d link_src target_dir
mklink /J link_src target_dir
This has good discussion on the plus and minus of both. https://superuser.com/questions/343074/directory-junction-vs...
ntuser.ini
ntuser.dat.LOG1
ntuser.dat.LOG2
NTUSER.DAT
NTUSER.DAT{b2352f18-cdbf-1122-8680-002248483d79}.TM.blf
NTUSER.DAT{b2352f18-cdbf-1122-8680-002248483d79}.TMContainer00000000000000000001.regtrans-ms
NTUSER.DAT{b2352f18-cdbf-1122-8680-002248483d79}.TMContainer00000000000000000002.regtrans-msAt least macOS has one place to install applications, one place for the user's documents, and most apps somehow respect them. Then, you have designated dumping grounds like ~/Library that contains tons of junk I have no idea whether I need or not.
More, if you count UN*X binaries.
ls ~/Applications
Autodesk Fusion Service Utility.app
Autodesk Fusion.app
Chrome Apps.localized
Edge Apps.localized
Remove Autodesk Fusion.app
ls -ls /Applications | wc -l
94I actually like that simplicity more than how many things FHS describes for the various Linux distros: https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
Like, when a developer just wants to ship a product and doesn't have that much free time, it's understandable that tidy things will be overlooked.
Maybe something like https://www.gobolinux.org/at_a_glance.html would help with that.
Linux prefers by-purpose organization, so executables go in /bin (or at least something ending in /bin), configuration goes into /etc, libraries go into /lib and so on. This simplifies discovery and cross-application data management, the answer to "how do I find a library" is just "search those 5 directories, if it's not there then it's missing", but it complicates package management and makes it too easy for garbage to accumulate. It's also better for GUI apps, it's far easier to make a music app that lets you think of artists, albums and playlists, not directories, if all your music is in one place.
Mac and Windows (mostly) prefer by-package organization, where everything related to a single application is contained inside that application's folder. This makes discovery harder, as now e.g. finding all applications that can open a particular file format requires you to check every single one. However, it makes package maintenance easier, removing an app just removes all its files. This approach complicates GUI applications and makes it impossible to escape the directory hierarchy, you can no longer make a nice music app if music files are strewn all around.
No system clearly falls in one bucket or the other, the Windows registry is partially organized by purpose, so are parts of Mac OS's Library folders, while Linux has package managers like Nix, which organize by package.
Ideally, we'd do by-package organization, and have some sort of per-user / per-process "union directories" (a bit like the /bin in Plan9) that would provide easy lookups for downstream applications.
And yet far too many apps dare to put their files there. Drives me absolutely insane.
You must be using finder a lot. When working from terminal, none of that happens. Frankly, no clue why it bothers people.
If there's anything I've heard about drivers, though, it's that filesystem drivers are particularly annoying to write.
If you want to simply hide the files from view, you may have an easier time writing a shell plug-in. You have to deal with COM, but you're less likely to take down the whole system.
The Detours library lets you attach a custom DLL during the launch of any process, intercepting Win32 calls to file system APIs by writing a custom hook.
There's the built-in "compatibility shims", which are borderline undocumented, but they work similarly. They can toggle compatibility flags and redirect file and registry paths. Conveniently, these are designed to trigger only for specific EXEs based on heuristics.
To support technology like App-V and later Docker containers, Windows has an entire API surface for "virtualising" the filesystem and the registry, as well as any other NT kernel namespace.
Then there's the User Mode Filesystem and probably more approaches I'm not aware of or that I forgot about...
Almost 2 years ago they said "36,000 lines of code including a systemcall" [1], I'm curious how that project has progressed.
[1] https://www.thurrott.com/windows/282471/microsoft-is-rewriti...
https://techcommunity.microsoft.com/blog/windows-itpro-blog/...
Maybe nowadays there is more to it.
[0] https://github.com/microsoft/windows-drivers-rs/
[1] https://github.com/microsoft/windows-drivers-rs/blob/main/ex...
The actual issue here is that this "simple driver in Rust" is having to touch those direct C bindings at all - if Microsoft is going to advertise that they have support for writing drivers in Rust, that should presumably mean an API surface that's native to the language.
There's a lot more complexity in writing FFI code - you have to think very carefully about everything you do. Case convention is a triviality here.
That way functions can be marked as accurate/"ok" to call in safe code by the author of the bindings. They could absolutely not be safe; in that case, the binding author is in error marking it so.
It reads pretty naturally to me as referring to the implementation of the driver.
So you can use TRect and TPoint and pass those to PtInRect[1] which expects RECT and POINT respectively.
[1]: https://learn.microsoft.com/en-us/windows/win32/api/winuser/...
A driver that actually does something interesting would be able to have unsafe interfaces at the boundary, and more typical Rust code inside.
> wdk: Safe idiomatic bindings to APIs available in the Windows Development Kit (WDK)
And then if you look at that crate they've only implemented dbg_break, print, spinlock, and timer.
I'd take this as a sign that the bindings are a work in progress.
If you're going to write your driver in Rust... honestly I'd recommend just writing the `wdk` crate bindings you need for your driver and probably even upstreaming them. Wrapping FFI bindings in safe abstractions is usually pretty easy - but it's definitely the case that without them rust doesn't give you much.
This sample is using `wdk_sys` bindings directly without wrapping them... which is basically never the recommended way of interacting with the FFI in rust.
Being totally migrated to Linux by then I refused to use Windows for writing as well as building it, so I worked hard to build it with MSYS.
Long story short, I made it, and the driver worked great.
I think I had to write a patcher for the resulting PE (.sys) to get it to actually load.
Fun times.
It seems to be WordPress.com.
They probably rely heavily on caching and CDN.
Makes me sad that I just didn't stick to my WordPress blog 10 years ago.