Get builder closer in line with the documentation. Adjust test.yaml accordingly.

This commit is contained in:
Bas Wiel, van de 2024-05-02 18:25:54 +02:00
parent 3009149ae9
commit cbb1762a2d
5 changed files with 78 additions and 48 deletions

View File

@ -5,12 +5,8 @@ use crate::{
partition::{Partition, PartitionType},
Disk,
},
downloader::{file::DownloadedFile, ZipDownloader},
fat::{
direntry::{DirEntry, DirEntryType},
vbr::Vbr,
Fat,
},
downloader::ZipDownloader,
fat::{vbr::Vbr, Fat},
manifest::Manifest,
os::OperatingSystem,
};
@ -21,18 +17,19 @@ pub struct DiskBuilder {
operating_system: OperatingSystem,
disk: Disk,
partition: Partition,
manifest: Manifest,
}
impl DiskBuilder {
/// Create a new builder from a manifest
pub fn new(manifest: &Manifest) -> Result<Self, std::io::Error> {
pub fn new(manifest: Manifest) -> Result<Self, std::io::Error> {
// Gather what we need from the manifest and instantiate structs as needed
let mut disk = Disk::new(manifest.disktype.as_str(), manifest.os.as_str())?;
let operating_system = OperatingSystem::from_str(manifest.os.as_str()).unwrap();
disk.attach(manifest.diskname.as_str())?;
disk.set_geometry(manifest.disksize)?;
let root_partition =
Partition::fill_disk(&disk, Some(Self::derive_partition_type(manifest)))?;
Partition::fill_disk(&disk, Some(Self::derive_partition_type(&manifest)))?;
disk.partition_table
.add_partition(root_partition.clone(), Some(0))?;
let filesystem = Fat::new(&disk, &root_partition, Some(operating_system))?;
@ -43,6 +40,7 @@ impl DiskBuilder {
filesystem,
partition: root_partition,
operating_system,
manifest: manifest,
})
}
@ -54,12 +52,10 @@ impl DiskBuilder {
) -> Result<(), std::io::Error> {
if let Some(source_file) = downloader.get_file_by_name(filename) {
self.filesystem
.mkfile(None, source_file.get_name(), source_file.get_bytes())?;
println!("Copied regular file {} to the VHD.", filename);
.mkfile(None, source_file.get_name(), false, source_file.get_bytes())?;
Ok(())
} else {
// If the file was not found, nothing essentially bad happens. Just continue and do nothing for now.
println!("We did not find file {}.", filename);
Ok(())
}
}
@ -72,11 +68,9 @@ impl DiskBuilder {
) -> Result<(), std::io::Error> {
if let Some(source_file) = downloader.get_file_by_name(filename) {
self.filesystem
.mksysfile(source_file.get_name(), source_file.get_bytes())?;
println!("Copied system file {} to the VHD.", filename);
.mkfile(None, source_file.get_name(), true, source_file.get_bytes())?;
Ok(())
} else {
println!("We did not find system file {}.", filename);
Ok(())
}
}
@ -84,18 +78,6 @@ impl DiskBuilder {
/// The builder is the struct that does all manner of validation before trying to
/// create a Disk so that what we create will make sense.
pub fn build(&mut self) -> Result<(), std::io::Error> {
let osdownloader = ZipDownloader::from_url(
&self.operating_system.get_download_url(),
Some(&format!(
"Downloading {}",
&self.operating_system.get_friendlyname()
)),
)?;
let gamedownloader = ZipDownloader::from_url(
"https://dosk8s-dist.area536.com/alleycat.zip",
Some("Downloading Alley Cat"),
)?;
let vbr = Vbr::from_os(&self.operating_system, &self.filesystem);
self.disk.write_os_bootcode()?;
@ -103,14 +85,37 @@ impl DiskBuilder {
self.disk.write_boot_signature()?;
self.disk.write_sector(vbr.as_bytes(), 1)?;
// Instantiate a downloader specifically for the operating system
let osdownloader = ZipDownloader::from_url(
&self.operating_system.get_download_url(),
Some(&format!(
"Downloading {}",
&self.operating_system.get_friendlyname()
)),
)?;
// Install the required components for a bootable operating system
self.copy_sysfile(&osdownloader, &self.operating_system.get_iosys())?;
self.copy_sysfile(&osdownloader, &self.operating_system.get_msdossys())?;
self.copy_file(&osdownloader, &self.operating_system.get_commandcom())?;
// Instantiate as many downloaders as we need for the application's distfiles
let mut gamedownloaders: Vec<ZipDownloader> =
Vec::with_capacity(self.manifest.distfiles.len());
for distfile in &self.manifest.distfiles {
let downloader = ZipDownloader::from_url(
&distfile.get_url(),
Some(&format!("Downloading {}", &distfile.get_label())),
)?;
gamedownloaders.push(downloader);
}
// Process all files in the game ZIP
for file in gamedownloader.get_files() {
self.copy_file(&gamedownloader,file.get_name())?;
for gamedownloader in gamedownloaders {
for file in gamedownloader.get_files() {
self.copy_file(&gamedownloader, file.get_name())?;
}
}
// filesystem.mkdir(None, "DOS")?;

View File

@ -330,36 +330,46 @@ impl Fat {
bootsector
}
/// Create a new system file, give the data as a byte slice.
pub fn mksysfile(&mut self, filename: &str, data: &[u8]) -> Result<(), std::io::Error> {
Ok(())
}
/// Create a new file, give the data as a byte slice.
pub fn mkfile(
&mut self,
parent: Option<&mut DirEntry>,
filename: &str,
sysfile: bool,
data: &[u8],
) -> Result<(), std::io::Error> {
// 1. Allocate the required number of clusters on the allocation table
let bytes_per_cluster = self.sectors_per_cluster as usize * 512;
let mut remaining_data = data;
// Determine the DirEntryType based on sysfile flag
let entry_type = if sysfile {
DirEntryType::SysFile
} else {
DirEntryType::File
};
// 2. Create a directory entry for the new file.
let mut file_entry = DirEntry::new(
// Attempt to allocate clusters and handle errors appropriately
let allocated_clusters = self.allocate_clusters(data)?;
println!(
"Writing {} with {} bytes into {} clusters.",
filename,
DirEntryType::File,
data.len(),
allocated_clusters.len()
);
// Create a new directory entry
let file_entry = DirEntry::new(
filename,
entry_type,
None,
&self.allocate_clusters(data)?,
&allocated_clusters,
data.len() as u32,
Some(data),
)?;
// 3. Place the entry into the correct directory entry inside the file system
match parent {
Some(subdir) => subdir.add_child(file_entry),
None => self.root_directory.add_child(file_entry),
// Add the new entry to the parent directory or use the root directory
if let Some(parent_dir) = parent {
parent_dir.add_child(file_entry);
} else {
self.root_directory.add_child(file_entry);
}
Ok(())

View File

@ -45,7 +45,7 @@ fn main() {
println!("{}", manifest.get_metadata());
println!("{}", manifest);
// Construct a DiskBuilder struct from the manifest.
let mut builder = DiskBuilder::new(&manifest).expect("Failed to create a DiskBuilder for this manifest.");
let mut builder = DiskBuilder::new(manifest).expect("Failed to create a DiskBuilder for this manifest.");
// If that worked, we're ready to do some actual building.
builder.build().expect("Failed to build the disk image.");
}

View File

@ -22,11 +22,26 @@ impl fmt::Display for GameMetadata {
#[derive(Debug, Deserialize, Serialize)]
pub struct DistFile {
name: String,
url: String,
checksum: Option<String>,
label: Option<String>
}
impl DistFile {
pub fn get_url(&self) -> String {
self.url.to_owned()
}
pub fn get_label(&self) -> String {
if self.label.is_some() {
return self.label.clone().unwrap();
}
else {
return self.url.to_owned();
}
}
}
#[derive(Debug, Deserialize, Serialize)]
struct GameConfig {
autoexec: String,

View File

@ -9,6 +9,6 @@ diskname: alleycat.vhd
disktype: pcxt
disksize: 10
distfiles:
- name: alleycat.zip
checksum: 0316fb862c67fdf9318a5c8513d99e5af185ce10306d20c27f5c6da099b5b176
- url: https://dosk8s-dist.area536.com/alleycat.zip
label: Alley Cat
os: IBMDOS200