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, %d, %d);", i * spc, spc; BlkRead(drive, iso, i * spc, spc); // D(iso); // Sleep(3000); 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_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, "ZenithOS RedSea") || !StrCompare(iso->publisher_id, "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); 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; } FClose(f); Free(buf); Free(out_name2); } class CDualBuf { U8 *buf0, *buf1; I64 in_buf, out_buf, count; U8 *filename; CBlkDev *dvd_bd; }; 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 > COPY_BUF_BLKS) n = COPY_BUF_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 i, 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->type == BDT_ATA || bd2->type == BDT_ATAPI) && bd2->base0 == bd->base0) { PrintErr("Can't burn CD/DVD on same ATA controller 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(COPY_BUF_BLKS << BLK_SIZE_BITS); d->buf1 = MAlloc(COPY_BUF_BLKS << BLK_SIZE_BITS); d->count = count; task = Spawn(&DVDImageWriteTask, d, "Write CD/DVD"); while (d->in_buf <= d->out_buf) Yield; BlkDevLock(bd); // IDEATAPIWaitReady(bd, 0); progress1 = 0; progress1_max = count; StrCopy(progress1_desc, "Writing"); while (count > 0) { if (count > COPY_BUF_BLKS) n = COPY_BUF_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; IDEATAPIWriteBlks(bd, buf, blk / spc, (n + spc - 1) / spc); d->out_buf++; count -= n; blk += n; progress1 += n; } IDEATAPISync(bd); progress1 = 0; progress1_max = 2; StrCopy(progress1_desc, "Closing"); for (i = 0; i < 2; i++) { IDEATAPIClose(bd, 0x100, i); //Close tracks progress1++; } IDEATAPISync(bd); IDEATAPIClose(bd, 0x200); //close disk IDEATAPISync(bd); if (media_type == MT_DVD) { IDEATAPIClose(bd, 0x300); IDEATAPISync(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); }