Skip to content

Commit 2a7da70

Browse files
committed
Strip \?\ prefix from Windows autostart paths
Path::canonicalize on Windows returns extended-length paths with the \?\ prefix, which the Windows shell silently refuses to launch from the Run key (and which also breaks the macOS launchd / Linux .desktop Exec lines if anyone ever lands on a UNC path). Resolve the binary and config to an absolute path and strip the prefix before writing.
1 parent e6ee511 commit 2a7da70

1 file changed

Lines changed: 33 additions & 22 deletions

File tree

src/autostart.rs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,8 @@ fn enable_for_exe(exe: &Path, config_path: &Path) -> Result<()> {
3232
fn platform_enable(exe: &Path, config_path: &Path) -> Result<()> {
3333
use std::process::Command;
3434

35-
let exe = exe
36-
.canonicalize()
37-
.unwrap_or_else(|_| exe.to_path_buf())
38-
.to_string_lossy()
39-
.into_owned();
40-
let config = config_path
41-
.canonicalize()
42-
.unwrap_or_else(|_| config_path.to_path_buf())
43-
.to_string_lossy()
44-
.into_owned();
35+
let exe = absolute_display_path(exe);
36+
let config = absolute_display_path(config_path);
4537
let value = format!(
4638
"\"{}\" --config \"{}\" {} gui",
4739
exe, config, AUTOSTART_FLAG
@@ -130,16 +122,8 @@ fn platform_enable(exe: &Path, config_path: &Path) -> Result<()> {
130122
.with_context(|| format!("failed to create {}", parent.display()))?;
131123
}
132124

133-
let exe = exe
134-
.canonicalize()
135-
.unwrap_or_else(|_| exe.to_path_buf())
136-
.to_string_lossy()
137-
.into_owned();
138-
let config = config_path
139-
.canonicalize()
140-
.unwrap_or_else(|_| config_path.to_path_buf())
141-
.to_string_lossy()
142-
.into_owned();
125+
let exe = absolute_display_path(exe);
126+
let config = absolute_display_path(config_path);
143127
let plist = format!(
144128
r#"<?xml version="1.0" encoding="UTF-8"?>
145129
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -231,8 +215,8 @@ fn platform_enable(exe: &Path, config_path: &Path) -> Result<()> {
231215

232216
let exec = format!(
233217
"{} --config {} {} gui",
234-
desktop_quote(&exe.to_string_lossy()),
235-
desktop_quote(&config_path.to_string_lossy()),
218+
desktop_quote(&absolute_display_path(exe)),
219+
desktop_quote(&absolute_display_path(config_path)),
236220
AUTOSTART_FLAG,
237221
);
238222

@@ -288,6 +272,33 @@ fn home_dir() -> Option<PathBuf> {
288272
std::env::var_os("HOME").map(PathBuf::from)
289273
}
290274

275+
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))]
276+
fn absolute_display_path(path: &Path) -> String {
277+
let resolved = path
278+
.canonicalize()
279+
.ok()
280+
.or_else(|| std::path::absolute(path).ok())
281+
.unwrap_or_else(|| path.to_path_buf());
282+
let display = resolved.to_string_lossy().into_owned();
283+
strip_extended_length_prefix(display)
284+
}
285+
286+
#[cfg(target_os = "windows")]
287+
fn strip_extended_length_prefix(value: String) -> String {
288+
if let Some(rest) = value.strip_prefix(r"\\?\UNC\") {
289+
return format!(r"\\{rest}");
290+
}
291+
if let Some(rest) = value.strip_prefix(r"\\?\") {
292+
return rest.to_string();
293+
}
294+
value
295+
}
296+
297+
#[cfg(not(target_os = "windows"))]
298+
fn strip_extended_length_prefix(value: String) -> String {
299+
value
300+
}
301+
291302
#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
292303
fn platform_enable(_exe: &Path, _config_path: &Path) -> Result<()> {
293304
bail!("autostart is not supported on this platform")

0 commit comments

Comments
 (0)