mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2025-06-07 00:04:48 +00:00
218 lines
5.7 KiB
HolyC
Executable File
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;
|
|
}
|