mirror of
https://github.com/lune-org/lune.git
synced 2025-04-04 10:30:54 +01:00
feat: store magic signature as a meaningful constant
This commit is contained in:
parent
94b27d81d1
commit
3c2464d3ce
3 changed files with 33 additions and 30 deletions
|
@ -8,6 +8,11 @@ use tokio::{
|
|||
use anyhow::Result;
|
||||
use mlua::Compiler as LuaCompiler;
|
||||
|
||||
// The signature which separates indicates the presence of bytecode to execute
|
||||
// If a binary contains this magic signature as the last 8 bytes, that must mean
|
||||
// it is a standalone binary
|
||||
pub const MAGIC: &[u8; 8] = b"cr3sc3nt";
|
||||
|
||||
/**
|
||||
Compiles and embeds the bytecode of a requested lua file to form a standalone binary,
|
||||
then writes it to an output file, with the required permissions.
|
||||
|
@ -32,10 +37,6 @@ pub async fn build_standalone<T: AsRef<Path>>(
|
|||
let mut patched_bin = fs::read(env::current_exe()?).await?;
|
||||
let base_bin_offset = u64::try_from(patched_bin.len())?;
|
||||
|
||||
// The signature which separates indicates the presence of bytecode to execute
|
||||
// If a binary contains this signature, that must mean it is a standalone binary
|
||||
let signature: Vec<u8> = vec![0x4f, 0x3e, 0xf8, 0x41, 0xc3, 0x3a, 0x52, 0x16];
|
||||
|
||||
// Compile luau input into bytecode
|
||||
let bytecode = LuaCompiler::new()
|
||||
.set_optimization_level(2)
|
||||
|
@ -45,18 +46,18 @@ pub async fn build_standalone<T: AsRef<Path>>(
|
|||
|
||||
println!(" {bytecode_prefix} {script_path}");
|
||||
|
||||
patched_bin.append(&mut bytecode.clone());
|
||||
patched_bin.extend(&bytecode);
|
||||
|
||||
let mut meta = base_bin_offset.to_ne_bytes().to_vec();
|
||||
let mut meta = base_bin_offset.to_ne_bytes().to_vec(); // Start with the base bytecode offset
|
||||
|
||||
// Include metadata in the META chunk, each field is 8 bytes
|
||||
meta.append(&mut (bytecode.len() as u64).to_ne_bytes().to_vec()); // Size of bytecode, used to calculate end offset at runtime
|
||||
meta.append(&mut 1_u64.to_ne_bytes().to_vec()); // Number of files, padded with null bytes - for future use
|
||||
meta.extend((bytecode.len() as u64).to_ne_bytes()); // Size of bytecode, used to calculate end offset at runtime
|
||||
meta.extend(1_u64.to_ne_bytes()); // Number of files, padded with null bytes - for future use
|
||||
|
||||
patched_bin.append(&mut meta);
|
||||
patched_bin.extend(meta);
|
||||
|
||||
// Append the signature to the base binary
|
||||
patched_bin.append(&mut signature.clone());
|
||||
// Append the magic signature to the base binary
|
||||
patched_bin.extend(MAGIC);
|
||||
|
||||
// Write the compiled binary to file
|
||||
#[cfg(target_family = "unix")]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::{env, ops::ControlFlow, process::ExitCode};
|
||||
|
||||
use crate::cli::build::MAGIC;
|
||||
use lune::Lune;
|
||||
|
||||
use anyhow::Result;
|
||||
|
@ -9,10 +10,7 @@ use tokio::fs::read as read_to_vec;
|
|||
Returns information about whether the execution environment is standalone
|
||||
or not, the standalone binary signature, and the contents of the binary.
|
||||
*/
|
||||
pub async fn check_env() -> (bool, Vec<u8>, Vec<u8>) {
|
||||
// Signature which is only present in standalone lune binaries
|
||||
let signature: Vec<u8> = vec![0x4f, 0x3e, 0xf8, 0x41, 0xc3, 0x3a, 0x52, 0x16];
|
||||
|
||||
pub async fn check_env() -> (bool, Vec<u8>) {
|
||||
// Read the current lune binary to memory
|
||||
let bin = if let Ok(contents) = read_to_vec(
|
||||
env::current_exe().expect("failed to get path to current running lune executable"),
|
||||
|
@ -24,20 +22,21 @@ pub async fn check_env() -> (bool, Vec<u8>, Vec<u8>) {
|
|||
Vec::new()
|
||||
};
|
||||
|
||||
let is_standalone = !bin.is_empty() && bin[bin.len() - signature.len()..bin.len()] == signature;
|
||||
let is_standalone =
|
||||
!bin.is_empty() && bin[bin.len() - MAGIC.len()..bin.len()] == MAGIC.to_vec();
|
||||
|
||||
(is_standalone, signature, bin)
|
||||
(is_standalone, bin)
|
||||
}
|
||||
|
||||
/**
|
||||
Discovers, loads and executes the bytecode contained in a standalone binary.
|
||||
*/
|
||||
pub async fn run_standalone(signature: Vec<u8>, bin: Vec<u8>) -> Result<ExitCode> {
|
||||
pub async fn run_standalone(bin: Vec<u8>) -> Result<ExitCode> {
|
||||
let mut bytecode_offset = 0;
|
||||
let mut bytecode_size = 0;
|
||||
|
||||
// standalone binary structure (reversed, 8 bytes per field)
|
||||
// [0] => signature
|
||||
// [0] => magic signature
|
||||
// ----------------
|
||||
// -- META Chunk --
|
||||
// [1] => file count
|
||||
|
@ -47,21 +46,21 @@ pub async fn run_standalone(signature: Vec<u8>, bin: Vec<u8>) -> Result<ExitCode
|
|||
// -- MISC Chunk --
|
||||
// [4..n] => bytecode (variable size)
|
||||
// ----------------
|
||||
// NOTE: All integers are 8 byte unsigned 64 bit (u64's).
|
||||
// NOTE: All integers are 8 byte, padded, unsigned & 64 bit (u64's).
|
||||
|
||||
// The rchunks will have unequally sized sections in the beginning
|
||||
// but that doesn't matter to us because we don't need anything past the
|
||||
// middle chunks where the bytecode is stored
|
||||
bin.rchunks(signature.len())
|
||||
bin.rchunks(MAGIC.len())
|
||||
.enumerate()
|
||||
.try_for_each(|(idx, chunk)| {
|
||||
if bytecode_offset != 0 && bytecode_size != 0 {
|
||||
return ControlFlow::Break(());
|
||||
}
|
||||
|
||||
if idx == 0 && chunk != signature {
|
||||
if idx == 0 && chunk != MAGIC {
|
||||
// Binary is guaranteed to be standalone, we've confirmed this before
|
||||
unreachable!("expected proper signature for standalone binary")
|
||||
unreachable!("expected proper magic signature for standalone binary")
|
||||
}
|
||||
|
||||
if idx == 3 {
|
||||
|
@ -78,16 +77,19 @@ pub async fn run_standalone(signature: Vec<u8>, bin: Vec<u8>) -> Result<ExitCode
|
|||
// If we were able to retrieve the required metadata, we load
|
||||
// and execute the bytecode
|
||||
|
||||
// println!("offset: {}", bytecode_offset);
|
||||
// println!("size: {}", bytecode_size);
|
||||
|
||||
// Skip the first argument which is the path to current executable
|
||||
let args = env::args().skip(1).collect::<Vec<_>>();
|
||||
let bytecode =
|
||||
&bin[usize::try_from(bytecode_offset)?..usize::try_from(bytecode_offset + bytecode_size)?];
|
||||
|
||||
// println!("bytecode: {:?}", bytecode);
|
||||
|
||||
let result = Lune::new()
|
||||
.with_args(args)
|
||||
.run(
|
||||
"STANDALONE",
|
||||
&bin[usize::try_from(bytecode_offset)?
|
||||
..usize::try_from(bytecode_offset + bytecode_size)?],
|
||||
)
|
||||
.run("STANDALONE", bytecode)
|
||||
.await;
|
||||
|
||||
Ok(match result {
|
||||
|
|
|
@ -28,12 +28,12 @@ async fn main() -> ExitCode {
|
|||
.with_level(true)
|
||||
.init();
|
||||
|
||||
let (is_standalone, signature, bin) = executor::check_env().await;
|
||||
let (is_standalone, bin) = executor::check_env().await;
|
||||
|
||||
if is_standalone {
|
||||
// It's fine to unwrap here since we don't want to continue
|
||||
// if something fails
|
||||
return executor::run_standalone(signature, bin).await.unwrap();
|
||||
return executor::run_standalone(bin).await.unwrap();
|
||||
}
|
||||
|
||||
match Cli::parse().run().await {
|
||||
|
|
Loading…
Add table
Reference in a new issue