|
8 | 8 | //! to import the image into the gateway's containerd runtime. |
9 | 9 |
|
10 | 10 | use std::collections::HashMap; |
11 | | -use std::io::Read; |
12 | 11 | use std::path::Path; |
13 | 12 |
|
14 | 13 | use bollard::Docker; |
@@ -176,36 +175,10 @@ fn walk_and_add( |
176 | 175 | if path.is_dir() { |
177 | 176 | walk_and_add(root, &path, ignore_patterns, builder)?; |
178 | 177 | } else { |
179 | | - let mut file = std::fs::File::open(&path) |
180 | | - .into_diagnostic() |
181 | | - .wrap_err_with(|| format!("failed to open file: {}", path.display()))?; |
182 | | - let metadata = file |
183 | | - .metadata() |
184 | | - .into_diagnostic() |
185 | | - .wrap_err_with(|| format!("failed to read metadata: {}", path.display()))?; |
186 | | - |
187 | | - let mut header = tar::Header::new_gnu(); |
188 | | - header.set_size(metadata.len()); |
189 | | - header.set_mode(0o644); |
190 | | - #[cfg(unix)] |
191 | | - { |
192 | | - use std::os::unix::fs::PermissionsExt; |
193 | | - header.set_mode(metadata.permissions().mode()); |
194 | | - } |
195 | | - header |
196 | | - .set_path(&relative_normalized) |
197 | | - .into_diagnostic() |
198 | | - .wrap_err_with(|| format!("failed to set tar entry path: {relative_normalized}"))?; |
199 | | - header.set_cksum(); |
200 | | - |
201 | | - #[allow(clippy::cast_possible_truncation)] |
202 | | - let mut contents = Vec::with_capacity(metadata.len() as usize); |
203 | | - file.read_to_end(&mut contents) |
204 | | - .into_diagnostic() |
205 | | - .wrap_err_with(|| format!("failed to read file: {}", path.display()))?; |
206 | | - |
| 178 | + // Use append_path_with_name which handles GNU LongName extensions |
| 179 | + // for paths exceeding 100 bytes (the POSIX tar name field limit). |
207 | 180 | builder |
208 | | - .append(&header, contents.as_slice()) |
| 181 | + .append_path_with_name(&path, &relative_normalized) |
209 | 182 | .into_diagnostic() |
210 | 183 | .wrap_err_with(|| format!("failed to add file to tar: {relative_normalized}"))?; |
211 | 184 | } |
@@ -433,6 +406,39 @@ mod tests { |
433 | 406 | assert!(entries.iter().any(|e| e.contains("important.log"))); |
434 | 407 | } |
435 | 408 |
|
| 409 | + #[test] |
| 410 | + fn test_long_path_exceeding_100_bytes() { |
| 411 | + let dir = tempfile::tempdir().unwrap(); |
| 412 | + let dir_path = dir.path(); |
| 413 | + |
| 414 | + // Build a nested path that exceeds 100 bytes when relative to root. |
| 415 | + let deep_dir = dir_path.join( |
| 416 | + "a/deeply/nested/directory/path/that/exceeds/one/hundred/bytes/total/from/the/build/context/root", |
| 417 | + ); |
| 418 | + fs::create_dir_all(&deep_dir).unwrap(); |
| 419 | + fs::write(deep_dir.join("file.txt"), "deep content\n").unwrap(); |
| 420 | + fs::write(dir_path.join("Dockerfile"), "FROM ubuntu:24.04\n").unwrap(); |
| 421 | + |
| 422 | + let tar_bytes = create_build_context_tar(dir_path).unwrap(); |
| 423 | + let mut archive = tar::Archive::new(tar_bytes.as_slice()); |
| 424 | + let entries: Vec<String> = archive |
| 425 | + .entries() |
| 426 | + .unwrap() |
| 427 | + .filter_map(std::result::Result::ok) |
| 428 | + .map(|e| e.path().unwrap().to_string_lossy().to_string()) |
| 429 | + .collect(); |
| 430 | + |
| 431 | + let long_entry = entries.iter().find(|e| e.contains("file.txt")); |
| 432 | + assert!( |
| 433 | + long_entry.is_some(), |
| 434 | + "tar should contain deeply nested file; entries: {entries:?}" |
| 435 | + ); |
| 436 | + assert!( |
| 437 | + long_entry.unwrap().len() > 100, |
| 438 | + "path should exceed 100 bytes to exercise GNU LongName handling" |
| 439 | + ); |
| 440 | + } |
| 441 | + |
436 | 442 | #[test] |
437 | 443 | fn test_simple_glob_match() { |
438 | 444 | assert!(simple_glob_match("*.txt", "hello.txt")); |
|
0 commit comments