//ISO1 is ISO9660 //ISO2 is ISO13490 //ISO3 is ISO13346 Bool ISOInit(CDrv *dv,I64 blk) { CBlkDev *bd=dv->bd; I64 spc=bd->blk_size>>BLK_SIZE_BITS,i=blk/spc,drv_offset=0; CISO1PriDesc *iso=MAlloc(bd->blk_size); CISO1DirEntry *de; Bool unlock,res=FALSE; U8 buf[8]; try { unlock=DrvLock(dv); dv->fs_type=FSt_ISO9660; dv->spc=spc; dv->data_area=dv->root_clus=dv->drv_offset=bd->drv_offset=dv->size=0; while (TRUE) { dv->size=MaxI64(dv->size,(i+1)*spc); BlkRead(dv,iso,i*spc,spc); buf[0](U32)=iso->id[0](U32); buf[4](U16)=iso->id[4](U8); switch (LstMatch(buf,"CD001\0CDW02\0BEA01\0BOOT2\0NSR02\0NSR03\0TEA01\0", LMF_EXACT)) { case 0: switch (iso->type) { case ISO1T_BOOT_RECORD: drv_offset+=(2*DVD_BLK_SIZE+DVD_BLK_SIZE)/BLK_SIZE; break; case ISO1T_SUPPLEMENTARY_DESC: de=&iso->root_dir_record; dv->size=iso->vol_space_size.little*bd->blk_size>>BLK_SIZE_BITS; if (!StrCmp(iso->publisher_id,"TempleOS RedSea")) { dv->fs_type=FSt_REDSEA; bd->drv_offset=dv->drv_offset=19<<2+drv_offset; bd->max_blk=dv->size-1; dv->size-=bd->drv_offset; RedSeaInit(dv); } else dv->root_clus=de->loc.little; res=TRUE; goto di_done; case ISO1T_TERMINATOR: throw('Drv'); } break; default: //Its normal for ISO13346 to read NULL blk as terminator PrintErr("File System Not Supported\n"); throw('Drv'); } i++; } di_done: Free(iso); if (unlock) DrvUnlock(dv); } catch { dv->fs_type=FSt_ISO9660; dv->spc=spc; dv->drv_offset=bd->drv_offset=dv->data_area=dv->root_clus=0; Free(iso); if (unlock) DrvUnlock(dv); } return res; } U0 DVDImageRead(U8 dvd_drv_let,U8 *out_name) {//Read entire CD/DVD image into ISO file. CDrv *dv=Let2Drv(dvd_drv_let); CBlkDev *bd=dv->bd; U8 *buf=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS), *out_name2=ExtDft(out_name,"ISO"); CFile *f=FOpen(out_name2,"w"); I64 n,spc=bd->blk_size>>BLK_SIZE_BITS,blk=0,cnt,retry; BlkDevInit(bd); if (bd->type!=BDT_ATAPI) throw('BlkDev'); if (!out_name) out_name=blkdev.dft_iso_filename; cnt=CeilU64(dv->size,spc); while (cnt>0) { if (cnt>COPY_BUF_BLKS) n=COPY_BUF_BLKS; else n=cnt; if (n>bd->max_reads) n=bd->max_reads; retry=4; while (--retry) if (ATAPIReadBlks2(bd,tS+7.0+0.004*n/spc,buf,blk/spc,n/spc,TRUE)) //n is 0x800 if max_reads. Up to 8 additional seconds break; if (!retry) ATAPIReadBlks2(bd,0,buf,blk/spc,n/spc,TRUE); FBlkWrite(f,buf,blk,n); cnt-=n; blk+=n; } FClose(f); Free(buf); Free(out_name2); } class CDualBuf { U8 *buf0,*buf1; I64 in_buf,out_buf,cnt; U8 *filename; CBlkDev *dvd_bd; }; U0 DVDImageWriteTask(CDualBuf *d) { U8 *buf; I64 n,blk=0,cnt=d->cnt; CFile *f; if (FileAttr(d->filename)&RS_ATTR_CONTIGUOUS) f=FOpen(d->filename,"rc"); else f=FOpen(d->filename,"r"); while (cnt>0) { if (cnt>COPY_BUF_BLKS) n=COPY_BUF_BLKS; else n=cnt; 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++; cnt-=n; blk+=n; } FClose(f); } U0 DVDImageWrite(U8 dvd_drv_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,cnt; CDrv *dv=Let2Drv(dvd_drv_let); CBlkDev *bd=dv->bd,*bd2; CTask *task; CFile *f; if (!in_name) in_name=blkdev.dft_iso_filename; in_name3=ExtDft(in_name,"ISO"); in_name2=FileNameAbs(in_name3); f=FOpen(in_name2,"r"); if (!f) { Free(d); return; } cnt=(FSize(f)+BLK_SIZE-1)>>BLK_SIZE_BITS; FClose(f); if (bd->type!=BDT_ATAPI) throw('BlkDev'); bd2=Let2BlkDev(*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 (dv->size<cnt) dv->size=cnt; 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->cnt=cnt; task=Spawn(&DVDImageWriteTask,d,"Write CD/DVD"); while (d->in_buf<=d->out_buf) Yield; BlkDevLock(bd); ATAPIWaitReady(bd,0); progress1=0; progress1_max=cnt; StrCpy(progress1_desc,"Writing"); while (cnt>0) { if (cnt>COPY_BUF_BLKS) n=COPY_BUF_BLKS; else n=cnt; 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; ATAPIWriteBlks(bd,buf,blk/spc,(n+spc-1)/spc); d->out_buf++; cnt-=n; blk+=n; progress1+=n; } ATAPISync(bd); progress1=0; progress1_max=2; StrCpy(progress1_desc,"Closing"); for (i=0;i<2;i++) { ATAPIClose(bd,0x100,i); //Close tracks progress1++; } ATAPISync(bd); ATAPIClose(bd,0x200); //close disk ATAPISync(bd); if (media_type==MT_DVD) { ATAPIClose(bd,0x300); ATAPISync(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); }