chore: initial sanitized public snapshot

This commit is contained in:
Aria2 Rust Pro Contributors
2026-07-18 16:01:12 +08:00
commit 7c6b6a3746
321 changed files with 76896 additions and 0 deletions
@@ -0,0 +1,474 @@
use std::{
fs,
path::{Path, PathBuf},
};
use crate::model::{DownloadFile, PieceIndex, PieceState};
use super::{
model::{ControlFileError, ControlFileVersion, ControlMetadata},
text::{decode_control_metadata, encode_control_metadata},
};
/// Magic trailer marker for text metadata appended to binary control files.
const BINARY_CONTROL_TRAILER_MAGIC: &[u8; 8] = b"AR2RTXT1";
/// Block length used by upstream binary control files for piece bitfields.
const BINARY_PIECE_BLOCK_LENGTH: u64 = 16 * 1024;
/// Writes the simplified control-file representation used by the Rust implementation.
///
/// # Errors
///
/// Returns [`ControlFileError`] when the encoded control file cannot be written.
pub fn write_aria2_control_file(
path: &Path,
metadata: &ControlMetadata,
) -> Result<(), ControlFileError> {
let encoded = encode_binary_control_prefix(metadata)
.and_then(|mut prefix| {
let trailer = encode_binary_control_trailer(metadata)?;
prefix.extend_from_slice(&trailer);
Some(prefix)
})
.unwrap_or_else(|| encode_control_metadata(metadata).into_bytes());
fs::write(path, encoded)?;
Ok(())
}
/// Reads the simplified control-file representation from disk.
///
/// # Errors
///
/// Returns [`ControlFileError`] when the control file cannot be read or decoded.
pub fn read_aria2_control_file(path: &Path) -> Result<ControlMetadata, ControlFileError> {
let content = fs::read(path)?;
if looks_like_binary_control_file(&content) {
return decode_binary_control_metadata(path, &content);
}
let text = String::from_utf8(content)
.map_err(|_| ControlFileError::Parse("control file is not valid UTF-8".to_owned()))?;
decode_control_metadata(&text)
}
/// Reads an upstream-compatible binary `.aria2` control file.
///
/// # Errors
///
/// Returns [`ControlFileError`] when the control file cannot be read or decoded.
pub fn read_aria2_binary_control_file(path: &Path) -> Result<ControlMetadata, ControlFileError> {
let content = fs::read(path)?;
decode_binary_control_metadata(path, &content)
}
/// Detects whether the raw bytes look like an upstream binary control file.
fn looks_like_binary_control_file(content: &[u8]) -> bool {
matches!(
content.get(0..2),
Some(bytes) if bytes == [0x00, 0x00] || bytes == [0x00, 0x01]
)
}
/// Encodes the upstream-compatible binary control-file prefix when possible.
fn encode_binary_control_prefix(metadata: &ControlMetadata) -> Option<Vec<u8>> {
let piece_length = metadata.files.first()?.piece_length;
if piece_length == 0 || piece_length > u64::from(u32::MAX) {
return None;
}
let total_length = metadata.files.iter().map(|file| file.length).sum::<u64>();
let piece_count = binary_piece_count(total_length, piece_length)?;
let mut verified_bitfield = vec![0_u8; binary_bitfield_length(piece_count)?];
let mut normalized_states = std::collections::BTreeMap::<u32, PieceState>::new();
for (index, state) in &metadata.piece_states {
normalized_states.insert(index.0, *state);
}
let mut inflight_pieces = Vec::new();
for (index, state) in normalized_states {
let span_length = control_piece_span_bytes(index, piece_length, total_length);
if span_length > u64::from(u32::MAX) {
return None;
}
match state {
PieceState::Verified => set_binary_bit(&mut verified_bitfield, index),
PieceState::InFlight => inflight_pieces.push((
index,
u32::try_from(span_length).ok()?,
vec![0_u8; binary_bitfield_length(binary_piece_block_count(span_length)?)?],
)),
PieceState::Pending | PieceState::Failed => {}
}
}
let mut bytes = Vec::new();
push_u16_be(&mut bytes, 1_u16);
push_u32_be(&mut bytes, 0_u32);
push_u32_be(&mut bytes, 0_u32);
push_u32_be(&mut bytes, u32::try_from(piece_length).ok()?);
bytes.extend_from_slice(&total_length.to_be_bytes());
bytes.extend_from_slice(&0_u64.to_be_bytes());
push_u32_be(&mut bytes, u32::try_from(verified_bitfield.len()).ok()?);
bytes.extend_from_slice(&verified_bitfield);
push_u32_be(&mut bytes, u32::try_from(inflight_pieces.len()).ok()?);
for (index, length, bitfield) in inflight_pieces {
push_u32_be(&mut bytes, index);
push_u32_be(&mut bytes, length);
push_u32_be(&mut bytes, u32::try_from(bitfield.len()).ok()?);
bytes.extend_from_slice(&bitfield);
}
Some(bytes)
}
/// Encodes a text metadata trailer that can be appended to a binary control file.
fn encode_binary_control_trailer(metadata: &ControlMetadata) -> Option<Vec<u8>> {
let text = encode_control_metadata(metadata);
let text_len = u32::try_from(text.len()).ok()?;
let mut bytes = Vec::new();
bytes.extend_from_slice(BINARY_CONTROL_TRAILER_MAGIC);
push_u32_be(&mut bytes, text_len);
bytes.extend_from_slice(text.as_bytes());
Some(bytes)
}
/// Decodes an upstream-compatible binary control file into normalized metadata.
#[expect(
clippy::too_many_lines,
reason = "binary control metadata decoding keeps the upstream v0/v1 format walk in one auditable parser"
)]
fn decode_binary_control_metadata(
path: &Path,
content: &[u8],
) -> Result<ControlMetadata, ControlFileError> {
if !looks_like_binary_control_file(content) {
return Err(ControlFileError::UnsupportedBinaryCompatibility);
}
let mut offset = 0_usize;
let version = match read_binary_slice(content, &mut offset, 2)? {
[0x00, 0x00] => 0_u16,
[0x00, 0x01] => 1_u16,
_ => return Err(ControlFileError::UnsupportedBinaryCompatibility),
};
let _extension = read_binary_u32(content, &mut offset, version)?;
let info_hash_length = u32_to_usize(read_binary_u32(content, &mut offset, version)?)?;
if info_hash_length > 20 {
return Err(ControlFileError::Parse(
"invalid binary info hash length".to_owned(),
));
}
let _info_hash = read_binary_slice(content, &mut offset, info_hash_length)?;
let piece_length = u64::from(read_binary_u32(content, &mut offset, version)?);
if piece_length == 0 {
return Err(ControlFileError::Parse(
"binary piece length must not be 0".to_owned(),
));
}
let total_length = read_binary_u64(content, &mut offset, version)?;
let _upload_length = read_binary_u64(content, &mut offset, version)?;
let piece_count = binary_piece_count(total_length, piece_length).ok_or_else(|| {
ControlFileError::Parse("binary piece count exceeds supported range".to_owned())
})?;
let bitfield_length = u32_to_usize(read_binary_u32(content, &mut offset, version)?)?;
let expected_bitfield_length = binary_bitfield_length(piece_count).ok_or_else(|| {
ControlFileError::Parse("binary bitfield length exceeds supported range".to_owned())
})?;
if bitfield_length != expected_bitfield_length {
return Err(ControlFileError::Parse(format!(
"binary bitfield length mismatch: expected {expected_bitfield_length}, got {bitfield_length}"
)));
}
let verified_bitfield = read_binary_slice(content, &mut offset, bitfield_length)?;
let mut completed_length = 0_u64;
let mut piece_states = std::collections::BTreeMap::<u32, PieceState>::new();
for index in 0..piece_count {
if binary_bit_is_set(verified_bitfield, index) {
completed_length = completed_length
.checked_add(control_piece_span_bytes(index, piece_length, total_length))
.ok_or_else(|| {
ControlFileError::Parse("binary completed length overflowed".to_owned())
})?;
piece_states.insert(index, PieceState::Verified);
}
}
let inflight_count = read_binary_u32(content, &mut offset, version)?;
for _ in 0..inflight_count {
let index = read_binary_u32(content, &mut offset, version)?;
if total_length > 0 && index >= piece_count {
return Err(ControlFileError::Parse(format!(
"binary in-flight piece index out of range: {index}"
)));
}
let piece_span = control_piece_span_bytes(index, piece_length, total_length);
let encoded_length = u64::from(read_binary_u32(content, &mut offset, version)?);
if encoded_length > piece_span {
return Err(ControlFileError::Parse(format!(
"binary in-flight piece length exceeds span: {encoded_length}"
)));
}
let encoded_bitfield_length =
u32_to_usize(read_binary_u32(content, &mut offset, version)?)?;
let expected_piece_bitfield_length =
binary_bitfield_length(binary_piece_block_count(encoded_length).ok_or_else(|| {
ControlFileError::Parse(
"binary in-flight piece block count exceeds supported range".to_owned(),
)
})?)
.ok_or_else(|| {
ControlFileError::Parse(
"binary in-flight piece bitfield length exceeds supported range".to_owned(),
)
})?;
if encoded_bitfield_length != expected_piece_bitfield_length {
return Err(ControlFileError::Parse(format!(
"binary in-flight piece bitfield length mismatch: expected {expected_piece_bitfield_length}, got {encoded_bitfield_length}"
)));
}
let piece_bitfield = read_binary_slice(content, &mut offset, encoded_bitfield_length)?;
let was_verified = piece_states.get(&index) == Some(&PieceState::Verified);
if !was_verified {
completed_length = completed_length
.checked_add(binary_piece_completed_length(
encoded_length,
piece_bitfield,
))
.ok_or_else(|| {
ControlFileError::Parse("binary completed length overflowed".to_owned())
})?;
}
piece_states.insert(index, PieceState::InFlight);
}
let trailer_slice = content.get(offset..).ok_or_else(|| {
ControlFileError::Parse("binary control trailer offset is out of range".to_owned())
})?;
if let Some(trailer_metadata) = decode_binary_control_trailer(trailer_slice)? {
return Ok(trailer_metadata);
}
Ok(ControlMetadata {
version: if version == 0 {
ControlFileVersion::CURRENT
} else {
ControlFileVersion::BINARY_V1
},
files: vec![DownloadFile {
path: infer_binary_control_target_path(path),
length: total_length,
piece_length,
}],
checksums: Vec::new(),
piece_states: piece_states
.into_iter()
.map(|(index, state)| (PieceIndex(index), state))
.collect(),
completed_length,
retry_count: 0,
last_error: None,
last_error_at_unix_ms: None,
last_retry_at_unix_ms: None,
next_retry_at_unix_ms: None,
consecutive_failure_count: None,
active_segment_count: None,
resume_verified_at_unix_ms: None,
resume_generation: None,
})
}
/// Decodes the optional text trailer appended to a binary control file.
fn decode_binary_control_trailer(
content: &[u8],
) -> Result<Option<ControlMetadata>, ControlFileError> {
if content.is_empty() {
return Ok(None);
}
if !content.starts_with(BINARY_CONTROL_TRAILER_MAGIC) {
return Ok(None);
}
let minimum_length = checked_add_usize(
BINARY_CONTROL_TRAILER_MAGIC.len(),
4,
"binary control trailer",
)?;
if content.len() < minimum_length {
return Err(ControlFileError::Parse(
"binary control trailer is truncated".to_owned(),
));
}
let mut offset = BINARY_CONTROL_TRAILER_MAGIC.len();
let len_end = checked_add_usize(offset, 4, "binary control trailer length field")?;
let len_bytes = content
.get(offset..len_end)
.ok_or_else(|| ControlFileError::Parse("binary control trailer is truncated".to_owned()))?;
let text_len = u32_to_usize(u32::from_be_bytes(len_bytes.try_into().map_err(|_| {
ControlFileError::Parse("binary control trailer is truncated".to_owned())
})?))?;
offset = len_end;
let text_end = checked_add_usize(offset, text_len, "binary control trailer payload")?;
if content.len() != text_end {
return Err(ControlFileError::Parse(
"binary control trailer length mismatch".to_owned(),
));
}
let text_bytes = content
.get(offset..text_end)
.ok_or_else(|| ControlFileError::Parse("binary control trailer is truncated".to_owned()))?;
let text = std::str::from_utf8(text_bytes).map_err(|_| {
ControlFileError::Parse("binary control trailer is not valid UTF-8".to_owned())
})?;
decode_control_metadata(text).map(Some)
}
/// Infers the payload target path from a binary `.aria2` file path.
fn infer_binary_control_target_path(path: &Path) -> PathBuf {
let Some(file_name) = path.file_name().and_then(|name| name.to_str()) else {
return path.to_path_buf();
};
let Some(stem) = file_name.strip_suffix(".aria2") else {
return path.to_path_buf();
};
path.with_file_name(stem)
}
/// Computes the number of pieces required by a binary control file.
fn binary_piece_count(total_length: u64, piece_length: u64) -> Option<u32> {
if piece_length == 0 {
return Some(0);
}
u32::try_from(total_length.div_ceil(piece_length)).ok()
}
/// Computes the number of sub-blocks represented by a piece bitfield.
fn binary_piece_block_count(piece_length: u64) -> Option<u32> {
if piece_length == 0 {
return Some(0);
}
u32::try_from(piece_length.div_ceil(BINARY_PIECE_BLOCK_LENGTH)).ok()
}
/// Computes the byte length needed to store `bit_count` bits.
fn binary_bitfield_length(bit_count: u32) -> Option<usize> {
usize::try_from(u64::from(bit_count).div_ceil(8)).ok()
}
/// Appends a big-endian `u16` to a binary control buffer.
fn push_u16_be(bytes: &mut Vec<u8>, value: u16) {
bytes.extend_from_slice(&value.to_be_bytes());
}
/// Appends a big-endian `u32` to a binary control buffer.
fn push_u32_be(bytes: &mut Vec<u8>, value: u32) {
bytes.extend_from_slice(&value.to_be_bytes());
}
/// Marks one bit inside a binary control-file bitfield.
fn set_binary_bit(bitfield: &mut [u8], index: u32) {
let byte_index = usize::try_from(index >> 3).unwrap_or(usize::MAX);
let bit_offset = 7_u32.saturating_sub(index & 7);
if let Some(byte) = bitfield.get_mut(byte_index) {
*byte |= 1_u8 << bit_offset;
}
}
/// Returns whether one bit is set inside a binary control-file bitfield.
fn binary_bit_is_set(bitfield: &[u8], index: u32) -> bool {
let byte_index = usize::try_from(index >> 3).unwrap_or(usize::MAX);
let bit_offset = 7_u32.saturating_sub(index & 7);
bitfield
.get(byte_index)
.is_some_and(|byte| (byte & (1_u8 << bit_offset)) != 0)
}
/// Computes the completed bytes represented by one in-flight piece bitfield.
fn binary_piece_completed_length(piece_length: u64, bitfield: &[u8]) -> u64 {
let Some(block_count) = binary_piece_block_count(piece_length) else {
return 0;
};
let mut completed = 0_u64;
for block_index in 0..block_count {
if binary_bit_is_set(bitfield, block_index) {
let Some(block_start) = u64::from(block_index).checked_mul(BINARY_PIECE_BLOCK_LENGTH)
else {
return piece_length;
};
let Some(remaining) = piece_length.checked_sub(block_start) else {
return piece_length;
};
completed = completed.saturating_add(remaining.min(BINARY_PIECE_BLOCK_LENGTH));
}
}
completed.min(piece_length)
}
/// Computes the span of one piece within the total binary payload length.
fn control_piece_span_bytes(index: u32, piece_length: u64, total_length: u64) -> u64 {
let Some(start) = u64::from(index).checked_mul(piece_length) else {
return 0;
};
total_length.saturating_sub(start).min(piece_length)
}
/// Reads one raw binary slice and advances the offset.
fn read_binary_slice<'a>(
content: &'a [u8],
offset: &mut usize,
len: usize,
) -> Result<&'a [u8], ControlFileError> {
let end = checked_add_usize(*offset, len, "binary control field")?;
let slice = content
.get(*offset..end)
.ok_or_else(|| ControlFileError::Parse("binary control file is truncated".to_owned()))?;
*offset = end;
Ok(slice)
}
/// Reads a `u32` field using the endianness defined by the binary version.
fn read_binary_u32(
content: &[u8],
offset: &mut usize,
version: u16,
) -> Result<u32, ControlFileError> {
let raw = read_binary_slice(content, offset, 4)?;
let bytes: [u8; 4] = raw
.try_into()
.map_err(|_| ControlFileError::Parse("binary u32 field is truncated".to_owned()))?;
Ok(if version == 0 {
u32::from_le_bytes(bytes)
} else {
u32::from_be_bytes(bytes)
})
}
/// Reads a `u64` field using the endianness defined by the binary version.
fn read_binary_u64(
content: &[u8],
offset: &mut usize,
version: u16,
) -> Result<u64, ControlFileError> {
let raw = read_binary_slice(content, offset, 8)?;
let bytes: [u8; 8] = raw
.try_into()
.map_err(|_| ControlFileError::Parse("binary u64 field is truncated".to_owned()))?;
Ok(if version == 0 {
u64::from_le_bytes(bytes)
} else {
u64::from_be_bytes(bytes)
})
}
/// Converts a `u32` length value into `usize` for buffer indexing.
fn u32_to_usize(value: u32) -> Result<usize, ControlFileError> {
usize::try_from(value).map_err(|_| {
ControlFileError::Parse("binary length exceeds the supported platform size".to_owned())
})
}
/// Adds two `usize` values and returns a parse error on overflow.
fn checked_add_usize(lhs: usize, rhs: usize, context: &str) -> Result<usize, ControlFileError> {
lhs.checked_add(rhs)
.ok_or_else(|| ControlFileError::Parse(format!("{context} length overflowed")))
}