diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/rootfs.rs | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/src/rootfs.rs b/src/rootfs.rs index 06b2557..9246aa8 100644 --- a/src/rootfs.rs +++ b/src/rootfs.rs @@ -167,7 +167,7 @@ fn copy_entry( if let Some(parent) = output.parent() { fs::create_dir_all(parent)?; } - symlink(&target, &output).with_context(|| format!("create symlink {}", output.display()))?; + replace_with_symlink(&target, &output)?; manifest.record(destination); } else if metadata.file_type().is_file() { if let Some(parent) = output.parent() { @@ -204,8 +204,23 @@ fn enable_service(rootfs: &Path, service: &ServiceName, manifest: &mut MutationM ))?; let output = rootfs.join(destination.as_path()); fs::create_dir_all(output.parent().expect("service path has a parent"))?; - symlink(format!("/usr/lib/systemd/system/{}", service.0), &output) - .with_context(|| format!("enable service {}", service.0))?; + replace_with_symlink( + Path::new(&format!("/usr/lib/systemd/system/{}", service.0)), + &output, + ) + .with_context(|| format!("enable service {}", service.0))?; manifest.record(destination.as_path()); Ok(()) } + +fn replace_with_symlink(target: &Path, output: &Path) -> Result<()> { + match fs::symlink_metadata(output) { + Ok(metadata) if metadata.file_type().is_dir() => { + bail!("cannot replace directory with symlink: {}", output.display()); + } + Ok(_) => fs::remove_file(output).with_context(|| format!("replace {}", output.display()))?, + Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} + Err(error) => return Err(error).with_context(|| format!("inspect {}", output.display())), + } + symlink(target, output).with_context(|| format!("create symlink {}", output.display())) +} |