135 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use std::{
 | |
|     fs::{self},
 | |
|     io::{Cursor, Read},
 | |
|     path::PathBuf,
 | |
| };
 | |
| 
 | |
| const BIN_DATA: &[u8] = include_bytes!("../data.bin");
 | |
| // 4bytes
 | |
| const LENGTH: usize = 4;
 | |
| const IDENTIFIER_LENGTH: usize = 8;
 | |
| const MD5_LENGTH: usize = 32;
 | |
| const BUF_SIZE: usize = 4096;
 | |
| 
 | |
| pub(crate) struct BinaryData {
 | |
|     pub md5_code: &'static [u8],
 | |
|     // compressed gzip data
 | |
|     pub raw: &'static [u8],
 | |
|     pub path: String,
 | |
| }
 | |
| 
 | |
| pub(crate) struct BinaryReader {
 | |
|     pub files: Vec<BinaryData>,
 | |
|     pub exe: String,
 | |
| }
 | |
| 
 | |
| impl Default for BinaryReader {
 | |
|     fn default() -> Self {
 | |
|         let (files, exe) = BinaryReader::read();
 | |
|         Self { files, exe }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl BinaryData {
 | |
|     fn decompress(&self) -> Vec<u8> {
 | |
|         let cursor = Cursor::new(self.raw);
 | |
|         let mut decoder = brotli::Decompressor::new(cursor, BUF_SIZE);
 | |
|         let mut buf = Vec::new();
 | |
|         decoder.read_to_end(&mut buf).unwrap();
 | |
|         buf
 | |
|     }
 | |
| 
 | |
|     pub fn write_to_file(&self, prefix: &PathBuf) {
 | |
|         let p = prefix.join(&self.path);
 | |
|         if let Some(parent) = p.parent() {
 | |
|             if !parent.exists() {
 | |
|                 let _ = fs::create_dir_all(parent);
 | |
|             }
 | |
|         }
 | |
|         if p.exists() {
 | |
|             // check md5
 | |
|             let f = fs::read(p.clone()).unwrap();
 | |
|             let digest = format!("{:x}", md5::compute(&f));
 | |
|             let md5_record = String::from_utf8_lossy(self.md5_code);
 | |
|             if digest == md5_record {
 | |
|                 // same, skip this file
 | |
|                 println!("skip {}", &self.path);
 | |
|                 return;
 | |
|             } else {
 | |
|                 println!("writing {}", p.display());
 | |
|                 println!("{} -> {}", md5_record, digest)
 | |
|             }
 | |
|         }
 | |
|         let _ = fs::write(p, self.decompress());
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl BinaryReader {
 | |
|     fn read() -> (Vec<BinaryData>, String) {
 | |
|         let mut base: usize = 0;
 | |
|         let mut parsed = vec![];
 | |
|         assert!(BIN_DATA.len() > IDENTIFIER_LENGTH, "bin data invalid!");
 | |
|         let mut iden = String::from_utf8_lossy(&BIN_DATA[base..base + IDENTIFIER_LENGTH]);
 | |
|         if iden != "rustdesk" {
 | |
|             panic!("bin file is not vaild!");
 | |
|         }
 | |
|         base += IDENTIFIER_LENGTH;
 | |
|         loop {
 | |
|             iden = String::from_utf8_lossy(&BIN_DATA[base..base + IDENTIFIER_LENGTH]);
 | |
|             if iden == "rustdesk" {
 | |
|                 base += IDENTIFIER_LENGTH;
 | |
|                 break;
 | |
|             }
 | |
|             // start reading
 | |
|             let mut offset = 0;
 | |
|             let path_length = u32::from_be_bytes([
 | |
|                 BIN_DATA[base + offset],
 | |
|                 BIN_DATA[base + offset + 1],
 | |
|                 BIN_DATA[base + offset + 2],
 | |
|                 BIN_DATA[base + offset + 3],
 | |
|             ]) as usize;
 | |
|             offset += LENGTH;
 | |
|             let path =
 | |
|                 String::from_utf8_lossy(&BIN_DATA[base + offset..base + offset + path_length])
 | |
|                     .to_string();
 | |
|             offset += path_length;
 | |
|             // file sz
 | |
|             let file_length = u32::from_be_bytes([
 | |
|                 BIN_DATA[base + offset],
 | |
|                 BIN_DATA[base + offset + 1],
 | |
|                 BIN_DATA[base + offset + 2],
 | |
|                 BIN_DATA[base + offset + 3],
 | |
|             ]) as usize;
 | |
|             offset += LENGTH;
 | |
|             let raw = &BIN_DATA[base + offset..base + offset + file_length];
 | |
|             offset += file_length;
 | |
|             // md5
 | |
|             let md5 = &BIN_DATA[base + offset..base + offset + MD5_LENGTH];
 | |
|             offset += MD5_LENGTH;
 | |
|             parsed.push(BinaryData {
 | |
|                 md5_code: md5,
 | |
|                 raw: raw,
 | |
|                 path: path,
 | |
|             });
 | |
|             base += offset;
 | |
|         }
 | |
|         // executable
 | |
|         let executable = String::from_utf8_lossy(&BIN_DATA[base..]).to_string();
 | |
|         (parsed, executable)
 | |
|     }
 | |
| 
 | |
|     #[cfg(unix)]
 | |
|     pub fn configure_permission(&self, prefix: &PathBuf) {
 | |
|         use std::os::unix::prelude::PermissionsExt;
 | |
| 
 | |
|         let exe_path = prefix.join(&self.exe);
 | |
|         if exe_path.exists() {
 | |
|             let f = File::open(exe_path).unwrap();
 | |
|             let meta = f.metadata().unwrap();
 | |
|             let mut permissions = meta.permissions();
 | |
|             permissions.set_mode(0o755);
 | |
|             f.set_permissions(permissions).unwrap();
 | |
|         }
 | |
|     }
 | |
| }
 |