Skip to content

Commit

Permalink
more layer hacking
Browse files Browse the repository at this point in the history
  • Loading branch information
tofay committed Sep 17, 2024
1 parent ed2f267 commit 15791b0
Show file tree
Hide file tree
Showing 5 changed files with 830 additions and 154 deletions.
33 changes: 0 additions & 33 deletions hack.py

This file was deleted.

101 changes: 2 additions & 99 deletions src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,110 +13,13 @@
//! You should have received a copy of the GNU General Public License
//! along with this program. If not, see <https://www.gnu.org/licenses/>.
use anyhow::{Context, Result};
use std::{
collections::{hash_map::Entry, HashMap},
io::Write,
os::unix::{
fs::MetadataExt,
prelude::{FileTypeExt, OsStrExt},
},
path::{Path, PathBuf},
};
use walkdir::WalkDir;
use std::{io::Write, os::unix::prelude::OsStrExt, path::Path};

// https://mgorny.pl/articles/portability-of-tar-features.html#id25
const PAX_SCHILY_XATTR: &[u8; 13] = b"SCHILY.xattr.";

/// custom implementation of tar-rs's append_dir_all that:
/// - works around https://github.com/alexcrichton/tar-rs/issues/102 so that security capabilities are preserved
/// - emulates tar's `--clamp-mtime` option so that any file/dir/symlink mtimes are no later than a specific value
/// - supports hardlinks
pub(super) fn append_dir_all_with_xattrs(
builder: &mut tar::Builder<impl Write>,
src_path: impl AsRef<Path>,
clamp_mtime: i64,
) -> Result<()> {
let src_path = src_path.as_ref();
// Map (dev, inode) -> path for hardlinks
let mut hardlinks: HashMap<(u64, u64), PathBuf> = HashMap::new();

for entry in WalkDir::new(src_path)
.follow_links(false)
.sort_by_file_name()
.into_iter()
{
let entry = entry?;
let meta = entry.metadata()?;
// skip sockets as tar-rs errors when trying to archive them.
// For comparison, umoci also errors, whereas docker skips them
if meta.file_type().is_socket() {
continue;
}

let rel_path = pathdiff::diff_paths(entry.path(), src_path)
.expect("walkdir returns path inside of search root");
if rel_path == Path::new("") {
continue;
}

if entry.file_type().is_symlink() {
if meta.mtime() > clamp_mtime {
// Setting the mtime on a symlink is fiddly with tar-rs, so we use filetime to change
// the mtime before adding the symlink to the tar archive
let mtime = filetime::FileTime::from_unix_time(clamp_mtime, 0);
filetime::set_symlink_file_times(entry.path(), mtime, mtime)?;
}
add_pax_extension_header(entry.path(), builder)?;
builder.append_path_with_name(entry.path(), rel_path)?;
} else if entry.file_type().is_file() || entry.file_type().is_dir() {
add_pax_extension_header(entry.path(), builder)?;

// If this is a hardlink, add a link header instead of the file
// if this isn't the first time we've seen this inode
if meta.nlink() > 1 {
match hardlinks.entry((meta.dev(), meta.ino())) {
Entry::Occupied(e) => {
// Add link header and continue to next entry
let mut header = tar::Header::new_gnu();
header.set_metadata(&meta);
if meta.mtime() > clamp_mtime {
header.set_mtime(clamp_mtime as u64);
}
header.set_entry_type(tar::EntryType::Link);
header.set_cksum();
builder.append_link(&mut header, &rel_path, e.get())?;
continue;
}
Entry::Vacant(e) => {
// This is the first time we've seen this inode
e.insert(rel_path.clone());
}
}
}

let mut header = tar::Header::new_gnu();
header.set_size(meta.len());
header.set_metadata(&meta);
if meta.mtime() > clamp_mtime {
header.set_mtime(clamp_mtime as u64);
}
if entry.file_type().is_file() {
builder.append_data(
&mut header,
rel_path,
&mut std::fs::File::open(entry.path())?,
)?;
} else {
builder.append_data(&mut header, rel_path, &mut std::io::empty())?;
};
}
}

Ok(())
}

// Convert any extended attributes on the specified path to a tar PAX extension header, and add it to the tar archive
fn add_pax_extension_header(
pub(crate) fn add_pax_extension_header(
path: impl AsRef<Path>,
builder: &mut tar::Builder<impl Write>,
) -> Result<(), anyhow::Error> {
Expand Down
Loading

0 comments on commit 15791b0

Please sign in to comment.