ZealOS/src/Kernel/BlkDev/DiskCDDVD.ZC
2022-08-27 08:15:06 -04:00

291 lines
6.5 KiB
HolyC
Executable file

Bool ISOInit(CDrive *drive, I64 blk)
{
CBlkDev *bd = drive->bd;
I64 spc = bd->blk_size >> BLK_SIZE_BITS, i = blk / spc, drv_offset = 0;
CISOPriDesc *iso = MAlloc(bd->blk_size);
CISODirEntry *de;
Bool unlock, res = FALSE;
U8 buf[8];
try
{
unlock = DriveLock(drive);
drive->fs_type = FSt_ISO9660;
drive->spc = spc;
drive->data_area = drive->root_clus = drive->drv_offset = bd->drv_offset = drive->size = 0;
while (TRUE)
{
drive->size = MaxI64(drive->size, (i + 1) * spc);
BlkRead(drive, iso, i * spc, spc);
buf[0](U32) = iso->id[0](U32);
buf[4](U16) = iso->id[4](U8);
switch (ListMatch(buf, "CD001\0CDW02\0BEA01\0BOOT2\0NSR02\0NSR03\0TEA01\0", LMF_EXACT))
{
case 0:
switch (iso->type)
{
case ISOT_BOOT_RECORD:
drv_offset += (2 * DVD_BLK_SIZE + DVD_BLK_SIZE) / BLK_SIZE;
break;
// case ISOT_PRI_VOL_DESC:
case ISOT_SUPPLEMENTARY_DESC:
de = &iso->root_dir_record;
drive->size = iso->vol_space_size.little * bd->blk_size >> BLK_SIZE_BITS;
if (!StrCompare(iso->publisher_id, "ZealOS RedSea") ||
!StrCompare(iso->publisher_id - 4, "ZenithOS RedSea") ||
!StrCompare(iso->publisher_id - 4, "TempleOS RedSea"))
{
drive->fs_type = FSt_REDSEA;
bd->drv_offset = drive->drv_offset = 19 << 2 + drv_offset;
bd->max_blk = drive->size - 1;
drive->size -= bd->drv_offset;
RedSeaInit(drive);
}
else
drive->root_clus = de->loc.little;
res = TRUE;
goto di_done;
case ISOT_TERMINATOR:
throw('Drive');
}
break;
default: //Its normal for ISO3346 to read NULL blk as terminator
PrintErr("File System Not Supported\n");
throw('Drive');
}
i++;
}
di_done:
Free(iso);
if (unlock)
DriveUnlock(drive);
}
catch
{
drive->fs_type = FSt_ISO9660;
drive->spc = spc;
drive->drv_offset = bd->drv_offset = drive->data_area = drive->root_clus = 0;
Free(iso);
if (unlock)
DriveUnlock(drive);
}
return res;
}
U0 DVDImageRead(U8 dvd_drive_let, U8 *out_name)
{//Read entire CD/DVD image into ISO file.
CDrive *drive = Letter2Drive(dvd_drive_let);
CBlkDev *bd = drive->bd;
U8 *buf = MAlloc(COPY_BUF_BLKS << BLK_SIZE_BITS), *out_name2 = ExtDefault(out_name, "ISO");
CFile *f = FOpen(out_name2, "w");
I64 n, spc = bd->blk_size >> BLK_SIZE_BITS, blk = 0, count, retry;
BlkDevInit(bd);
if (bd->type != BDT_ATAPI)
throw('BlkDev');
if (!out_name)
out_name = blkdev.default_iso_filename;
// count = CeilU64(drive->size, spc);
count = bd->max_blk + 1;
progress1 = 0;
progress1_max = count;
while (count > 0)
{
if (count > COPY_BUF_BLKS)
n = COPY_BUF_BLKS;
else
n = count;
if (n > bd->max_reads)
n = bd->max_reads;
retry = 4;
while (--retry)
if (AHCIAtapiBlksRead(bd, buf, blk / spc, n / spc))
//n is 0x800 if max_reads. Up to 8 additional seconds
break;
if (!retry)
AHCIAtapiBlksRead(bd, buf, blk / spc, n / spc);
FBlkWrite(f, buf, blk, n);
count -= n;
blk += n;
progress1 += n;
}
progress1 = progress1_max = 0;
FClose(f);
Free(buf);
Free(out_name2);
}
class CDualBuf
{
U8 *buf0, *buf1;
I64 in_buf, out_buf, count;
U8 *filename;
CBlkDev *dvd_bd;
};
#define DVD_WRITE_BLKS 0xFFFFF
/*
U0 DVDImageWriteTask(CDualBuf *d)
{
U8 *buf;
I64 n, blk = 0, count = d->count;
CFile *f;
if (FileAttr(d->filename) & RS_ATTR_CONTIGUOUS)
f = FOpen(d->filename, "rc");
else
f = FOpen(d->filename, "r");
while (count > 0)
{
if (count > DVD_WRITE_BLKS)
n = DVD_WRITE_BLKS;
else
n = count;
// if (n > d->dvd_bd->max_writes)
// n = d->dvd_bd->max_writes;
if (d->in_buf & 1)
buf = d->buf1;
else
buf = d->buf0;
while (d->in_buf>d->out_buf + 1)
Yield;
FBlkRead(f, buf, blk, n);
d->in_buf++;
count -= n;
blk += n;
}
FClose(f);
}
*/
U0 DVDImageWrite(U8 dvd_drive_let, U8 *in_name=NULL, I64 media_type=MT_DVD)
{//Write CD/DVD ISO file to disk.
CDualBuf *d = CAlloc(sizeof(CDualBuf));
U8 *buf, *in_name2, *in_name3;
I64 /*n,*/ spc, blk = 0, count;
CDrive *drive = Letter2Drive(dvd_drive_let);
CBlkDev *bd = drive->bd, *bd2;
// CTask *task;
CFile *f;
if (!in_name)
in_name = blkdev.default_iso_filename;
in_name3 = ExtDefault(in_name, "ISO");
in_name2 = FileNameAbs(in_name3);
f = FOpen(in_name2, "r");
if (!f)
{
Free(d);
return;
}
count = (FSize(f) + BLK_SIZE - 1) >> BLK_SIZE_BITS;
FClose(f);
if (bd->type != BDT_ATAPI)
throw('BlkDev');
bd2 = Letter2BlkDev(*in_name2);
while (bd2->lock_fwding)
bd2 = bd2->lock_fwding; //If two blkdevs on same controller, use one lock
if (bd2->port_num == bd->port_num)
{
PrintErr("Can't burn CD/DVD on same SATA port as file.\n\n");
throw('BlkDev');
}
bd->flags |= BDF_READ_ONLY_OVERRIDE;
BlkDevInit(bd);
spc = bd->blk_size >> BLK_SIZE_BITS;
if (drive->size < count)
drive->size = count;
/*
d->filename = in_name2;
d->dvd_bd = bd;
d->buf0 = MAlloc(DVD_WRITE_BLKS << BLK_SIZE_BITS);
d->buf1 = MAlloc(DVD_WRITE_BLKS << BLK_SIZE_BITS);
d->count = count;
task = Spawn(&DVDImageWriteTask, d, "Write CD/DVD");
while (d->in_buf <= d->out_buf)
Yield;
*/
buf = MAlloc(DVD_WRITE_BLKS << BLK_SIZE_BITS);
FBlkRead(f, buf, blk, count);
progress1 = 0;
progress1_max = 1;
StrCopy(progress1_desc, "Blanking");
// BlkDevLock(bd);
AHCIPortWait(bd->port_num, tS + 2);
AHCIAtapiBlank(bd);
bd->flags |= BDF_LAST_WAS_WRITE;
AHCIAtapiModeWriteSelect(bd);
StrCopy(progress1_desc, "Writing");
AHCIAtapiBlksWrite(bd, buf, blk / spc, (count + spc - 1) / spc, FALSE);
progress1++;
/*
while (count > 0)
{
// if (count > DVD_WRITE_BLKS)
// n = DVD_WRITE_BLKS;
// else
n = count;
// if (n > bd->max_writes)
// n = bd->max_writes;
// if (d->out_buf & 1)
// buf = d->buf1;
// else
buf = d->buf0;
while (d->in_buf <= d->out_buf)
Yield;
"AHCIAtapiBlksWrite(bd, 0x%0X, 0x%0X, %d, FALSE);\n", buf, blk / spc, (n + spc - 1) / spc;
AHCIAtapiBlksWrite(bd, buf, blk / spc, (n + spc - 1) / spc, FALSE);
d->out_buf++;
count -= n;
blk += n;
progress1 += n;
}
*/
AHCIAtapiSync(bd);
progress1 = 0;
progress1_max = 2;
StrCopy(progress1_desc, "Closing track");
AHCIAtapiClose(bd, 0x100, 0xFF); //Close track
progress1++;
AHCIAtapiSync(bd);
StrCopy(progress1_desc, "Closing session");
AHCIAtapiClose(bd, 0x200); //close disk
progress1++;
AHCIAtapiSync(bd);
if (media_type == MT_DVD)
{
AHCIAtapiClose(bd, 0x300);
AHCIAtapiSync(bd);
}
*progress1_desc = 0;
progress1 = progress1_max = 0;
bd->flags &= ~BDF_READ_ONLY_OVERRIDE;
BlkDevUnlock(bd);
// Free(d->buf0);
// Free(d->buf1);
Free(in_name2);
Free(in_name3);
Free(d);
}