diff options
Diffstat (limited to 'src/manifest.rs')
| -rw-r--r-- | src/manifest.rs | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/src/manifest.rs b/src/manifest.rs index 3c34ade..5b7ae77 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -131,7 +131,13 @@ impl ArtifactManifest { } } EntryType::Directory => {} - EntryType::Link => {} + EntryType::Link => { + let target = entry + .link_name() + .with_context(|| format!("read archive hardlink target for {path}"))? + .ok_or_else(|| anyhow::anyhow!("archive hardlink has no target: {path}"))?; + files.push(FileRecord::hardlink(path, portable_path(&target)?)); + } _ => unreachable!("entry type was checked above"), } } @@ -247,16 +253,29 @@ fn portable_path(path: &Path) -> Result<String> { bail!("absolute path is not valid in an artifact manifest: {}", path.display()); } let value = path.to_str().ok_or_else(|| anyhow::anyhow!("non-UTF-8 path is not valid in an artifact manifest: {}", path.display()))?; - if value.is_empty() || value == "." { + if value.is_empty() { bail!("empty path is not valid in an artifact manifest"); } - if path - .components() - .any(|component| matches!(component, std::path::Component::ParentDir)) - { - bail!("parent path is not valid in an artifact manifest: {}", path.display()); + let mut normalized = PathBuf::new(); + for component in path.components() { + match component { + std::path::Component::Normal(part) => normalized.push(part), + std::path::Component::CurDir => {} + std::path::Component::ParentDir => { + bail!("parent path is not valid in an artifact manifest: {}", path.display()); + } + std::path::Component::RootDir | std::path::Component::Prefix(_) => { + bail!("absolute path is not valid in an artifact manifest: {}", path.display()); + } + } } - Ok(value.to_owned()) + if normalized.as_os_str().is_empty() { + return Ok(".".into()); + } + let normalized = normalized + .to_str() + .ok_or_else(|| anyhow::anyhow!("non-UTF-8 path is not valid in an artifact manifest: {}", path.display()))?; + Ok(normalized.to_owned()) } fn is_enabled_service(path: &str) -> bool { @@ -326,6 +345,10 @@ impl FileRecord { pub fn symlink(path: impl Into<String>, target: impl Into<String>) -> Self { Self { path: path.into(), kind: "symlink".into(), digest: None, target: Some(target.into()) } } + + pub fn hardlink(path: impl Into<String>, target: impl Into<String>) -> Self { + Self { path: path.into(), kind: "hardlink".into(), digest: None, target: Some(target.into()) } + } } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] |