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 bytespub 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)}