ZealOS/src/System/Boot/DiskISORedSea.ZC
2023-11-26 04:24:21 -05:00

218 lines
5.7 KiB
HolyC
Executable File

#help_index "File/CD DVD"
U0 FillU16Palindrome(CPalindromeU16 *dst, U16 w)
{
dst->big = EndianU16(w);
dst->little = w;
}
U0 FillU32Palindrome(CPalindromeU32 *dst, I64 d)
{
dst->big = EndianU32(d);
dst->little = d;
}
class CElTorito
{
U16 w[16];
U8 bootable; // 88=bootable 00=not bootable
U8 media_type; // 0=no emulation 4=hard disk
U16 load_seg; // 0000->07C0
U8 sys_type;
U8 zero;
U16 sect_count;
U32 load_rba; // start address of virtual disk
U8 zero2[20];
};
U0 RedSeaISO9660Stage1(U8 *iso_filename, U8 *stage2_filename)
{
CDirEntry de;
CFile *out_file = NULL;
U8 *stage1_buf = CAlloc(DVD_BOOT_LOADER_SIZE);
if (FileFind(stage2_filename, &de) && (out_file = FOpen(iso_filename, "wc+")))
{
MemCopy(stage1_buf, BDVD_START, BDVD_END - BDVD_START);
*(BDVD_BLK_LO - BDVD_START + stage1_buf)(U32 *) = de.clus >> 2;
*(BDVD_BLK_COUNT - BDVD_START + stage1_buf)(U16 *) = (de.size + DVD_BLK_SIZE - 1) >> (BLK_SIZE_BITS + 2);
*(BDVD_SHIFT_BLKS - BDVD_START + stage1_buf)(U16 *) = de.clus & 3;
if (de.clus & 3)
*(BDVD_BLK_COUNT - BDVD_START + stage1_buf)(U16 *) += 1;
FBlkWrite(out_file, stage1_buf, 20 << 2 + 1 << 2, DVD_BOOT_LOADER_SIZE / BLK_SIZE);
FClose(out_file);
}
Free(stage1_buf);
}
U0 RedSeaISO9660(U8 *iso_filename, U8 drv_let)
{
CDrive *drive = Letter2Drive(drv_let);
CISOPriDesc *iso_pri = CAlloc(DVD_BLK_SIZE),
*iso_boot = CAlloc(DVD_BLK_SIZE),
*iso_sup = CAlloc(DVD_BLK_SIZE),
*iso_term = CAlloc(DVD_BLK_SIZE);
I64 iso_size = 0, i, j;
U32 *d;
CElTorito *et = CAlloc(DVD_BLK_SIZE);
U8 *zero_buf = CAlloc(DVD_BLK_SIZE), *st;
CFile *out_file = NULL;
if (out_file = FOpen(iso_filename, "wc+"))
{
iso_size = FSize(out_file) / DVD_BLK_SIZE;
for (i = 0; i < drive->bd->drv_offset; i += 4)
FBlkWrite(out_file, zero_buf, i, 4);
iso_pri->type = ISOT_PRI_VOL_DESC;
StrCopy(iso_pri->id, "CD001");
iso_pri->version = 1;
FillU16Palindrome(&iso_pri->vol_set_size, 1);
FillU16Palindrome(&iso_pri->vol_seq_num, 1);
FillU16Palindrome(&iso_pri->log_block_size, DVD_BLK_SIZE);
FillU32Palindrome(&iso_pri->vol_space_size, iso_size);
FillU32Palindrome(&iso_pri->root_dir_record, drive->root_clus);
iso_pri->file_structure_version = 1;
StrCopy(iso_pri->publisher_id, "ZealOS RedSea");
st = MStrPrint("%s %D %T", sys_os_version_str, Now, Now);
StrCopy(iso_pri->preparer_id, st);
Free(st);
MemCopy(iso_sup, iso_pri, DVD_BLK_SIZE);
iso_sup->type = ISOT_SUPPLEMENTARY_DESC;
iso_boot->type = ISOT_BOOT_RECORD;
StrCopy(iso_boot->id, "CD001");
iso_boot->version = 1;
StrCopy(iso_boot(U8 *) + 7, "EL TORITO SPECIFICATION");
FBlkWrite(out_file, iso_pri, 16 << 2, 4);
iso_term->type = ISOT_TERMINATOR;
StrCopy(iso_term->id, "CD001");
iso_term->version = 1;
d = iso_boot(U8 *) + 0x47;
*d = 20 << 2 >> 2;
FBlkWrite(out_file, iso_boot, 17 << 2, 4);
FBlkWrite(out_file, iso_sup, 18 << 2, 4);
FBlkWrite(out_file, iso_term, 19 << 2, 4);
et->w[0] = 1;
StrCopy(&et->w[2], "ZealOS");
et->w[15] = 0xAA55;
j = 0;
for (i = 0; i < 16; i++) //Checksum
j += et->w[i];
et->w[14] = -j;
et->bootable = 0x88;
et->media_type = 0;//0=no emu 2=1.44meg 4=hard drive
et->sect_count = 4; //5 seems like the limit, 4 is safer
et->load_rba = 20 << 2 >> 2 + 1;
FBlkWrite(out_file, et, 20 << 2, 4);
FClose(out_file);
}
Free(zero_buf);
Free(et);
Free(iso_pri);
Free(iso_boot);
Free(iso_sup);
Free(iso_term);
}
I64 RedSeaISOPass1(CDirEntry *tmpde)
{
I64 dir_entry_count = 3 + LinkedListCount(tmpde), res = 0;
while (tmpde)
{
if (tmpde->attr & RS_ATTR_DIR)
{
if (tmpde->sub)
res += RedSeaISOPass1(tmpde->sub);
else
res += BLK_SIZE; //Empty dir
}
else
res += CeilU64(tmpde->size, BLK_SIZE);
tmpde = tmpde->next;
}
res += CeilU64(dir_entry_count << 6, BLK_SIZE); //Size in bytes
#assert CDIR_SIZE == 64
return res;
}
public I64 RedSeaISO(U8 *_iso_filename=NULL, U8 *_src_dir, U8 *_stage2_filename=NULL)
{//See $LK,"::/Misc/DoDistro.ZC"$. Must be ISO.C
I64 i, res, root_count, root_dir_blks, bitmap_blks, bitmap_blks1;
CDirEntry *tmpde;
U8 buf[STR_LEN], *iso_filename, *src_dir, *stage2_filename;
CDrive *drive = DriveMakeFreeSlot(DriveNextFreeLet('Q')); //First $LK,"BDT_ISO_FILE_WRITE",A="MN:BDT_ISO_FILE_WRITE"$
CBlkDev *bd = BlkDevNextFreeSlot(drive->drv_let, BDT_ISO_FILE_WRITE);
if (!IsDir(_src_dir))
PrintErr("'%s' is not a dir.\n", _src_dir);
else
{
if (!_iso_filename)
_iso_filename = blkdev.default_iso_c_filename;
iso_filename = ExtChange(_iso_filename, "ISO.C");
src_dir = DirNameAbs(_src_dir);
if (_stage2_filename)
{
stage2_filename = FileNameAbs(_stage2_filename);
*stage2_filename = drive->drv_let;
i = StrLen(src_dir);
if (i != 3) //If not root
i++; //Skip slash
StrCopy(stage2_filename + 3, stage2_filename + i);
}
else
stage2_filename = NULL;
tmpde = FilesFind(src_dir, FUF_RECURSE);
root_count = LinkedListCount(tmpde) + 3;
root_dir_blks = CeilU64(root_count << 6, BLK_SIZE) >> BLK_SIZE_BITS;
if (res = RedSeaISOPass1(tmpde) >> BLK_SIZE_BITS)
{
bd->drv_offset = 19 << 2 + (DVD_BLK_SIZE * 2 + DVD_BOOT_LOADER_SIZE) / BLK_SIZE;
bitmap_blks = 1;
do
{
bitmap_blks1 = bitmap_blks;
bitmap_blks = (res + bitmap_blks + BLK_SIZE << 3 - 1) / BLK_SIZE << 3;
}
while (bitmap_blks != bitmap_blks1);
bd->max_blk = CeilI64(bd->drv_offset + 1 + bitmap_blks + res, 4);
bd->max_blk--; //Inclusive.
bd->file_disk_name = SysStrNew(iso_filename);
bd->init_root_dir_blks = root_dir_blks;
BlkDevAdd(bd,, TRUE, TRUE);
StrPrint(buf, "%C:/", drive->drv_let);
CopyTree(src_dir, buf, TRUE);
RedSeaISO9660Stage1(iso_filename, stage2_filename);
DriveDel(drive);
BlkDevDel(bd);
}
Free(stage2_filename);
Free(src_dir);
Free(iso_filename);
}
return res;
}