VMLXN5A4W7BY6A2JY7TZRHOM3ZUYBZ2XXTNT2D5TDTY2W34RUPWAC
fn process_paths<'a>(
mut udf_image: &File,
udf_reader: &udfread::UdfRead<impl Read + Seek>,
input_dir: &Path,
paths: impl Iterator<Item = &'a Path>,
dry_run: bool,
) -> bool {
for path in paths {
let utf8_path = match path.to_str() {
Some(path) => path,
None => {
eprintln!(
"Relative path contains non-UTF-8 characters: {}",
path.to_string_lossy()
);
return false;
}
};
let udf_file = match udf_reader.open_file(utf8_path) {
Some(file) => file,
None => {
eprintln!("Failed to open {} from UDF image", utf8_path);
return false;
}
};
let udf_size = match udf_file.size() {
Some(size) => size,
None => {
eprintln!("Failed to get UDF file size of {}", utf8_path);
return false;
}
};
let fs_path = input_dir.join(path);
let mut fs_file = match File::open(&fs_path) {
Ok(file) => file,
Err(err) => {
eprintln!("Failed to open {}: {}", fs_path.to_string_lossy(), err);
return false;
}
};
fn main() {
let fs_size = match fs_file.seek(SeekFrom::End(0)) {
Ok(size) => size,
Err(err) => {
eprintln!(
"Failed to get file size of {}: {}",
fs_path.to_string_lossy(),
err
);
return false;
}
};
if udf_size != fs_size {
eprintln!(
"Size mismatch for {} ({} vs {})",
utf8_path, fs_size, udf_size
);
return false;
}
if udf_size == 0 {
continue;
}
let blocks: u32 = ((udf_size - 1) / u64::from(UDF_BLOCK_SIZE) + 1)
.try_into()
.expect("UDF file too large!");
let mut bytes_remaining = udf_size;
for block in 0..blocks {
let image_block = match udf_file.block_lba(block) {
Some(image_block) => image_block,
None => {
eprintln!("Unsupported: file inline or sparse: {}", utf8_path);
return false;
}
};
let file_offset = u64::from(block) * u64::from(UDF_BLOCK_SIZE);
let image_offset = u64::from(image_block) * u64::from(UDF_BLOCK_SIZE);
let mut data = [0u8; UDF_BLOCK_SIZE as usize];
let bytes = if bytes_remaining > u64::from(UDF_BLOCK_SIZE) {
UDF_BLOCK_SIZE as usize
} else {
bytes_remaining as usize
};
if !dry_run {
if let Err(err) = fs_file
.seek(SeekFrom::Start(file_offset))
.and_then(|_| fs_file.read_exact(&mut data[0..bytes]))
{
eprintln!("Error reading from {}: {}", fs_path.to_string_lossy(), err);
return false;
}
if let Err(err) = udf_image
.seek(SeekFrom::Start(image_offset))
.and_then(|_| udf_image.write_all(&data[0..bytes]))
{
eprintln!("Error writing to UDF image: {}", err);
return false;
}
}
bytes_remaining -= bytes as u64;
}
}
return true;
}
fn main() -> Result<(), &'static str> {
udfread::UdfRead::open_reader(&file).expect("Failed to create UDF reader");
udfread::UdfRead::open_image_reader(&file).expect("Failed to create UDF reader");
if !process_paths(
&file,
&udf_reader,
&args.input_dir,
(&args.paths).into_iter().map(AsRef::as_ref),
true,
) {
Err("Dry run failed. UDF image is unchanged.")?;
}
if !process_paths(
&file,
&udf_reader,
&args.input_dir,
(&args.paths).into_iter().map(AsRef::as_ref),
false,
) {
Err("Replace failed after successful dry run. Image likely in an inconsistant state.")?;
}
Ok(())
fn str_to_mutf8(input: &str) -> CString {
let mut result = Vec::with_capacity(input.len() + 1);
for &byte in input.as_bytes() {
if byte == 0 {
// MUTF-8 uses an over-long encoding to represent null characters to prevent a null byte
// from appearing in the string.
result.push(0xC0);
result.push(0x80);
} else {
result.push(byte);
}
}
return CString::new(result).unwrap();
}
pub fn open_reader(reader: R) -> Option<UdfRead<R>> {
/// Open a UDF image from a generic reader.
///
/// Note: The reader’s underlying stream can be shared (e.g., by passing a &File) given the
/// following caveats:
///
/// 1. Any call to a UdfRead method (or a method on a returned object) may change the seek
/// position of the stream.
/// 2. While such a method is in progress, no other code should change the seek positon of the
/// stream. (This is trivially the case if the stream is only used from one thread.)
pub fn open_image_reader(reader: R) -> Option<UdfRead<R>> {
}
}
pub struct UdfFile<'a> {
udffile: *mut c_includes::UDFFILE,
phantom: PhantomData<&'a UdfRead>,
}
impl<'a> UdfFile<'a> {
/// Returns the size of the file in bytes
pub fn size(&self) -> Option<u64> {
let result = unsafe { c_includes::udfread_file_size(self.udffile) };
if result < 0 {
None
} else {
Some(result as u64)
}
}
/// Translates file-relative block to image-relative block
///
/// Returns None if the block is beyond the end of the file or points to a sparse region.
pub fn block_lba(&self, block: u32) -> Option<u32> {
let result = unsafe { c_includes::udfread_file_lba(self.udffile, block) };
if result == 0 {
None
} else {
Some(result)
}