Skip to content

Commit fcae36a

Browse files
committed
Try to force-enable Windows LongPaths
1 parent 76baa19 commit fcae36a

5 files changed

Lines changed: 102 additions & 5 deletions

File tree

Cargo.lock

Lines changed: 35 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ serde_yaml_ng = "0.10.0"
2424
sysinfo = "0.37.2"
2525
tar = "0.4.44"
2626

27+
[target.'cfg(windows)'.dependencies]
28+
windows-registry = "0.6.1"
29+
2730
[dev-dependencies]
2831
assert_cmd = "2.0"
2932
predicates = { version = "3.0", features = ["regex"] }

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,10 @@ available:
2020
download `micromamba` if it was not found in `$PATH`. This is mostly useful
2121
for testing, but could be useful if you wish to ensure `csm` never downloads
2222
`micromamba` even if the one in `$PATH` should disappear.
23+
24+
* `skip_longpaths_check` - A boolean, which, if true, disables checking for
25+
LongPaths support on Windows. By default when `csm.exe` runs, it will check
26+
for LongPaths support. If not already enabled, it will try to enable it. If
27+
this fails (for example, because the user running `csm.exe` is not an
28+
administrator), `csm.exe` will prompt for confirmation before continuing.
29+
Setting this configuration option to true, disables the check entirely.

src/csmrc.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ pub struct Config {
2626
/// the configuration file is parsed after logging is initialized. The user
2727
/// can technically do it, we won't error, but it won't have much effect.
2828
pub verbose: bool,
29+
30+
/// If true, skip checking for LongPaths support on Windows, and never try
31+
/// to set it.
32+
pub skip_longpaths_check: bool,
2933
}
3034

3135
#[allow(clippy::derivable_impls)]
@@ -37,6 +41,7 @@ impl Default for Config {
3741
cache_dir: None,
3842
download_micromamba: true,
3943
verbose: false,
44+
skip_longpaths_check: false,
4045
}
4146
}
4247
}

src/main.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use std::fs::File;
1313
use std::io::Write;
1414
use std::path::Path;
1515
use std::process::ExitCode;
16+
#[cfg(windows)]
17+
use windows_registry::LOCAL_MACHINE;
1618

1719
#[derive(Parser, Debug)]
1820
#[command(version)]
@@ -117,6 +119,34 @@ fn main() -> ExitCode {
117119
);
118120
}
119121

122+
#[cfg(windows)]
123+
if !config.skip_longpaths_check
124+
&& let Err(e) = windows_set_longpaths()
125+
{
126+
warn!(
127+
"Error while checking or enabling LongPaths for Windows: {}",
128+
e
129+
);
130+
eprintln!(
131+
"Continuing without LongPaths support can have unwanted effects and is not recommended."
132+
);
133+
eprint!("Continue anyway? [y/N]: ");
134+
let mut input = String::new();
135+
if let Err(_) = std::io::stdin().read_line(&mut input) {
136+
error!("Failed to get user input");
137+
}
138+
match input.trim().as_ref() {
139+
"y" | "Y" | "yes" => info!(
140+
"You can add the line 'skip_longpaths_check: true' to {} to skip this prompt in the future",
141+
home.join(".csmrc").display()
142+
),
143+
_ => {
144+
error!("Exiting.");
145+
return ExitCode::FAILURE;
146+
}
147+
}
148+
}
149+
120150
match cli.command {
121151
Command::Env(sub) => env::run(config, sub).finish(),
122152
Command::Robot(sub) => robot::run(config, sub).finish(),
@@ -150,3 +180,25 @@ fn create_mambarc(config: &Config, home: &Path) -> std::io::Result<()> {
150180
}
151181
Ok(())
152182
}
183+
184+
/// On windows, check if LongPaths are enabled in the registry, and enable them
185+
/// if they are not.
186+
#[cfg(windows)]
187+
fn windows_set_longpaths() -> windows_registry::Result<()> {
188+
let reg_path = r"SYSTEM\CurrentControlSet\Control\FileSystem";
189+
let ro_key = LOCAL_MACHINE.open(reg_path)?;
190+
match ro_key.get_u32("LongPathsEnabled") {
191+
Ok(1) => {
192+
debug!("Windows LongPathsEnabled setting is already enabled");
193+
Ok(())
194+
}
195+
Ok(_) => {
196+
info!(
197+
"Enabling LongPaths in the registry, this may require administrative permissions"
198+
);
199+
let rw_key = LOCAL_MACHINE.create(reg_path)?;
200+
rw_key.set_u32("LongPathsEnabled", 1)
201+
}
202+
e @ Err(_) => e.map(|_| ()),
203+
}
204+
}

0 commit comments

Comments
 (0)