fix(windows): opt-in pad-driver file logs + size-capped service log rotation
Two disk-write fixes: - pf-xusb/pf-dualsense no longer write C:\Users\Public\pf*-driver.log unconditionally — the file log is now opt-in (debug builds, or the PFXUSB_DEBUG_LOG / PFDS_DEBUG_LOG system env var), mirroring the audit-§4.4 fix pf-vdisplay already got: a release driver never writes the world-writable Public file (info-leak/DoS surface), and the per-report OUTPUT/SET_STATE hex dumps stop being a sustained per-rumble disk-write path during gameplay. OutputDebugStringA stays unconditional; the host's driver-silence WARN and the gamepad-driver-health failure-mode table now say the log is opt-in. - service.log/host.log get one-generation rotation: at each (re)open a file over 10 MB is renamed to .old, so a crash-restart loop or a RUST_LOG=debug left in host.env can't grow the append-forever logs without bound. Rotation runs only before an open (never under a live appender — host.log's handle lacks FILE_SHARE_DELETE, so a racing rename harmlessly fails). Windows CI compile/clippy pending (drivers workspace + host are not Linux-cross-checkable); rides along with the next pad-driver redeploy. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -269,18 +269,45 @@ fn channel_cfg() -> ChannelConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the world-writable bring-up file log is enabled (resolved once). OPT-IN — debug builds,
|
||||
/// or the `PFDS_DEBUG_LOG` (system-wide) env var — the same treatment pf-vdisplay got in audit
|
||||
/// §4.4: a RELEASE driver never writes the Public file (info-leak/DoS surface), and the per-report
|
||||
/// OUTPUT hex dumps stop being a sustained disk-write path during gameplay. DebugView can't see the
|
||||
/// UMDF host across session 0, so the file stays the bring-up diagnostic when enabled.
|
||||
fn file_log_enabled() -> bool {
|
||||
use std::sync::OnceLock;
|
||||
static ON: OnceLock<bool> = OnceLock::new();
|
||||
*ON.get_or_init(|| cfg!(debug_assertions) || std::env::var_os("PFDS_DEBUG_LOG").is_some())
|
||||
}
|
||||
|
||||
/// Process-lifetime append handle to the bring-up log, opened ONCE and shared via a `Mutex`
|
||||
/// (pf-vdisplay's pattern) — no per-line open/close.
|
||||
fn file_appender() -> Option<&'static std::sync::Mutex<std::fs::File>> {
|
||||
use std::sync::OnceLock;
|
||||
static APPENDER: OnceLock<Option<std::sync::Mutex<std::fs::File>>> = OnceLock::new();
|
||||
APPENDER
|
||||
.get_or_init(|| {
|
||||
if !file_log_enabled() {
|
||||
return None;
|
||||
}
|
||||
std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open("C:\\Users\\Public\\pfds-driver.log")
|
||||
.ok()
|
||||
.map(std::sync::Mutex::new)
|
||||
})
|
||||
.as_ref()
|
||||
}
|
||||
|
||||
fn log(s: &str) {
|
||||
if let Ok(c) = std::ffi::CString::new(s) {
|
||||
// SAFETY: c is a valid null-terminated string for the duration of the call.
|
||||
unsafe { OutputDebugStringA(c.as_ptr().cast()) };
|
||||
}
|
||||
// Also append to a world-writable file — DebugView can't capture the UMDF host's output
|
||||
// across session 0, so this is how we read driver-start diagnostics.
|
||||
use std::io::Write;
|
||||
if let Ok(mut f) = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open("C:\\Users\\Public\\pfds-driver.log")
|
||||
if let Some(m) = file_appender()
|
||||
&& let Ok(mut f) = m.lock()
|
||||
{
|
||||
let _ = writeln!(f, "{s}");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user