blob: 0448dce73ff2a93f6caad1e31825c2aa6a983a77 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use crate::remote_bundle::{Owner, Writer};
use {
anyhow::{Context, Error, Result},
ext4_metadata::{ExtendedAttributes, ROOT_INODE_NUM},
ext4_read_only::{
parser::Parser as ExtParser,
readers::{IoAdapter, Reader},
structs::{DirEntry2, EntryType},
},
sparse::reader::SparseReader,
std::{collections::HashMap, io::Cursor},
};
pub mod remote_bundle;
pub(crate) const METADATA_PATH: &str = "metadata.v1";
/// Extract the files from an ext4 image at `path` and return a map of the destination
/// to source pairs. Additionally, create a metadata file that provides information
/// necessary for mounting the files from a fuchsia package.
pub fn ext4_extract(path: &str, out_dir: &str) -> Result<HashMap<String, String>, Error> {
let mut file =
std::fs::File::open(path).with_context(|| format!("Unable to open `{:?}'", path))?;
let reader = if sparse::is_sparse_image(&mut file) {
Box::new(IoAdapter::new(SparseReader::new(Box::new(file))?)) as Box<dyn Reader>
} else {
Box::new(IoAdapter::new(file)) as Box<dyn Reader>
};
let parser = ExtParser::new(reader);
let inode = parser.inode(ROOT_INODE_NUM as u32).unwrap();
let mut writer = Writer::new(
&out_dir,
ROOT_INODE_NUM,
inode.e2di_mode.get(),
Owner::from_inode(&inode),
ExtendedAttributes::new(),
)?;
parser.index(
parser.root_inode()?,
vec![],
&mut |parser: &ExtParser, path: Vec<&str>, entry: &DirEntry2| {
let xattr: ExtendedAttributes = parser
.inode_xattrs(entry.e2d_ino.get())?
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect();
let inode_num = entry.e2d_ino.get();
let inode = parser.inode(inode_num).unwrap();
let mode = inode.e2di_mode.get();
let owner = Owner::from_inode(&inode);
match EntryType::from_u8(entry.e2d_type)? {
EntryType::RegularFile => {
let data = parser.read_data(inode_num)?;
let mut cursor = Cursor::new(data);
writer
.add_file(&path, &mut cursor, inode_num as u64, mode, owner, xattr)
.unwrap();
}
EntryType::SymLink => {
let data = parser.read_data(inode_num)?;
writer.add_symlink(&path, data, inode_num as u64, mode, owner, xattr).unwrap();
}
EntryType::Directory => {
writer.add_directory(&path, inode_num as u64, mode, owner, xattr);
}
_ => {}
}
Ok(true)
},
)?;
Ok(writer.export()?)
}