Initial (manual) import
This commit is contained in:
1 parent
f39611c506
commit
895fe109de
661 files changed
+245862
No files matched your search
@@ -0,0 +1,611 @@
|
||||
U0 ATABlkSel(CBlkDev *bd,I64 blk,I64 cnt)
|
||||
{
|
||||
if (bd->type!=BDT_ATAPI && bd->base1)
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x8);
|
||||
if (bd->flags & BDF_EXT_SIZE) { //48 Bit LBA?
|
||||
OutU8(bd->base0+ATAR0_NSECT,cnt.u8[1]);
|
||||
OutU8(bd->base0+ATAR0_SECT,blk.u8[3]);
|
||||
OutU8(bd->base0+ATAR0_LCYL,blk.u8[4]);
|
||||
OutU8(bd->base0+ATAR0_HCYL,blk.u8[5]);
|
||||
OutU8(bd->base0+ATAR0_NSECT,cnt);
|
||||
OutU8(bd->base0+ATAR0_SECT,blk);
|
||||
OutU8(bd->base0+ATAR0_LCYL,blk.u8[1]);
|
||||
OutU8(bd->base0+ATAR0_HCYL,blk.u8[2]);
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
} else { //28 Bit LBA
|
||||
OutU8(bd->base0+ATAR0_NSECT,cnt);
|
||||
OutU8(bd->base0+ATAR0_SECT,blk);
|
||||
OutU8(bd->base0+ATAR0_LCYL,blk.u8[1]);
|
||||
OutU8(bd->base0+ATAR0_HCYL,blk.u8[2]);
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4|blk.u8[3]);
|
||||
}
|
||||
}
|
||||
|
||||
Bool ATAWaitNotBUSY(CBlkDev *bd,F64 timeout)
|
||||
{
|
||||
I64 i;
|
||||
do {
|
||||
for (i=0;i<3;i++)
|
||||
if (!(InU8(bd->base0+ATAR0_STAT)&ATAS_BSY))
|
||||
return TRUE;
|
||||
Yield;
|
||||
} while (!(0<timeout<tS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool ATAWaitDRQ(CBlkDev *bd,F64 timeout)
|
||||
{
|
||||
I64 i;
|
||||
do {
|
||||
for (i=0;i<3;i++)
|
||||
if (InU8(bd->base0+ATAR0_STAT)&ATAS_DRQ)
|
||||
return TRUE;
|
||||
Yield;
|
||||
} while (!(0<timeout<tS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool ATANop(CBlkDev *bd,F64 timeout)
|
||||
{
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_FEAT,0);
|
||||
OutU8(bd->base0+ATAR0_CMD,ATA_NOP);
|
||||
return ATAWaitNotBUSY(bd,timeout);
|
||||
}
|
||||
|
||||
U0 ATACmd(CBlkDev *bd,U8 cmd)
|
||||
{
|
||||
OutU8(bd->base0+ATAR0_FEAT,0);
|
||||
OutU8(bd->base0+ATAR0_CMD,cmd);
|
||||
bd->last_time=tS;
|
||||
PortNop;
|
||||
}
|
||||
|
||||
Bool ATAGetRes(CBlkDev *bd,F64 timeout,U8 *buf,I64 cnt,
|
||||
I64 _avail,Bool one_read)
|
||||
{
|
||||
I64 avail,overflow;
|
||||
bd->flags&=~BDF_LAST_WAS_WRITE;
|
||||
MemSet(buf,0,cnt);
|
||||
while (cnt>0) {
|
||||
if (!ATAWaitDRQ(bd,timeout))
|
||||
return FALSE;
|
||||
if (_avail)
|
||||
avail=_avail;
|
||||
else
|
||||
avail=InU8(bd->base0+ATAR0_HCYL)<<8+InU8(bd->base0+ATAR0_LCYL);
|
||||
if (avail) {
|
||||
if (avail>cnt) {
|
||||
overflow=avail-cnt;
|
||||
avail=cnt;
|
||||
} else
|
||||
overflow=0;
|
||||
if (avail&2)
|
||||
RepInU16(buf,avail>>1,bd->base0+ATAR0_DATA);
|
||||
else
|
||||
RepInU32(buf,avail>>2,bd->base0+ATAR0_DATA);
|
||||
cnt-=avail;
|
||||
buf+=avail;
|
||||
while (overflow>0) {
|
||||
InU16(bd->base0+ATAR0_DATA);
|
||||
overflow-=2;
|
||||
if (0<timeout<tS)
|
||||
return FALSE;
|
||||
}
|
||||
if (one_read)
|
||||
break;
|
||||
} else
|
||||
Yield;
|
||||
}
|
||||
return ATAWaitNotBUSY(bd,timeout);
|
||||
}
|
||||
|
||||
Bool ATAPIWritePktWord(CBlkDev *bd,F64 timeout,...)
|
||||
{
|
||||
I64 i;
|
||||
for (i=0;i<argc;i++) {
|
||||
if (!ATAWaitDRQ(bd,timeout))
|
||||
return FALSE;
|
||||
OutU16(bd->base0+ATAR0_DATA,EndianU16(argv[i]));
|
||||
bd->last_time=tS;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool ATAPISetMaxSpeed(CBlkDev *bd)
|
||||
{
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,0);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0xBB00,0xFFFF,0xFFFF,0,0,0);
|
||||
return ATAWaitNotBUSY(bd,0);
|
||||
}
|
||||
|
||||
Bool ATAPISeek(CBlkDev *bd,I64 native_blk)
|
||||
{
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,0);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x2B00,native_blk>>16,native_blk,0,0,0);
|
||||
return ATAWaitNotBUSY(bd,0);
|
||||
}
|
||||
|
||||
Bool ATAPIStartStop(CBlkDev *bd,F64 timeout,Bool start)
|
||||
{
|
||||
I64 i;
|
||||
if (start)
|
||||
i=0x100;
|
||||
else
|
||||
i=0;
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
//Start/Stop
|
||||
if (ATAPIWritePktWord(bd,timeout,0x1B00,0,i,0,0,0))
|
||||
return ATAWaitNotBUSY(bd,timeout);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 ATAGetDevId(CBlkDev *bd,F64 timeout,Bool keep_id_record)
|
||||
{
|
||||
I64 res=BDT_NULL;
|
||||
U16 *id_record=NULL;
|
||||
if (bd->type!=BDT_ATAPI && bd->base1)
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x8);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
ATACmd(bd,ATA_ID_DEV);
|
||||
if (ATAWaitNotBUSY(bd,timeout)) {
|
||||
if (InU8(bd->base0+ATAR0_STAT)&ATAS_ERR)
|
||||
res=BDT_ATAPI;
|
||||
else {
|
||||
id_record=ACAlloc(512);
|
||||
if (ATAGetRes(bd,timeout,id_record,512,512,FALSE))
|
||||
res=BDT_ATA;
|
||||
else {
|
||||
Free(id_record);
|
||||
id_record=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (keep_id_record) {
|
||||
Free(bd->dev_id_record);
|
||||
bd->dev_id_record=id_record;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 ATAReadNativeMax(CBlkDev *bd,F64 timeout)
|
||||
{//Returns zero on err
|
||||
I64 res=0;
|
||||
Bool okay=TRUE;
|
||||
if (bd->type==BDT_ATAPI) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
ATACmd(bd,ATA_DEV_RST);
|
||||
if (!ATAWaitNotBUSY(bd,0))
|
||||
okay=FALSE;
|
||||
} else {
|
||||
while (InU8(bd->base0+ATAR0_STAT) & ATAS_BSY) {
|
||||
if (bd->flags&BDF_LAST_WAS_WRITE)
|
||||
OutU16(bd->base0+ATAR0_DATA,0);
|
||||
else
|
||||
InU16(bd->base0+ATAR0_DATA);
|
||||
Yield;
|
||||
if (0<timeout<tS)
|
||||
return FALSE;
|
||||
}
|
||||
if (ATAGetDevId(bd,timeout,TRUE)==BDT_NULL)
|
||||
okay=FALSE;
|
||||
else
|
||||
BEqu(&bd->flags,BDf_EXT_SIZE,Bt(&bd->dev_id_record[86],10));
|
||||
}
|
||||
if (okay) {
|
||||
if (bd->flags & BDF_EXT_SIZE && bd->base1) {
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x8);
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
ATACmd(bd,ATA_READ_NATIVE_MAX_EXT);
|
||||
if (ATAWaitNotBUSY(bd,timeout)) {
|
||||
res.u8[0]=InU8(bd->base0+ATAR0_SECT);
|
||||
res.u8[1]=InU8(bd->base0+ATAR0_LCYL);
|
||||
res.u8[2]=InU8(bd->base0+ATAR0_HCYL);
|
||||
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x80);
|
||||
res.u8[3]=InU8(bd->base0+ATAR0_SECT);
|
||||
res.u8[4]=InU8(bd->base0+ATAR0_LCYL);
|
||||
res.u8[5]=InU8(bd->base0+ATAR0_HCYL);
|
||||
|
||||
if (res>>24==res&0xFFFFFF) {//Kludge to make QEMU work
|
||||
bd->flags&=~BDF_EXT_SIZE;
|
||||
res&=0xFFFFFF;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (bd->type!=BDT_ATAPI && bd->base1)
|
||||
OutU8(bd->base1+ATAR1_CTRL,0x8);
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
ATACmd(bd,ATA_READ_NATIVE_MAX);
|
||||
if (ATAWaitNotBUSY(bd,timeout)) {
|
||||
res.u8[0]=InU8(bd->base0+ATAR0_SECT);
|
||||
res.u8[1]=InU8(bd->base0+ATAR0_LCYL);
|
||||
res.u8[2]=InU8(bd->base0+ATAR0_HCYL);
|
||||
res.u8[3]=InU8(bd->base0+ATAR0_SEL) & 0xF;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bd->max_blk=res;
|
||||
}
|
||||
|
||||
I64 ATAPIReadCapacity(CBlkDev *bd,I64 *_blk_size=NULL)
|
||||
{//Supposedly this can return a res +/- 75 sects.
|
||||
//Error might just be for music.
|
||||
Bool unlock=BlkDevLock(bd);
|
||||
U32 buf[2];
|
||||
if (ATAWaitNotBUSY(bd,0)) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,8);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x2500,0,0,0,0,0);
|
||||
if (!ATAGetRes(bd,0,buf,8,0,TRUE))
|
||||
buf[0]=buf[1]=0;
|
||||
} else
|
||||
buf[0]=buf[1]=0;
|
||||
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
if (_blk_size) *_blk_size=EndianU32(buf[1]);
|
||||
return EndianU32(buf[0]);
|
||||
}
|
||||
|
||||
CATAPITrack *ATAPIReadTrackInfo(CBlkDev *bd,I64 blk)
|
||||
{
|
||||
CATAPITrack *res=CAlloc(sizeof(CATAPITrack));
|
||||
Bool unlock=BlkDevLock(bd);
|
||||
if (ATAWaitNotBUSY(bd,0)) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,sizeof(CATAPITrack)&0xFF);
|
||||
OutU8(bd->base0+ATAR0_HCYL,sizeof(CATAPITrack)>>8);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x5200,blk.u16[1],blk.u16[0],
|
||||
(sizeof(CATAPITrack)&0xFF00)>>8,(sizeof(CATAPITrack)&0x00FF)<<8,0);
|
||||
if (!ATAGetRes(bd,0,res,sizeof(CATAPITrack),0,TRUE)) {
|
||||
Free(res);
|
||||
res=NULL;
|
||||
}
|
||||
} else {
|
||||
Free(res);
|
||||
res=NULL;
|
||||
}
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool ATAInit(CBlkDev *bd)
|
||||
{
|
||||
Bool unlock=BlkDevLock(bd),okay=FALSE;
|
||||
|
||||
if (bd->type==BDT_ATAPI)
|
||||
bd->flags&=~BDF_EXT_SIZE;
|
||||
else
|
||||
bd->flags|=BDF_EXT_SIZE;
|
||||
|
||||
if (ATAReadNativeMax(bd,tS+0.1)) {
|
||||
ATABlkSel(bd,bd->max_blk,0);
|
||||
if (bd->flags&BDF_EXT_SIZE)
|
||||
ATACmd(bd,ATA_SET_MAX_EXT);
|
||||
else
|
||||
ATACmd(bd,ATA_SET_MAX);
|
||||
if (ATAWaitNotBUSY(bd,0)) {
|
||||
okay=TRUE;
|
||||
if (bd->type==BDT_ATAPI) {
|
||||
if (ATAPIStartStop(bd,0,TRUE)) {
|
||||
if(!ATAPISetMaxSpeed(bd))
|
||||
okay=FALSE;
|
||||
} else
|
||||
okay=FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
return okay;
|
||||
}
|
||||
|
||||
Bool ATAPIWaitReady(CBlkDev *bd,F64 timeout)
|
||||
{
|
||||
do {
|
||||
if (!ATAWaitNotBUSY(bd,timeout) ||
|
||||
!ATANop(bd,timeout) ||
|
||||
!ATAPIStartStop(bd,timeout,TRUE))
|
||||
return FALSE;
|
||||
if (InU8(bd->base0+ATAR0_STAT) & ATAS_DRDY &&
|
||||
!InU8(bd->base0+ATAR0_FEAT));
|
||||
return TRUE;
|
||||
ATAInit(bd);
|
||||
Yield;
|
||||
} while (!(0<timeout<tS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 ATAReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
I64 retries=3;
|
||||
Bool unlock=BlkDevLock(bd);
|
||||
|
||||
retry:
|
||||
ATABlkSel(bd,blk,cnt);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
ATACmd(bd,ATA_READ_MULTI_EXT);
|
||||
else
|
||||
ATACmd(bd,ATA_READ_MULTI);
|
||||
if (!ATAGetRes(bd,tS+1.0,buf,cnt*bd->blk_size,BLK_SIZE,FALSE)) {
|
||||
if (retries--) {
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
goto retry;
|
||||
} else
|
||||
throw('BlkDev');
|
||||
}
|
||||
|
||||
blkdev.read_cnt+=(cnt*bd->blk_size)>>BLK_SIZE_BITS;
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
}
|
||||
|
||||
I64 ATAProbe(I64 base0,I64 base1,I64 unit)
|
||||
{
|
||||
CBlkDev bd;
|
||||
MemSet(&bd,0,sizeof(CBlkDev));
|
||||
bd.type=BDT_ATAPI;
|
||||
bd.base0=base0;
|
||||
bd.base1=base1;
|
||||
bd.unit=unit;
|
||||
bd.blk_size=DVD_BLK_SIZE;
|
||||
return ATAGetDevId(&bd,tS+0.1,FALSE);
|
||||
}
|
||||
|
||||
Bool ATAPIReadBlks2(CBlkDev *bd,F64 timeout,U8 *buf,
|
||||
I64 native_blk, I64 cnt,Bool lock)
|
||||
{
|
||||
Bool res=FALSE,unlock;
|
||||
if (cnt<=0)
|
||||
return FALSE;
|
||||
if (lock)
|
||||
unlock=BlkDevLock(bd);
|
||||
if (ATAPIWaitReady(bd,timeout)) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);
|
||||
OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
if (ATAPIWritePktWord(bd,timeout,0xA800,
|
||||
native_blk.u16[1],native_blk,cnt.u16[1],cnt,0) &&
|
||||
ATAGetRes(bd,timeout,buf,cnt*bd->blk_size,0,FALSE)) {
|
||||
blkdev.read_cnt+=(cnt*bd->blk_size)>>BLK_SIZE_BITS;
|
||||
res=TRUE;
|
||||
}
|
||||
}
|
||||
// ATAPIStartStop(bd,0,FALSE);
|
||||
if (lock && unlock) BlkDevUnlock(bd);
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 ATAPIReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
CDrv *dv=Let2Drv(bd->first_drv_let);
|
||||
I64 retry,spc=bd->blk_size>>BLK_SIZE_BITS,n,blk2,
|
||||
l2=bd->max_reads<<1+spc<<1;
|
||||
U8 *dvd_buf=MAlloc(l2<<BLK_SIZE_BITS);
|
||||
if (cnt>0) {
|
||||
if (blk<=bd->max_reads)
|
||||
blk2=0;
|
||||
else
|
||||
blk2=FloorU64(blk-bd->max_reads,spc);
|
||||
if (blk2+l2>dv->size+dv->drv_offset)
|
||||
l2=dv->size+dv->drv_offset-blk2;
|
||||
n=(l2+spc-1)/spc;
|
||||
|
||||
retry=4;
|
||||
while (--retry)
|
||||
if (ATAPIReadBlks2(bd,tS+7.0+0.004*n,dvd_buf,blk2/spc,n,TRUE))
|
||||
//n is 0x800 if max_reads. Up to 8 additional seconds
|
||||
break;
|
||||
if (!retry)
|
||||
ATAPIReadBlks2(bd,0,dvd_buf,blk2/spc,n,TRUE);
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
DskCacheAdd(dv,dvd_buf,blk2,n*spc);
|
||||
MemCpy(buf,dvd_buf+(blk-blk2)<<BLK_SIZE_BITS,cnt<<BLK_SIZE_BITS);
|
||||
}
|
||||
Free(dvd_buf);
|
||||
}
|
||||
|
||||
Bool ATARBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
I64 n;
|
||||
CBlkDev *bd=dv->bd;
|
||||
while (cnt>0) {
|
||||
n=cnt;
|
||||
if (n>bd->max_reads)
|
||||
n=bd->max_reads;
|
||||
if (bd->type==BDT_ATAPI)
|
||||
ATAPIReadBlks(bd,buf,blk,n);
|
||||
else
|
||||
ATAReadBlks(bd,buf,blk,n);
|
||||
buf+=n<<BLK_SIZE_BITS;
|
||||
blk+=n;
|
||||
cnt-=n;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U0 ATAWriteBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)
|
||||
{//For low level disk access.
|
||||
//Use WBlks() instead.
|
||||
I64 i,U32s_avail,sects_avail,retries=3;
|
||||
F64 timeout;
|
||||
Bool unlock=BlkDevLock(bd);
|
||||
retry:
|
||||
ATABlkSel(bd,blk,cnt);
|
||||
if (bd->flags&BDF_EXT_SIZE)
|
||||
ATACmd(bd,ATA_WRITE_MULTI_EXT);
|
||||
else
|
||||
ATACmd(bd,ATA_WRITE_MULTI);
|
||||
bd->flags|=BDF_LAST_WAS_WRITE;
|
||||
while (cnt>0) {
|
||||
timeout=tS+1.0;
|
||||
while (TRUE) {
|
||||
i=InU8(bd->base0+ATAR0_STAT);
|
||||
if (!(i & ATAS_DRDY)||!(i & ATAS_DRQ)) {
|
||||
Yield;
|
||||
} else
|
||||
break;
|
||||
if (/* i&ATAS_ERR||*/ tS>timeout) {
|
||||
if (retries--) {
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
goto retry;
|
||||
} else
|
||||
throw('BlkDev');
|
||||
}
|
||||
}
|
||||
sects_avail=1;
|
||||
U32s_avail=sects_avail<<BLK_SIZE_BITS>>2;
|
||||
RepOutU32(buf,U32s_avail,bd->base0+ATAR0_DATA);
|
||||
buf+=U32s_avail<<2;
|
||||
cnt-=sects_avail;
|
||||
retries=3;
|
||||
}
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
}
|
||||
|
||||
Bool ATAPISync(CBlkDev *bd)
|
||||
{
|
||||
Bool okay=TRUE;
|
||||
if (!ATAWaitNotBUSY(bd,0))
|
||||
okay=FALSE;
|
||||
else {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,0);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x3500,0,0,0,0,0);
|
||||
if (!ATAWaitNotBUSY(bd,0))
|
||||
okay=FALSE;
|
||||
}
|
||||
return okay;
|
||||
}
|
||||
|
||||
U0 ATAPIClose(CBlkDev *bd,I64 close_field=0x200,I64 track=0)
|
||||
{//0x200 CD/DVD part 1
|
||||
// 0x300 DVD part 2
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,0);
|
||||
OutU8(bd->base0+ATAR0_HCYL,0);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x5B00,close_field,track,0,0,0);
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
}
|
||||
|
||||
U0 ATAPIWriteBlks(CBlkDev *bd,U8 *buf, I64 native_blk, I64 cnt)
|
||||
{
|
||||
I64 U32s_avail;
|
||||
U8 *buf2;
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
ATAPISeek(bd,native_blk);
|
||||
|
||||
OutU8(bd->base0+ATAR0_FEAT,0);
|
||||
OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);
|
||||
OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_CMD,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0x0400,native_blk.u16[1],native_blk,cnt.u16[1],cnt,0);
|
||||
bd->flags|=BDF_LAST_WAS_WRITE;
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
|
||||
ATAPISeek(bd,native_blk);
|
||||
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);
|
||||
else
|
||||
OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);
|
||||
OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);
|
||||
OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);
|
||||
ATACmd(bd,ATA_PACKET);
|
||||
ATAPIWritePktWord(bd,0,0xAA00,native_blk.u16[1],native_blk,cnt.u16[1],cnt,0);
|
||||
buf2=buf+bd->blk_size*cnt;
|
||||
while (buf<buf2) {
|
||||
ATAWaitDRQ(bd,0);
|
||||
U32s_avail=(InU8(bd->base0+ATAR0_HCYL)<<8+InU8(bd->base0+ATAR0_LCYL))>>2;
|
||||
if (buf+U32s_avail<<2>buf2)
|
||||
U32s_avail=(buf2-buf)>>2;
|
||||
if (U32s_avail) {
|
||||
RepOutU32(buf,U32s_avail,bd->base0+ATAR0_DATA);
|
||||
buf+=U32s_avail<<2;
|
||||
blkdev.write_cnt+=U32s_avail>>(BLK_SIZE_BITS-2);
|
||||
}
|
||||
}
|
||||
ATAWaitNotBUSY(bd,0);
|
||||
}
|
||||
|
||||
Bool ATAWBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
I64 n,spc;
|
||||
CBlkDev *bd=dv->bd;
|
||||
Bool unlock;
|
||||
spc=bd->blk_size>>BLK_SIZE_BITS;
|
||||
if (bd->type==BDT_ATAPI) {
|
||||
unlock=BlkDevLock(bd);
|
||||
ATAPIWaitReady(bd,0);
|
||||
}
|
||||
while (cnt>0) {
|
||||
n=cnt;
|
||||
if (n>bd->max_writes)
|
||||
n=bd->max_writes;
|
||||
if (bd->type==BDT_ATAPI)
|
||||
ATAPIWriteBlks(bd,buf,blk/spc,(n+spc-1)/spc);
|
||||
else
|
||||
ATAWriteBlks(bd,buf,blk,n);
|
||||
buf+=n<<BLK_SIZE_BITS;
|
||||
blk+=n;
|
||||
cnt-=n;
|
||||
blkdev.write_cnt+=n;
|
||||
}
|
||||
if (bd->type==BDT_ATAPI) {
|
||||
ATAPISync(bd);
|
||||
// ATAPIStartStop(bd,0,FALSE);
|
||||
if (unlock) BlkDevUnlock(bd);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
Bool BootDVDProbe(CBlkDev *bd)
|
||||
{
|
||||
U8 *img=CAlloc(DVD_BLK_SIZE);
|
||||
I64 i;
|
||||
Bool res=FALSE;
|
||||
"Port: %04X,%04X Unit: %02X ",bd->base0,bd->base1,bd->unit;
|
||||
if (ATAProbe(bd->base0,bd->base1,bd->unit)==BDT_ATAPI) {
|
||||
" ATAPI";
|
||||
if (ATAPIStartStop(bd,tS+5.0,TRUE)) {
|
||||
" Started";
|
||||
for (i=0;i<2;i++) {//Retry
|
||||
if (ATAPIReadBlks2(bd,tS+7.0,img,sys_boot_blk,1,FALSE)) {
|
||||
if ((img+sys_boot_src.u16[1]<<BLK_SIZE_BITS)(CKernel *)
|
||||
->compile_time==sys_compile_time) {
|
||||
" Found\n";
|
||||
return TRUE;
|
||||
} else
|
||||
" Read";
|
||||
} else
|
||||
" NoRead";
|
||||
}
|
||||
}
|
||||
}
|
||||
" Nope\n";
|
||||
Free(img);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool BootDVDProbeAll(CBlkDev *bd)
|
||||
{
|
||||
I64 d1,d2,i,j,k;
|
||||
|
||||
bd->base1=0;
|
||||
for (k=0;k<256;k++) {
|
||||
i=-1;
|
||||
while (TRUE) {
|
||||
j=PCIClassFind(0x010100+k,++i);
|
||||
if (j<0)
|
||||
break;
|
||||
"Subcode:0x%X Bus:0x%X Dev:0x%X Fun:0x%X\n",k,j.u8[2],j.u8[1],j.u8[0];
|
||||
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x10);
|
||||
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x14);
|
||||
if (d1&1 && d2&1) {
|
||||
if (bd->base0=d1&~7) {
|
||||
bd->unit=0;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
bd->unit=1;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x18);
|
||||
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x1C);
|
||||
if (d1&1 && d2&1) {
|
||||
if (bd->base0=d1&~7) {
|
||||
bd->unit=0;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
bd->unit=1;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d1=0x1F0;
|
||||
d2=0x3F6;
|
||||
if (bd->base0=d1&~7) {
|
||||
bd->unit=0;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
bd->unit=1;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
d1=0x170;
|
||||
d2=0x376;
|
||||
if (bd->base0=d1&~7) {
|
||||
bd->unit=0;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
bd->unit=1;
|
||||
if (BootDVDProbe(bd))
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
U0 ATARepEntry(I64 base0,I64 base1,I64 unit,U8 *msg,
|
||||
CATARep **_head,I64 *num_hints)
|
||||
{
|
||||
I64 type;
|
||||
base0&=-8;
|
||||
base1&=-4;
|
||||
CATARep *tmpha;
|
||||
if (type=ATAProbe(base0,base1,unit)) {
|
||||
*num_hints+=1;
|
||||
"\n$$PURPLE$$ $$BT+X,\"%d\",LM=\"%d\\n\"$$$$FG$$$$LM,4$$",*num_hints,*num_hints;
|
||||
if (type==BDT_ATA)
|
||||
"$$RED$$Hard Drive $$LTBLUE$$ATA ";
|
||||
else
|
||||
"$$RED$$CD/DVD Drive $$LTBLUE$$ATAPI ";
|
||||
"%s$$FG$$\n",msg;
|
||||
if (base0==blkdev.ins_base0 && unit==blkdev.ins_unit)
|
||||
"$$PURPLE$$(Drive originally installed from.)$$FG$$\n";
|
||||
"Base0:0x%04X Base1:0x%04X Unit:%d$$LM,0$$\n",
|
||||
base0,base1,unit;
|
||||
if (_head) {
|
||||
tmpha=CAlloc(sizeof(CATARep));
|
||||
tmpha->next=*_head;
|
||||
*_head=tmpha;
|
||||
tmpha->num=*num_hints;
|
||||
tmpha->type=type;
|
||||
tmpha->base0=base0;
|
||||
tmpha->base1=base1;
|
||||
tmpha->unit=unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bool ATARepExitAllApplications()
|
||||
{
|
||||
"\nWe're going to probe hardware.\n"
|
||||
"$$RED$$Exit all other applications.$$FG$$\n"
|
||||
"Press '$$PURPLE$$p$$FG$$' to probe or '$$PURPLE$$s$$FG$$' to skip.\n";
|
||||
if (ToUpper(GetChar(,FALSE))=='S')
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
public I64 ATARep(Bool pmt=TRUE,Bool just_ide=FALSE,CATARep **_head=NULL)
|
||||
{//Report possible ATA devices by probing. Hard disks and CD/DVDs.
|
||||
I64 d1,d2,i,j,k,cnt=0,unlock_flags=0,num_hints=0;
|
||||
#assert BLKDEVS_NUM<=64
|
||||
if (_head) *_head=NULL;
|
||||
|
||||
if (pmt && ATARepExitAllApplications)
|
||||
return 0;
|
||||
|
||||
for (i=0;i<BLKDEVS_NUM;i++)
|
||||
if (blkdev.blkdevs[i].bd_signature==BD_SIGNATURE_VAL)
|
||||
BEqu(&unlock_flags,i,
|
||||
BlkDevLock(&blkdev.blkdevs[i]));
|
||||
|
||||
if (!just_ide)
|
||||
for (k=0;k<256;k++) {
|
||||
i=-1;
|
||||
while (TRUE) {
|
||||
j=PCIClassFind(0x010100+k,++i);
|
||||
if (j<0)
|
||||
break;
|
||||
|
||||
"\nSubcode:0x%X Bus:0x%X Dev:0x%X Fun:0x%X\n",k,j.u8[2],j.u8[1],j.u8[0];
|
||||
cnt++;
|
||||
|
||||
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x10);
|
||||
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x14);
|
||||
if (d1&1 && d2&1) {
|
||||
ATARepEntry(d1,d2,0,"Primary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Primary IDE",_head,&num_hints);
|
||||
} else {
|
||||
d1=0x1F0; d2=0x3F6;
|
||||
ATARepEntry(d1,d2,0,"Primary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Primary IDE",_head,&num_hints);
|
||||
}
|
||||
d1=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x18);
|
||||
d2=PCIReadU32(j.u8[2],j.u8[1],j.u8[0],0x1C);
|
||||
if (d1&1 && d2&1) {
|
||||
ATARepEntry(d1,d2,0,"Secondary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Secondary IDE",_head,&num_hints);
|
||||
} else {
|
||||
d1=0x170; d2=0x376;
|
||||
ATARepEntry(d1,d2,0,"Secondary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Secondary IDE",_head,&num_hints);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cnt) {
|
||||
d1=0x1F0; d2=0x3F6;
|
||||
ATARepEntry(d1,d2,0,"Primary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Primary IDE",_head,&num_hints);
|
||||
|
||||
d1=0x170; d2=0x376;
|
||||
ATARepEntry(d1,d2,0,"Secondary IDE",_head,&num_hints);
|
||||
ATARepEntry(d1,d2,1,"Secondary IDE",_head,&num_hints);
|
||||
}
|
||||
'\n\n';
|
||||
for (i=0;i<BLKDEVS_NUM;i++)
|
||||
if (Bt(&unlock_flags,i))
|
||||
BlkDevUnlock(&blkdev.blkdevs[i]);
|
||||
return num_hints;
|
||||
}
|
||||
|
||||
CATARep *ATARepFind(CATARep *haystack_head,I64 needle_num)
|
||||
{
|
||||
while (haystack_head) {
|
||||
if (haystack_head->num==needle_num)
|
||||
return haystack_head;
|
||||
haystack_head=haystack_head->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CATARep *ATAIDDrvs(CATARep *head,CATARep **_ata_drv,CATARep **_atapi_drv)
|
||||
{//This is for when trying to sort-out main hard drives and CD/DVD drives.
|
||||
CATARep *res=NULL,*tmpha=head,*ata_drv=NULL,*atapi_drv=NULL;
|
||||
CBlkDev *bd;
|
||||
Bool was_silent=Silent,ins_found=FALSE;
|
||||
bd=Let2BlkDev(':',FALSE);
|
||||
Silent(was_silent);
|
||||
while (tmpha) {
|
||||
if (!res && bd && bd->type==tmpha->type) {
|
||||
if (bd->type==BDT_ATAPI &&
|
||||
bd->base0==tmpha->base0 && bd->unit==tmpha->unit)
|
||||
res=atapi_drv=tmpha;
|
||||
else if (bd->type==BDT_ATA && bd->base0==tmpha->base0 &&
|
||||
bd->base1==tmpha->base1 && bd->unit==tmpha->unit)
|
||||
res=ata_drv=tmpha;
|
||||
}
|
||||
if (!res || res->type!=tmpha->type) {
|
||||
if (tmpha->type==BDT_ATA) {
|
||||
if (!ata_drv || tmpha->unit<ata_drv->unit ||
|
||||
tmpha->unit==ata_drv->unit && tmpha->num<ata_drv->num)
|
||||
ata_drv=tmpha;
|
||||
} else if (tmpha->type==BDT_ATAPI) {
|
||||
if (!atapi_drv || !ins_found && (tmpha->unit<atapi_drv->unit ||
|
||||
tmpha->unit==atapi_drv->unit && tmpha->num<atapi_drv->num))
|
||||
atapi_drv=tmpha;
|
||||
}
|
||||
}
|
||||
if (tmpha->type==BDT_ATAPI && bd && bd->type==BDT_ATA &&
|
||||
tmpha->base0==blkdev.ins_base0 && tmpha->unit==blkdev.ins_unit) {
|
||||
if (!ins_found) {
|
||||
atapi_drv=tmpha;
|
||||
ins_found=TRUE;
|
||||
}
|
||||
}
|
||||
tmpha=tmpha->next;
|
||||
}
|
||||
if (_ata_drv) *_ata_drv =ata_drv;
|
||||
if (_atapi_drv) *_atapi_drv=atapi_drv;
|
||||
return res;
|
||||
}
|
||||
|
||||
CBlkDev *ATAMount(U8 first_drv_let,I64 type,I64 base0,I64 base1,I64 unit)
|
||||
{
|
||||
CBlkDev *res;
|
||||
if (0<=first_drv_let-'A'<DRVS_NUM && (type==BDT_ATA || type==BDT_ATAPI) &&
|
||||
0<=unit<=1) {
|
||||
res=BlkDevNextFreeSlot(first_drv_let,type);
|
||||
res->unit=unit;
|
||||
res->base0=base0;
|
||||
res->base1=base1;
|
||||
if (BlkDevAdd(res,,FALSE,FALSE))
|
||||
return res;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
I64 AutoMountIDE()
|
||||
{//Try to mount hard drive and CD/DVD, automatically. (Kernel.Cfg option).
|
||||
//It uses 'C' and 'T' as first drive letters or whatever you set
|
||||
//in config when compiling Kernel.BIN.
|
||||
I64 res=0;
|
||||
CATARep *head=NULL,*ata_drv=NULL,*atapi_drv=NULL,*tmpha;
|
||||
ATARep(FALSE,TRUE,&head);
|
||||
ATAIDDrvs(head,&ata_drv,&atapi_drv);
|
||||
if (ata_drv && ATAMount(blkdev.first_hd_drv_let,BDT_ATA,
|
||||
ata_drv->base0,ata_drv->base1,ata_drv->unit))
|
||||
res++;
|
||||
if (atapi_drv && ATAMount(blkdev.first_dvd_drv_let,BDT_ATAPI,
|
||||
atapi_drv->base0,atapi_drv->base1,atapi_drv->unit))
|
||||
res++;
|
||||
tmpha=head;
|
||||
while (tmpha) {
|
||||
if (tmpha!=ata_drv && tmpha!=atapi_drv) {
|
||||
if (tmpha->type==BDT_ATA && ATAMount(blkdev.first_hd_drv_let,BDT_ATA,
|
||||
tmpha->base0,tmpha->base1,tmpha->unit))
|
||||
res++;
|
||||
else if (tmpha->type==BDT_ATAPI &&
|
||||
ATAMount(blkdev.first_dvd_drv_let,BDT_ATAPI,
|
||||
tmpha->base0,tmpha->base1,tmpha->unit))
|
||||
res++;
|
||||
}
|
||||
tmpha=tmpha->next;
|
||||
}
|
||||
LinkedLstDel(head);
|
||||
blkdev.auto_mount_ide_cnt=res;
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
U0 BlkDevLockFwdingSet(CBlkDev *bd)
|
||||
{ //If two blkdevs on same controller, use just one lock
|
||||
CBlkDev *bd1;
|
||||
I64 i;
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
bd->lock_fwding=Let2BlkDev(*bd->file_dsk_name);
|
||||
break;
|
||||
case BDT_ATA:
|
||||
case BDT_ATAPI:
|
||||
for (i=0;i<BLKDEVS_NUM;i++) {
|
||||
bd1=&blkdev.blkdevs[i];
|
||||
if (bd1->bd_signature==BD_SIGNATURE_VAL && bd!=bd1 &&
|
||||
(bd1->type==BDT_ATAPI || bd1->type==BDT_ATA) &&
|
||||
bd1->base0==bd->base0) {
|
||||
bd->lock_fwding=bd1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
I64 BlkDevAdd(CBlkDev *bd,I64 prt_num=I64_MIN,
|
||||
Bool whole_drv,Bool make_free)
|
||||
{//It will mount just one partition of prt_num>=0.
|
||||
//When repartitioing whole drive, whole_drv=TRUE.
|
||||
I64 i,j,ext_base,offset,res=0,num=0;
|
||||
CDrv *dv;
|
||||
CRedSeaBoot br;
|
||||
CMasterBoot mbr;
|
||||
|
||||
bd->bd_signature=BD_SIGNATURE_VAL;
|
||||
if (make_free)
|
||||
dv=DrvMakeFreeSlot(bd->first_drv_let);
|
||||
else
|
||||
dv=DrvMakeFreeSlot(DrvNextFreeLet(bd->first_drv_let));
|
||||
dv->bd=bd;
|
||||
dv->drv_offset=bd->drv_offset;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
//This is to force creation of a RAM
|
||||
//drive during boot, so it is probably
|
||||
//MAlloced to the same addr and can
|
||||
//be assumed to be already formatted.
|
||||
//If this line is removed, RAM Drives
|
||||
//will be alloced on a just-in-time
|
||||
//basis.
|
||||
if (BlkDevInit(bd))
|
||||
res++;
|
||||
else
|
||||
dv->dv_signature=0;
|
||||
break;
|
||||
case BDT_ATA:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL; //Temporarily validate
|
||||
if (!BlkDevInit(bd))
|
||||
dv->dv_signature=0; //Revoke validation
|
||||
else {
|
||||
dv->dv_signature=0; //Revoke validation
|
||||
if (whole_drv) {
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
//The following read is a test read.
|
||||
//if it hangs, the drive is not supported.
|
||||
ATAReadBlks(bd,&mbr,0,1);
|
||||
break;
|
||||
}
|
||||
offset=0;
|
||||
ext_base=INVALID_CLUSTER;
|
||||
while (prt_num<0 || num<=prt_num) {
|
||||
ATAReadBlks(bd,&mbr,offset,1);
|
||||
if (mbr.signature!=0xAA55)
|
||||
break;
|
||||
j=-1;
|
||||
for (i=0;i<4 && (prt_num<0 || num<=prt_num);i++) {
|
||||
if (mbr.p[i].type) {
|
||||
if (make_free)
|
||||
dv=DrvMakeFreeSlot(bd->first_drv_let+res);
|
||||
else
|
||||
dv=DrvMakeFreeSlot(DrvNextFreeLet(bd->first_drv_let+res));
|
||||
dv->bd=bd;
|
||||
dv->drv_offset=mbr.p[i].offset+offset;
|
||||
dv->size =mbr.p[i].size;
|
||||
switch (mbr.p[i].type) {
|
||||
case MBR_PT_REDSEA:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
RedSeaInit(dv);
|
||||
break;
|
||||
case MBR_PT_FAT32a:
|
||||
case MBR_PT_FAT32b:
|
||||
case MBR_PT_FAT32c:
|
||||
case MBR_PT_FAT32d:
|
||||
case MBR_PT_FAT32e:
|
||||
case MBR_PT_FAT32f:
|
||||
ATAReadBlks(bd,&br,dv->drv_offset,1);
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
if (br.signature==MBR_PT_REDSEA) {
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
RedSeaInit(dv);
|
||||
} else {
|
||||
dv->fs_type=FSt_FAT32;
|
||||
FAT32Init(dv);
|
||||
}
|
||||
break;
|
||||
case MBR_PT_NTFS:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_NTFS;
|
||||
break;
|
||||
case 5:
|
||||
case 15:
|
||||
j=i;
|
||||
break;
|
||||
default:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_UNKNOWN;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
if (Let2BlkDevType(bd->first_drv_let+res)!=bd->type)
|
||||
break;
|
||||
if (j<0)
|
||||
break;
|
||||
if (!mbr.p[j].offset)
|
||||
break;
|
||||
if (ext_base==INVALID_CLUSTER) {
|
||||
offset=mbr.p[j].offset;
|
||||
ext_base=offset;
|
||||
} else
|
||||
offset=mbr.p[j].offset+ext_base;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BDT_ATAPI:
|
||||
dv->dv_signature=DRV_SIGNATURE_VAL;
|
||||
dv->prt_num=num;
|
||||
res++;
|
||||
dv->fs_type=FSt_ISO9660; //Start with this
|
||||
dv->size=0;
|
||||
break;
|
||||
}
|
||||
if (res)
|
||||
BlkDevLockFwdingSet(bd);
|
||||
else
|
||||
BlkDevDel(bd);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool DrvEnable(U8 drv_let,Bool val)
|
||||
{//Can unmount or remount, but not mount the first time.
|
||||
CDrv *dv;
|
||||
if (dv=Let2Drv(drv_let,FALSE))
|
||||
return !LBEqu(&dv->fs_type,FStf_DISABLE,!val);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 SysGetI64()
|
||||
{
|
||||
U8 st[STR_LEN];
|
||||
GetS(st,STR_LEN,FALSE);
|
||||
return Str2I64(st,16);
|
||||
}
|
||||
|
||||
Bool GetBaseUnit(CBlkDev *bd)
|
||||
{
|
||||
I64 ch;
|
||||
Bool probe;
|
||||
#exe {
|
||||
if (kernel_cfg->opts[CFG_DONT_PROBE])
|
||||
StreamPrint("probe=FALSE;");
|
||||
else
|
||||
StreamPrint("probe=TRUE;");
|
||||
};
|
||||
if (!probe || !BootDVDProbeAll(bd)) {
|
||||
"\nDon't worry. This is not a product\n"
|
||||
"registration. TempleOS just needs the\n"
|
||||
"I/O port numbers for the CD/DVD.\n"
|
||||
"\nRetry the ports above or check Windows\n"
|
||||
"system information under I/O ports for\n"
|
||||
"'IDE', 'ATA' or 'SATA'.\n"
|
||||
"In Linux, use 'lspci -v' for ports.\n"
|
||||
"\n\nEnter 4-digit hex I/O Port number.\n"
|
||||
"CD/DVD I/O Port Base0: 0x";
|
||||
bd->base0=SysGetI64;
|
||||
bd->base1=0;
|
||||
bd->unit =0;
|
||||
if (bd->base0) {
|
||||
"\nUnit (0 or 1): ";
|
||||
do ch=GetChar(,FALSE);
|
||||
while (!('0'<=ch<='1'));
|
||||
'' ch;
|
||||
bd->unit=ch-'0';
|
||||
blkdev.dvd_boot_is_good=BootDVDProbe(bd);
|
||||
return TRUE;
|
||||
} else {
|
||||
blkdev.dvd_boot_is_good=FALSE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 BlkDevsInitAll()
|
||||
{
|
||||
CBlkDev *bd;
|
||||
I64 i;
|
||||
blkdev.blkdevs=CAlloc(sizeof(CBlkDev)*BLKDEVS_NUM);
|
||||
blkdev.drvs=CAlloc(sizeof(CDrv)*DRVS_NUM);
|
||||
for (i=0;i<DRVS_NUM;i++)
|
||||
blkdev.let_to_drv[i]=&blkdev.drvs[i];
|
||||
#exe {
|
||||
if (kernel_cfg->opts[CFG_AUTO_MOUNT_IDE])
|
||||
StreamPrint("AutoMountIDE;");
|
||||
StreamPrint("#exe {Option(OPTf_WARN_PAREN,OFF);}");
|
||||
StreamDoc(kernel_cfg->add_dev);
|
||||
StreamPrint("#exe {Option(OPTf_WARN_PAREN,ON);}");
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#define ZERO_BUF_SIZE 2048
|
||||
U0 WZeroBlks(CDrv *dv,I64 blk,I64 cnt)
|
||||
{//Fill blk cnt with zeros in Drv.
|
||||
I64 n;
|
||||
U8 *z=CAlloc(ZERO_BUF_SIZE<<BLK_SIZE_BITS);
|
||||
Bool show_progress;
|
||||
if (cnt>ZERO_BUF_SIZE && dv->bd->type!=BDT_RAM) {
|
||||
progress1=0; progress1_max=cnt;
|
||||
StrCpy(progress1_desc,"Zeroing");
|
||||
show_progress=TRUE;
|
||||
} else
|
||||
show_progress=FALSE;
|
||||
while (cnt>0) {
|
||||
n=cnt;
|
||||
if (n>ZERO_BUF_SIZE)
|
||||
n=ZERO_BUF_SIZE;
|
||||
WBlks(dv,z,blk,n);
|
||||
blk+=n;
|
||||
cnt-=n;
|
||||
if (show_progress)
|
||||
progress1+=n;
|
||||
Yield; //Prevent locking
|
||||
}
|
||||
Free(z);
|
||||
if (show_progress) {
|
||||
*progress1_desc=0;
|
||||
progress1=progress1_max=0;
|
||||
}
|
||||
}
|
||||
|
||||
Bool RBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{//Read blk cnt from Drv to buf.
|
||||
Bool res=TRUE,unlock;
|
||||
CBlkDev *bd=dv->bd;
|
||||
if (cnt<=0) return TRUE;
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
BlkDevInit(bd);
|
||||
if (dv->drv_offset && blk<dv->drv_offset ||
|
||||
blk+cnt>dv->drv_offset+dv->size)
|
||||
throw('Drv');
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
RCache(dv,&buf,&blk,&cnt);
|
||||
if (cnt>0) {
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
MemCpy(buf,bd->RAM_dsk+blk<<BLK_SIZE_BITS,cnt<<BLK_SIZE_BITS);
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
FRBlks(bd->file_dsk,buf,blk,cnt);
|
||||
break;
|
||||
case BDT_ATA:
|
||||
case BDT_ATAPI:
|
||||
res=ATARBlks(dv,buf,blk,cnt);
|
||||
break;
|
||||
}
|
||||
bd->last_time=tS;
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
DskCacheAdd(dv,buf,blk,cnt);
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool WBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{//Write blk cnt from buf to Drv.
|
||||
Bool res=TRUE,unlock;
|
||||
CBlkDev *bd=dv->bd;
|
||||
if (cnt<=0) return TRUE;
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
BlkDevInit(bd);
|
||||
if (bd->flags&BDF_READ_ONLY && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
|
||||
throw('BlkDev');
|
||||
if (dv->drv_offset && blk<dv->drv_offset ||
|
||||
blk+cnt>dv->drv_offset+dv->size)
|
||||
throw('Drv');
|
||||
if (cnt>0) {
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
MemCpy(bd->RAM_dsk+blk<<BLK_SIZE_BITS,buf,cnt<<BLK_SIZE_BITS);
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
FWBlks(bd->file_dsk,buf,blk,cnt);
|
||||
break;
|
||||
case BDT_ATA:
|
||||
case BDT_ATAPI:
|
||||
res=ATAWBlks(dv,buf,blk,cnt);
|
||||
break;
|
||||
}
|
||||
bd->last_time=tS;
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
DskCacheAdd(dv,buf,blk,cnt);
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
Bool BlkDevLock(CBlkDev *bd)
|
||||
{//Make this task have exclusive access to BlkDev.
|
||||
BlkDevChk(bd);
|
||||
while (bd->lock_fwding)
|
||||
bd=bd->lock_fwding; //If two blkdevs on same controller, use just one lock
|
||||
if (!Bt(&bd->locked_flags,BDlf_LOCKED) || bd->owning_task!=Fs) {
|
||||
while (LBts(&bd->locked_flags,BDlf_LOCKED))
|
||||
Yield;
|
||||
bd->owning_task=Fs;
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool BlkDevUnlock(CBlkDev *bd,Bool rst=FALSE)
|
||||
{//Release exclusive lock on access to BlkDev.
|
||||
BlkDevChk(bd);
|
||||
while (bd->lock_fwding)
|
||||
bd=bd->lock_fwding; //If two blkdevs on same controller, use just one lock
|
||||
if (Bt(&bd->locked_flags,BDlf_LOCKED) && bd->owning_task==Fs) {
|
||||
if (rst)
|
||||
bd->flags&=~(BDF_INITIALIZED|BDF_INIT_IN_PROGRESS);
|
||||
bd->owning_task=NULL;
|
||||
LBtr(&bd->locked_flags,BDlf_LOCKED);
|
||||
Yield; //Prevent deadlock
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool BlkDevInit(CBlkDev *bd)
|
||||
{
|
||||
CDirEntry de;
|
||||
U8 buf[STR_LEN];
|
||||
CDrv *dv=Let2Drv(bd->first_drv_let);
|
||||
Bool res=FALSE;
|
||||
if (!LBts(&bd->flags,BDf_INITIALIZED)) {
|
||||
bd->flags|=BDF_INIT_IN_PROGRESS;
|
||||
switch (bd->type) {
|
||||
case BDT_RAM:
|
||||
if (!bd->RAM_dsk) {
|
||||
bd->RAM_dsk=AMAlloc((bd->max_blk+1)<<BLK_SIZE_BITS);
|
||||
bd->max_blk=MSize(bd->RAM_dsk)>>BLK_SIZE_BITS-1;
|
||||
}
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
if (RedSeaValidate(bd->first_drv_let))
|
||||
RedSeaInit(dv);
|
||||
else
|
||||
RedSeaFmt(bd->first_drv_let);
|
||||
res=TRUE;
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
if (FileFind(bd->file_dsk_name,&de,FUF_JUST_FILES)) {
|
||||
bd->max_blk=de.size>>BLK_SIZE_BITS-1;
|
||||
try bd->file_dsk=FOpen(bd->file_dsk_name,"rc",bd->max_blk+1);
|
||||
catch {
|
||||
if (Fs->except_ch=='File')
|
||||
PrintErr("Not Contiguous. Move file to filename.ISO.C.\n");
|
||||
Fs->catch_except=TRUE;
|
||||
}
|
||||
if (bd->file_dsk) {
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
if (RedSeaValidate(bd->first_drv_let)) {
|
||||
RedSeaInit(dv);
|
||||
res=TRUE;
|
||||
} else
|
||||
PrintErr("Not RedSea\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BDT_ISO_FILE_WRITE:
|
||||
if (!bd->file_dsk_name) {
|
||||
StrPrint(buf,"%C:/Drv%C.ISO.C",
|
||||
blkdev.boot_drv_let,bd->first_drv_let);
|
||||
bd->file_dsk_name=AStrNew(buf);
|
||||
}
|
||||
if (bd->max_blk<7)
|
||||
bd->max_blk=7;
|
||||
bd->file_dsk=FOpen(bd->file_dsk_name,"wc",bd->max_blk+1);
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
dv->size=bd->max_blk+1-bd->drv_offset;
|
||||
RedSeaFmt(bd->first_drv_let);
|
||||
CallExtStr("RedSeaISO9660",bd->file_dsk_name,bd->first_drv_let);
|
||||
res=TRUE;
|
||||
break;
|
||||
case BDT_ATA:
|
||||
bd->max_reads=128;
|
||||
bd->max_writes=1;
|
||||
res=ATAInit(bd);
|
||||
break;
|
||||
case BDT_ATAPI:
|
||||
//0xFFFF*4 is too big for my taste
|
||||
bd->max_reads=0x800*4;
|
||||
//max of maybe a quarter of disk cache
|
||||
if (bd->max_reads>blkdev.cache_size/BLK_SIZE/4)
|
||||
bd->max_reads=blkdev.cache_size/BLK_SIZE/4 & ~3;
|
||||
if (bd->max_reads<128)
|
||||
bd->max_reads=128;
|
||||
bd->max_writes=0xFFFF*4;
|
||||
if (res=ATAInit(bd))
|
||||
dv->size=bd->max_blk+1;
|
||||
break;
|
||||
}
|
||||
if (res && bd->flags & BDF_READ_CACHE)
|
||||
DskCacheInvalidate(dv);
|
||||
bd->flags&=~BDF_INIT_IN_PROGRESS;
|
||||
} else
|
||||
res=TRUE;
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 BlkDevsRelease()
|
||||
{//When task dies, release all owned BlkDevs.
|
||||
I64 i;
|
||||
CBlkDev *bd;
|
||||
for (i=0;i<BLKDEVS_NUM;i++) {
|
||||
bd=&blkdev.blkdevs[i];
|
||||
if (bd->owning_task==Fs && bd->bd_signature==BD_SIGNATURE_VAL)
|
||||
BlkDevUnlock(bd,TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
CBlkDev *BlkDevNextFreeSlot(U8 first_drv_let,I64 type)
|
||||
{//Locate free slot for new BlkDev, like during $LK,"Mount",A="MN:Mount"$().
|
||||
I64 i=0;
|
||||
CBlkDev *res;
|
||||
if (Let2BlkDevType(first_drv_let)!=type)
|
||||
throw('BlkDev');
|
||||
do {
|
||||
res=&blkdev.blkdevs[i];
|
||||
if (res->bd_signature!=BD_SIGNATURE_VAL) {
|
||||
MemSet(res,0,sizeof(CBlkDev));
|
||||
res->first_drv_let=first_drv_let;
|
||||
res->type=type;
|
||||
res->flags=BDF_READ_CACHE;
|
||||
res->blk_size=BLK_SIZE;
|
||||
res->max_blk=0xEFFFFFFF;
|
||||
switch (type) {
|
||||
case BDT_RAM:
|
||||
res->flags&=~BDF_READ_CACHE;
|
||||
break;
|
||||
case BDT_ISO_FILE_READ:
|
||||
res->flags|=BDF_READ_ONLY;
|
||||
break;
|
||||
case BDT_ATAPI:
|
||||
res->flags|=BDF_REMOVABLE|BDF_READ_ONLY;
|
||||
res->blk_size=DVD_BLK_SIZE;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
} while (++i<BLKDEVS_NUM);
|
||||
throw('BlkDev');
|
||||
return NULL; //never gets here
|
||||
}
|
||||
|
||||
U0 BlkDevDel(CBlkDev *bd)
|
||||
{//Delete BlkDev
|
||||
DrvBlkDevDel(bd);
|
||||
FClose(bd->file_dsk);
|
||||
Free(bd->file_dsk_name);
|
||||
Free(bd->dev_id_record);
|
||||
MemSet(bd,0,sizeof(CBlkDev));
|
||||
}
|
||||
|
||||
CBlkDev *BlkDevChk(CBlkDev *bd,Bool except=TRUE)
|
||||
{//Check for valid BlkDev. Throw exception.
|
||||
if (!bd || bd->bd_signature!=BD_SIGNATURE_VAL ||
|
||||
!(BDT_NULL<bd->type<BDT_TYPES_NUM)) {
|
||||
if (except)
|
||||
throw('BlkDev');
|
||||
else
|
||||
return NULL;
|
||||
} else
|
||||
return bd;
|
||||
}
|
||||
|
||||
CBlkDev *Let2BlkDev(U8 drv_let=0,Bool except=TRUE)
|
||||
{//Drv letter to BlkDev ptr.
|
||||
CDrv *dv;
|
||||
if (dv=Let2Drv(drv_let,except))
|
||||
return BlkDevChk(dv->bd,except);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
//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_cluster=dv->drv_offset=bd->drv_offset=dv->size=0;
|
||||
while (TRUE) {
|
||||
dv->size=MaxI64(dv->size,(i+1)*spc);
|
||||
RBlks(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_cluster=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_cluster=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=DftExt(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);
|
||||
|
||||
FWBlks(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;
|
||||
FRBlks(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=DftExt(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);
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
I64 FSize(CFile *f)
|
||||
{//Report size of opened file in bytes.
|
||||
if (f)
|
||||
return f->de.size;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFile *FOpen(U8 *filename,U8 *flags,I64 cnt=0)
|
||||
{//Allows flags "r","w","w+". "c" for contiguous.
|
||||
//(It uses $LK,"StrOcc",A="MN:StrOcc"$() for 'w', 'r', '+', 'c')
|
||||
CFile *f=CAlloc(sizeof(CFile));
|
||||
CDirContext *dirc;
|
||||
U8 *full_name;
|
||||
Bool contiguous=StrOcc(flags,'c');
|
||||
|
||||
f->cluster=INVALID_CLUSTER;
|
||||
f->fblk_num=0;
|
||||
if (cnt>0)
|
||||
f->max_blk=cnt-1;
|
||||
else
|
||||
f->max_blk=I64_MAX;
|
||||
f->file_cluster_num=INVALID_CLUSTER;
|
||||
full_name=FileNameAbs(filename);
|
||||
f->dv=Let2Drv(*full_name);
|
||||
if (f->dv->fs_type==FSt_REDSEA)
|
||||
contiguous=TRUE;
|
||||
if (contiguous) {
|
||||
f->flags|=FF_CONTIGUOUS;
|
||||
if (f->dv->fs_type!=FSt_REDSEA &&
|
||||
!(FileAttr(filename) & RS_ATTR_CONTIGUOUS))
|
||||
throw('File');
|
||||
}
|
||||
f->cluster_buf=CAlloc(f->dv->spc<<BLK_SIZE_BITS);
|
||||
if (StrOcc(flags,'w')) {
|
||||
f->flags=f->flags|FF_WRITE|FF_NEEDS_WRITE;
|
||||
if (StrOcc(flags,'+')) {
|
||||
if (FileFind(full_name,&f->de,FUF_JUST_FILES)) {
|
||||
Free(full_name);
|
||||
if (contiguous)
|
||||
f->max_blk=(FSize(f)+BLK_SIZE-1)>>BLK_SIZE_BITS-1;
|
||||
return f;
|
||||
}
|
||||
} else
|
||||
Del(full_name,,,FALSE);
|
||||
f->de.full_name=full_name;
|
||||
f->flags|=FF_NEW_FILE;
|
||||
if (dirc=DirContextNew(full_name)) {
|
||||
StrCpy(f->de.name,dirc->mask);
|
||||
if (cnt>0) {//We pre-alloc the whole thing.
|
||||
f->de.cluster=ClustersAlloc(f->dv,0,
|
||||
(cnt+f->dv->spc-1)/f->dv->spc,contiguous);
|
||||
f->de.size=cnt<<BLK_SIZE_BITS;
|
||||
DirNew(dirc->dv,Fs->cur_dir,&f->de,TRUE);
|
||||
f->flags&=~FF_NEW_FILE;
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
return f;
|
||||
}
|
||||
} else {
|
||||
if (FileFind(full_name,&f->de,FUF_JUST_FILES)) {
|
||||
Free(full_name);
|
||||
f->max_blk=(FSize(f)+BLK_SIZE-1)>>BLK_SIZE_BITS-1;
|
||||
return f;
|
||||
}
|
||||
}
|
||||
Free(f->cluster_buf);
|
||||
Free(full_name);
|
||||
Free(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U0 FClose(CFile *f)
|
||||
{//Close CFile, updating directory.
|
||||
CDirContext *dirc;
|
||||
if (f) {
|
||||
if (f->flags & FF_BUF_DIRTY) {
|
||||
WClusters(f->dv,f->cluster_buf,f->cluster,1);
|
||||
f->flags&=~FF_BUF_DIRTY;
|
||||
}
|
||||
if (f->flags & FF_NEEDS_WRITE) {
|
||||
if (dirc=DirContextNew(f->de.full_name)) {
|
||||
if (!(f->flags & FF_USE_OLD_DATETIME))
|
||||
f->de.datetime=Now;
|
||||
if (f->flags & FF_NEW_FILE)
|
||||
DirNew(dirc->dv,Fs->cur_dir,&f->de,TRUE);
|
||||
else
|
||||
DirNew(dirc->dv,Fs->cur_dir,&f->de,FALSE);
|
||||
DirContextDel(dirc);
|
||||
} else
|
||||
throw('File');
|
||||
}
|
||||
Free(f->cluster_buf);
|
||||
Free(f->de.full_name);
|
||||
Free(f);
|
||||
}
|
||||
}
|
||||
|
||||
I64 FSetCluster(CFile *f,I64 c,I64 blk,Bool read)
|
||||
{
|
||||
CDrv *dv=f->dv;
|
||||
I64 i;
|
||||
if (f->cluster!=c) {
|
||||
if (f->flags & FF_BUF_DIRTY) {
|
||||
i=dv->spc;
|
||||
if (f->max_blk!=I64_MAX) {
|
||||
i=f->max_blk+1-f->file_cluster_num*dv->spc;
|
||||
if (i>dv->spc)
|
||||
i=dv->spc;
|
||||
}
|
||||
WClustersBlks(dv,f->cluster_buf,f->cluster,i);
|
||||
f->flags=f->flags & ~FF_BUF_DIRTY;
|
||||
}
|
||||
f->cluster=c;
|
||||
f->file_cluster_num=blk/dv->spc;
|
||||
if (read) {
|
||||
i=dv->spc;
|
||||
if (f->max_blk!=I64_MAX) {
|
||||
i=f->max_blk+1-f->file_cluster_num*dv->spc;
|
||||
if (i>dv->spc)
|
||||
i=dv->spc;
|
||||
}
|
||||
c=RClustersBlks(dv,f->cluster_buf,c,i);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
Bool FRBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1)
|
||||
{//Read [nth,n+cnt) blks of file.
|
||||
CDrv *dv=f->dv;
|
||||
I64 spc=dv->spc,i,j,c=f->de.cluster;
|
||||
if (!f || !dv) return FALSE;
|
||||
if (blk==FFB_NEXT_BLK)
|
||||
blk=f->fblk_num;
|
||||
if (blk+cnt-1>f->max_blk)
|
||||
return FALSE;
|
||||
if (cnt<=0) return TRUE;
|
||||
|
||||
if (f->flags & FF_CONTIGUOUS) {
|
||||
RBlks(dv,buf,Cluster2Blk(dv,c)+blk,cnt);
|
||||
blk+=cnt;
|
||||
} else {
|
||||
i=blk/spc;
|
||||
if (0<=f->file_cluster_num<=i) {
|
||||
c=f->cluster;
|
||||
i-=f->file_cluster_num;
|
||||
}
|
||||
if (i>0)
|
||||
c=ClusterNumNext(dv,c,i);
|
||||
|
||||
if (i=blk%spc) {
|
||||
c=FSetCluster(f,c,blk,TRUE);
|
||||
if (cnt<spc-i)
|
||||
j=cnt;
|
||||
else
|
||||
j=spc-i;
|
||||
MemCpy(buf,f->cluster_buf+i<<BLK_SIZE_BITS,j<<BLK_SIZE_BITS);
|
||||
buf+=j<<BLK_SIZE_BITS;
|
||||
cnt-=j;
|
||||
blk+=j;
|
||||
}
|
||||
while (cnt>=spc) {
|
||||
c=FSetCluster(f,c,blk,TRUE);
|
||||
MemCpy(buf,f->cluster_buf,spc<<BLK_SIZE_BITS);
|
||||
buf+=spc<<BLK_SIZE_BITS;
|
||||
cnt-=spc;
|
||||
blk+=spc;
|
||||
}
|
||||
if (cnt>0) {
|
||||
c=FSetCluster(f,c,blk,TRUE);
|
||||
MemCpy(buf,f->cluster_buf,cnt<<BLK_SIZE_BITS);
|
||||
buf+=cnt<<BLK_SIZE_BITS;
|
||||
blk+=cnt;
|
||||
}
|
||||
}
|
||||
f->fblk_num=blk;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool FWBlks(CFile *f,U8 *buf,I64 blk=FFB_NEXT_BLK,I64 cnt=1)
|
||||
{//Write [nth,n+cnt) blks of file.
|
||||
CDrv *dv=f->dv;
|
||||
I64 spc=dv->spc,i,j,c=f->de.cluster,c1;
|
||||
if (!f || !dv) return FALSE;
|
||||
if (blk==FFB_NEXT_BLK)
|
||||
blk=f->fblk_num;
|
||||
if (blk+cnt-1>f->max_blk)
|
||||
return FALSE;
|
||||
if (!(f->flags & FF_WRITE))
|
||||
return FALSE;
|
||||
if (cnt<=0) return TRUE;
|
||||
if (f->flags & FF_CONTIGUOUS) {
|
||||
WBlks(dv,buf,Cluster2Blk(dv,c)+blk,cnt);
|
||||
blk+=cnt;
|
||||
} else {
|
||||
if (!c) {
|
||||
c=ClustersAlloc(dv,0,1,FALSE);
|
||||
f->file_cluster_num=0;
|
||||
f->cluster=c;
|
||||
f->de.cluster=c;
|
||||
f->flags|=FF_NEEDS_WRITE|FF_NEW_FILE;
|
||||
}
|
||||
i=blk/spc;
|
||||
if (0<=f->file_cluster_num<=i) {
|
||||
c=f->cluster;
|
||||
i-=f->file_cluster_num;
|
||||
}
|
||||
while (i>0) {
|
||||
c1=c;
|
||||
c=ClusterNumNext(dv,c1,1);
|
||||
if (c==INVALID_CLUSTER) {
|
||||
c=ClustersAlloc(dv,c1,i,FALSE);
|
||||
if (i>1)
|
||||
c=ClusterNumNext(dv,c,i-1);
|
||||
break;
|
||||
} else
|
||||
i--;
|
||||
}
|
||||
|
||||
if (i=blk%spc) {
|
||||
FSetCluster(f,c,blk,TRUE);
|
||||
if (cnt<spc-i)
|
||||
j=cnt;
|
||||
else
|
||||
j=spc-i;
|
||||
MemCpy(f->cluster_buf+BLK_SIZE*i,buf,j<<BLK_SIZE_BITS);
|
||||
f->flags|=FF_BUF_DIRTY;
|
||||
buf+=j<<BLK_SIZE_BITS;
|
||||
cnt-=j;
|
||||
blk+=j;
|
||||
if (cnt>0) {
|
||||
c1=c;
|
||||
c=ClusterNumNext(dv,c1,1);
|
||||
if (c==INVALID_CLUSTER)
|
||||
c=ClustersAlloc(dv,c1,1,FALSE);
|
||||
}
|
||||
}
|
||||
while (cnt>=spc) {
|
||||
FSetCluster(f,c,blk,FALSE);
|
||||
MemCpy(f->cluster_buf,buf,spc<<BLK_SIZE_BITS);
|
||||
f->flags|=FF_BUF_DIRTY;
|
||||
buf+=spc<<BLK_SIZE_BITS;
|
||||
cnt-=spc;
|
||||
blk+=spc;
|
||||
if (cnt>0) {
|
||||
c1=c;
|
||||
c=ClusterNumNext(dv,c1,1);
|
||||
if (c==INVALID_CLUSTER)
|
||||
c=ClustersAlloc(dv,c1,1,FALSE);
|
||||
}
|
||||
}
|
||||
if (cnt>0) {
|
||||
FSetCluster(f,c,blk,TRUE);
|
||||
MemCpy(f->cluster_buf,buf,cnt<<BLK_SIZE_BITS);
|
||||
f->flags|=FF_BUF_DIRTY;
|
||||
buf+=cnt<<BLK_SIZE_BITS;
|
||||
blk+=cnt;
|
||||
}
|
||||
if (f->de.size<blk<<BLK_SIZE_BITS)
|
||||
f->de.size=blk<<BLK_SIZE_BITS;
|
||||
}
|
||||
f->fblk_num=blk;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
U0 DskCacheInit(I64 size_in_U8s)
|
||||
{
|
||||
CCacheBlk *tmpc;
|
||||
I64 i,cnt;
|
||||
|
||||
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
|
||||
Yield;
|
||||
Free(blkdev.cache_ctrl);
|
||||
Free(blkdev.cache_base);
|
||||
Free(blkdev.cache_hash_table);
|
||||
if (size_in_U8s<0x2000) {
|
||||
blkdev.cache_ctrl=NULL;
|
||||
blkdev.cache_base=NULL;
|
||||
blkdev.cache_hash_table=NULL;
|
||||
} else {
|
||||
blkdev.cache_ctrl=ACAlloc(offset(CCacheBlk.body));
|
||||
blkdev.cache_base=AMAlloc(size_in_U8s);
|
||||
QueInit(blkdev.cache_ctrl);
|
||||
|
||||
cnt=MSize(blkdev.cache_base)/sizeof(CCacheBlk);
|
||||
blkdev.cache_size=cnt*BLK_SIZE;
|
||||
for (i=0;i<cnt;i++) {
|
||||
tmpc=blkdev.cache_base+i;
|
||||
QueIns(tmpc,blkdev.cache_ctrl->last_lru);
|
||||
tmpc->next_hash=tmpc->last_hash=tmpc;
|
||||
tmpc->dv=NULL;
|
||||
tmpc->blk=0;
|
||||
}
|
||||
|
||||
blkdev.cache_hash_table=AMAlloc(DSK_CACHE_HASH_SIZE*sizeof(U8 *)*2);
|
||||
for (i=0;i<DSK_CACHE_HASH_SIZE;i++) {
|
||||
tmpc=blkdev.cache_hash_table(U8 *)+i*sizeof(U8 *)*2
|
||||
-offset(CCacheBlk.next_hash);
|
||||
tmpc->next_hash=tmpc->last_hash=tmpc;
|
||||
}
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
|
||||
}
|
||||
|
||||
I64 DskCacheHash(I64 blk)
|
||||
{
|
||||
I64 i=blk & (DSK_CACHE_HASH_SIZE-1);
|
||||
return blkdev.cache_hash_table(U8 *)+i<<4-offset(CCacheBlk.next_hash);
|
||||
}
|
||||
|
||||
U0 DskCacheQueRem(CCacheBlk *tmpc)
|
||||
{
|
||||
QueRem(tmpc);
|
||||
tmpc->next_hash->last_hash=tmpc->last_hash;
|
||||
tmpc->last_hash->next_hash=tmpc->next_hash;
|
||||
}
|
||||
|
||||
U0 DskCacheQueIns(CCacheBlk *tmpc)
|
||||
{
|
||||
CCacheBlk *tmp_n,*tmp_l;
|
||||
QueIns(tmpc,blkdev.cache_ctrl->last_lru);
|
||||
tmp_l=DskCacheHash(tmpc->blk);
|
||||
tmp_n=tmp_l->next_hash;
|
||||
tmpc->last_hash=tmp_l;
|
||||
tmpc->next_hash=tmp_n;
|
||||
tmp_l->next_hash=tmp_n->last_hash=tmpc;
|
||||
}
|
||||
|
||||
CCacheBlk *DskCacheFind(CDrv *dv,I64 blk)
|
||||
{
|
||||
CCacheBlk *tmpc,*tmpc1=DskCacheHash(blk);
|
||||
tmpc=tmpc1->next_hash;
|
||||
while (tmpc!=tmpc1) {
|
||||
if (tmpc->dv==dv && tmpc->blk==blk)
|
||||
return tmpc;
|
||||
tmpc=tmpc->next_hash;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U0 DskCacheAdd(CDrv *dv,U8 *buf, I64 blk, I64 cnt)
|
||||
{
|
||||
CCacheBlk *tmpc;
|
||||
if (blkdev.cache_base) {
|
||||
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
|
||||
Yield;
|
||||
while (cnt-->0) {
|
||||
if (!(tmpc=DskCacheFind(dv,blk)))
|
||||
tmpc=blkdev.cache_ctrl->next_lru;
|
||||
DskCacheQueRem(tmpc);
|
||||
MemCpy(&tmpc->body,buf,BLK_SIZE);
|
||||
tmpc->dv=dv;
|
||||
tmpc->blk=blk;
|
||||
DskCacheQueIns(tmpc);
|
||||
blk++;
|
||||
buf+=BLK_SIZE;
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
|
||||
}
|
||||
}
|
||||
|
||||
U0 DskCacheInvalidate2(CDrv *dv)
|
||||
{
|
||||
CCacheBlk *tmpc,*tmpc1;
|
||||
if (blkdev.cache_base) {
|
||||
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
|
||||
Yield;
|
||||
tmpc=blkdev.cache_ctrl->last_lru;
|
||||
while (tmpc!=blkdev.cache_ctrl) {
|
||||
tmpc1=tmpc->last_lru;
|
||||
if (tmpc->dv==dv) {
|
||||
DskCacheQueRem(tmpc);
|
||||
tmpc->dv=NULL;
|
||||
tmpc->blk=0;
|
||||
tmpc->next_hash=tmpc->last_hash=tmpc;
|
||||
QueIns(tmpc,blkdev.cache_ctrl->last_lru);
|
||||
}
|
||||
tmpc=tmpc1;
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
|
||||
}
|
||||
}
|
||||
|
||||
U0 RCache(CDrv *dv,U8 **_buf, I64 *_blk, I64 *_cnt)
|
||||
{
|
||||
CCacheBlk *tmpc;
|
||||
if (blkdev.cache_base) {
|
||||
while (LBts(&sys_semas[SEMA_DSK_CACHE],0))
|
||||
Yield;
|
||||
//fetch leading blks from cache
|
||||
while (*_cnt>0) {
|
||||
if (tmpc=DskCacheFind(dv,*_blk)) {
|
||||
MemCpy(*_buf,&tmpc->body,BLK_SIZE);
|
||||
*_cnt-=1;
|
||||
*_buf+=BLK_SIZE;
|
||||
*_blk+=1;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
//fetch trailing blks from cache
|
||||
while (*_cnt>0) {
|
||||
if (tmpc=DskCacheFind(dv,*_blk+*_cnt-1)) {
|
||||
MemCpy(*_buf+(*_cnt-1)<<BLK_SIZE_BITS,&tmpc->body,BLK_SIZE);
|
||||
*_cnt-=1;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
LBtr(&sys_semas[SEMA_DSK_CACHE],0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
I64 ClusterNumNext(CDrv *dv,I64 c,I64 cnt=1)
|
||||
{//Return next cnt'th cluster in chain.
|
||||
Bool unlock;
|
||||
DrvChk(dv);
|
||||
if (cnt<=0) return c;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_ISO9660:
|
||||
case FSt_REDSEA:
|
||||
c+=cnt;
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
while (cnt-->0 && 0<c<0x0FFFFFF8) {
|
||||
DrvFATBlkSet(dv,c);
|
||||
c=dv->cur_fat_blk[c & (BLK_SIZE/4-1)];
|
||||
}
|
||||
if (!(0<c<0x0FFFFFF8))
|
||||
c=INVALID_CLUSTER;
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return c;
|
||||
}
|
||||
|
||||
I64 Cluster2Blk(CDrv *dv,I64 c)
|
||||
{//Drv cluster num to blk num.
|
||||
DrvChk(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
return c;
|
||||
case FSt_ISO9660:
|
||||
case FSt_FAT32:
|
||||
return dv->data_area+c*dv->spc;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
}
|
||||
|
||||
I64 RClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks)
|
||||
{//Accepts blk count, so padding on last cluster is not read.
|
||||
I64 i;
|
||||
Bool unlock;
|
||||
DrvChk(dv);
|
||||
if (blks<=0) return c;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_ISO9660:
|
||||
RBlks(dv,buf,dv->data_area+c*dv->spc,blks);
|
||||
c+=(blks+dv->spc-1)/dv->spc;
|
||||
break;
|
||||
case FSt_REDSEA:
|
||||
RBlks(dv,buf,c,blks);
|
||||
c+=blks;
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
while (blks && 0<c<0x0FFFFFF8) {
|
||||
i=blks;
|
||||
if (i>dv->spc)
|
||||
i=dv->spc;
|
||||
RBlks(dv,buf,dv->data_area+c*dv->spc,i);
|
||||
buf+=i<<BLK_SIZE_BITS;
|
||||
c=ClusterNumNext(dv,c,1);
|
||||
blks-=i;
|
||||
}
|
||||
if (blks)
|
||||
throw('Drv');
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return c;
|
||||
}
|
||||
|
||||
I64 RClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt)
|
||||
{//Read cluster cnt from drv to buf.
|
||||
return RClustersBlks(dv,buf,c,cnt*dv->spc);
|
||||
}
|
||||
|
||||
I64 WClustersBlks(CDrv *dv,U8 *buf,I64 c,I64 blks)
|
||||
{//Accepts blk count, so padding on last cluster is not written.
|
||||
I64 i;
|
||||
Bool unlock;
|
||||
DrvChk(dv);
|
||||
if (blks<=0) return c;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
WBlks(dv,buf,c,blks);
|
||||
c=0;
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
while (blks) {
|
||||
if (!(0<c<0x0FFFFFF8))
|
||||
throw('Drv');
|
||||
i=blks;
|
||||
if (i>dv->spc)
|
||||
i=dv->spc;
|
||||
WBlks(dv,buf,dv->data_area+c*dv->spc,i);
|
||||
buf+=i<<BLK_SIZE_BITS;
|
||||
c=ClusterNumNext(dv,c);
|
||||
blks-=i;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return c;
|
||||
}
|
||||
|
||||
I64 WClusters(CDrv *dv,U8 *buf,I64 c,I64 cnt)
|
||||
{//Write cluster cnt from buf to drv.
|
||||
return WClustersBlks(dv,buf,c,cnt*dv->spc);
|
||||
}
|
||||
|
||||
I64 ClustersAlloc(CDrv *dv,I64 c=0,I64 cnt=1,Bool contiguous=FALSE)
|
||||
{//Alloc cluster cnt into chain.
|
||||
//c=0 means first cluster in chain
|
||||
DrvChk(dv);
|
||||
if (cnt<=0) return c;
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
return RedSeaAllocClusters(dv,cnt);
|
||||
case FSt_FAT32:
|
||||
if (contiguous) {
|
||||
if (c) throw('File');
|
||||
return FAT32AllocContiguousClusters(dv,cnt);
|
||||
} else
|
||||
return FAT32AllocClusters(dv,c,cnt);
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
Bool CopySingleZ(U8 *f1,U8 *f2) //Just one file
|
||||
{
|
||||
U8 *file_buf=NULL;
|
||||
I64 size,attr=0,c;
|
||||
CDirEntry de;
|
||||
if (FileFind(f1,&de,FUF_JUST_FILES)) {
|
||||
Free(de.full_name);
|
||||
file_buf=FileRead(f1,&size,&attr);
|
||||
attr=FileAttr(f2,attr);
|
||||
if (file_buf) {
|
||||
"Copying %s to %s\n",f1,f2;
|
||||
c=FileWrite(f2,file_buf,size,de.datetime,attr);
|
||||
Free(file_buf);
|
||||
return ToBool(c);
|
||||
} else
|
||||
PrintErr("File not found.\n");
|
||||
} else
|
||||
PrintErr("File not found.\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define COPY_BUF_BLKS 0x80
|
||||
Bool CopySingle(U8 *f1,U8 *f2) //Just one file
|
||||
{
|
||||
U8 *absf1=FileNameAbs(f1),*absf2=FileNameAbs(f2),*buf;
|
||||
I64 cnt,n,size,attr1=FileAttr(f1),attr2=FileAttr(f2),i,j;
|
||||
CFile *in_file=NULL,*out_file=NULL;
|
||||
if (!StrCmp(absf1,absf2)) {//onto self?
|
||||
Free(absf1);
|
||||
Free(absf2);
|
||||
return FALSE;
|
||||
}
|
||||
Free(absf1);
|
||||
Free(absf2);
|
||||
if (attr1!=attr2)
|
||||
return CopySingleZ(f1,f2);
|
||||
buf=MAlloc(COPY_BUF_BLKS<<BLK_SIZE_BITS);
|
||||
if (attr1 & RS_ATTR_CONTIGUOUS)
|
||||
in_file=FOpen(f1,"rc");
|
||||
else
|
||||
in_file=FOpen(f1,"r");
|
||||
if (in_file) {
|
||||
size=FSize(in_file);
|
||||
cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS;
|
||||
if (attr2 & RS_ATTR_CONTIGUOUS)
|
||||
out_file=FOpen(f2,"wc",cnt);
|
||||
else
|
||||
out_file=FOpen(f2,"w",cnt);
|
||||
if (out_file) {
|
||||
"Copying %s to %s\n",f1,f2;
|
||||
j=size;
|
||||
while (cnt>0) {
|
||||
if (cnt>COPY_BUF_BLKS) {
|
||||
n=COPY_BUF_BLKS;
|
||||
i=n<<BLK_SIZE_BITS;
|
||||
} else {
|
||||
n=cnt;
|
||||
i=j;
|
||||
}
|
||||
FRBlks(in_file, buf,FFB_NEXT_BLK,n);
|
||||
FWBlks(out_file,buf,FFB_NEXT_BLK,n);
|
||||
cnt-=n;
|
||||
j-=n<<BLK_SIZE_BITS;
|
||||
}
|
||||
out_file->flags|=FF_USE_OLD_DATETIME;
|
||||
out_file->de.datetime=in_file->de.datetime;
|
||||
out_file->de.size=size;
|
||||
out_file->de.attr=FileAttr(f2,in_file->de.attr);
|
||||
FClose(out_file);
|
||||
FClose(in_file);
|
||||
Free(buf);
|
||||
return TRUE;
|
||||
} else
|
||||
PrintErr("File not found.\n");
|
||||
FClose(in_file);
|
||||
} else
|
||||
PrintErr("File not found.\n");
|
||||
Free(buf);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 Del(U8 *files_find_mask,Bool make_mask=FALSE,
|
||||
Bool del_dir=FALSE,Bool print_msg=TRUE)
|
||||
{//Delete files.
|
||||
I64 res=0;
|
||||
CDirContext *dirc;
|
||||
if (dirc=DirContextNew(files_find_mask,make_mask)) {
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFilesDel(dirc->dv,Fs->cur_dir,dirc->mask,
|
||||
0,del_dir,print_msg);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FilesDel(dirc->dv,Fs->cur_dir,dirc->mask,
|
||||
0,del_dir,print_msg);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
Bool DirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain=TRUE)
|
||||
{//Makes a directory entry in the directory from a $LK,"CDirEntry",A="MN:CDirEntry"$ node.
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
return RedSeaDirNew(dv,cur_dir,tmpde,free_old_chain);
|
||||
case FSt_FAT32:
|
||||
return FAT32DirNew(dv,cur_dir,tmpde,free_old_chain);
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
return FALSE;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
U0 DirEntryDel(CDirEntry *tmpde)
|
||||
{//Free node returned from $LK,"FilesFind",A="MN:FilesFind"$(). Doesn't Free user_data.
|
||||
//Does not change the directory on disk.
|
||||
if (tmpde) {
|
||||
Free(tmpde->full_name);
|
||||
Free(tmpde);
|
||||
}
|
||||
}
|
||||
|
||||
U0 DirEntryDel2(CDirEntry *tmpde)
|
||||
{//Free node returned from $LK,"FilesFind",A="MN:FilesFind"$(). Frees user_data
|
||||
//Does not change the directory on disk.
|
||||
if (tmpde) {
|
||||
Free(tmpde->full_name);
|
||||
Free(tmpde->user_data);
|
||||
Free(tmpde);
|
||||
}
|
||||
}
|
||||
|
||||
U0 DirTreeDel(CDirEntry *tmpde)
|
||||
{//Free tree returned from $LK,"FilesFind",A="MN:FilesFind"$(). Doesn't Free user_data.
|
||||
//Does not change the directory on disk.
|
||||
CDirEntry *tmpde2;
|
||||
while (tmpde) {
|
||||
tmpde2=tmpde->next;
|
||||
if (tmpde->sub)
|
||||
DirTreeDel(tmpde->sub);
|
||||
DirEntryDel(tmpde);
|
||||
tmpde=tmpde2;
|
||||
}
|
||||
}
|
||||
|
||||
U0 DirTreeDel2(CDirEntry *tmpde)
|
||||
{//Free tree returned from $LK,"FilesFind",A="MN:FilesFind"$(). Frees user_data
|
||||
//Does not change the directory on disk.
|
||||
CDirEntry *tmpde2;
|
||||
while (tmpde) {
|
||||
tmpde2=tmpde->next;
|
||||
if (tmpde->sub)
|
||||
DirTreeDel2(tmpde->sub);
|
||||
DirEntryDel2(tmpde);
|
||||
tmpde=tmpde2;
|
||||
}
|
||||
}
|
||||
|
||||
I64 DirEntryCompareName(CDirEntry *e1,CDirEntry *e2)
|
||||
{
|
||||
U8 buf1[CDIR_FILENAME_LEN],buf2[CDIR_FILENAME_LEN],
|
||||
buf3[CDIR_FILENAME_LEN],buf4[CDIR_FILENAME_LEN];
|
||||
I64 d1=0,d2=0;
|
||||
if (e1->attr & RS_ATTR_DIR)
|
||||
d1=1;
|
||||
if (e2->attr & RS_ATTR_DIR)
|
||||
d2=1;
|
||||
if (d1!=d2)
|
||||
return d2-d1;
|
||||
else {
|
||||
StrCpy(buf1,e1->name);
|
||||
StrCpy(buf2,e2->name);
|
||||
FileExtRem(buf1,buf3);
|
||||
FileExtRem(buf2,buf4);
|
||||
if (d1=StrCmp(buf3,buf4))
|
||||
return d1;
|
||||
return StrCmp(buf1,buf2);
|
||||
}
|
||||
}
|
||||
|
||||
I64 DirEntryCompareCluster(CDirEntry *e1,CDirEntry *e2)
|
||||
{
|
||||
return e1->cluster-e2->cluster;
|
||||
}
|
||||
|
||||
#define SK_NAME 0
|
||||
#define SK_CLUSTER 1
|
||||
|
||||
U0 DirFilesSort(CDirEntry **_tmpde,I64 key)
|
||||
{
|
||||
I64 i,cnt;
|
||||
CDirEntry *tmpde=*_tmpde,*tmpde1,**sort_buf;
|
||||
if (tmpde) {
|
||||
cnt=LinkedLstCnt(tmpde);
|
||||
if (cnt>1) {
|
||||
sort_buf=MAlloc(cnt*sizeof(U8 *));
|
||||
i=0;
|
||||
tmpde1=tmpde;
|
||||
while (tmpde1) {
|
||||
sort_buf[i++]=tmpde1;
|
||||
tmpde1=tmpde1->next;
|
||||
}
|
||||
switch [key] {
|
||||
case SK_NAME:
|
||||
QSortI64(sort_buf,cnt,&DirEntryCompareName);
|
||||
break;
|
||||
case SK_CLUSTER:
|
||||
QSortI64(sort_buf,cnt,&DirEntryCompareCluster);
|
||||
break;
|
||||
}
|
||||
tmpde=sort_buf[0];
|
||||
*_tmpde=tmpde;
|
||||
for (i=0;i<cnt-1;i++) {
|
||||
tmpde1=sort_buf[i];
|
||||
tmpde1->next=sort_buf[i+1];
|
||||
}
|
||||
tmpde1=sort_buf[i];
|
||||
tmpde1->next=NULL;
|
||||
Free(sort_buf);
|
||||
|
||||
tmpde1=tmpde;
|
||||
while (tmpde1) {
|
||||
if (tmpde1->sub)
|
||||
DirFilesSort(&tmpde1->sub,key);
|
||||
tmpde1=tmpde1->next;
|
||||
}
|
||||
} else
|
||||
if (tmpde->sub)
|
||||
DirFilesSort(&tmpde->sub,key);
|
||||
}
|
||||
}
|
||||
|
||||
CDirEntry *DirFilesFlatten(CDirEntry *tmpde,CDirEntry **_res,I64 fuf_flags)
|
||||
{//Returns last node
|
||||
CDirEntry *tmpde1;
|
||||
Bool del;
|
||||
if (tmpde)
|
||||
while (TRUE) {
|
||||
tmpde1=tmpde->next;
|
||||
if (!(tmpde->attr&RS_ATTR_DIR)||!(fuf_flags&FUF_JUST_FILES)) {
|
||||
_res=*_res=tmpde;
|
||||
del=FALSE;
|
||||
} else
|
||||
del=TRUE;
|
||||
if (tmpde->sub) {
|
||||
_res=DirFilesFlatten(tmpde->sub,_res,fuf_flags);
|
||||
tmpde->sub=NULL;
|
||||
}
|
||||
if (del)
|
||||
DirEntryDel(tmpde);
|
||||
if (tmpde1)
|
||||
tmpde=tmpde1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
*_res=NULL;
|
||||
return _res;
|
||||
}
|
||||
|
||||
U0 PutFileLink(U8 *filename,U8 *full_name=NULL,I64 line=0,Bool plain_text=FALSE)
|
||||
{//Put $LK,"DolDoc",A="FI:::/Doc/DolDocOverview.DD"$ file,line link to StdOut, $LK,"DocPut",A="MN:DocPut"$.
|
||||
U8 *st;
|
||||
if (!filename) return;
|
||||
if (IsRaw) {
|
||||
if (line)
|
||||
"%s,%04d",filename,line;
|
||||
else
|
||||
"%s",filename;
|
||||
} else {
|
||||
//LK_DOC,LK_DOC_ANCHOR,LK_DOC_FIND,LK_DOC_LINE
|
||||
if (filename[0]=='A'&&filename[2]==':') {
|
||||
if (line) //See $LK,"SpriteEdText",A="MN:SpriteEdText"$()
|
||||
"$$LK,\"%s,%04d\",A=\"AL:%s,%d\"$$",filename+3,line,filename+3,line;
|
||||
else
|
||||
"$$LK,\"%s\",A=\"AI:%s\"$$",filename+3,filename+3;
|
||||
} else {
|
||||
if (!full_name)
|
||||
full_name=st=FileNameAbs(filename);
|
||||
else
|
||||
st=NULL;
|
||||
if (plain_text) {
|
||||
if (line)
|
||||
"$$LK,\"%s,%04d\",A=\"PL:%s,%d\"$$",filename,line,full_name,line;
|
||||
else
|
||||
"$$LK,\"%s\",A=\"PI:%s\"$$",filename,full_name;
|
||||
} else {
|
||||
if (line)
|
||||
"$$LK,\"%s,%04d\",A=\"FL:%s,%d\"$$",filename,line,full_name,line;
|
||||
else
|
||||
"$$LK,\"%s\",A=\"FI:%s\"$$",filename,full_name;
|
||||
}
|
||||
Free(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 PutDirLink(U8 *dirname,U8 *full_name=NULL)
|
||||
{//Put $LK,"DolDoc",A="FI:::/Doc/DolDocOverview.DD"$ dir macro to StdOut, $LK,"DocPut",A="MN:DocPut"$.
|
||||
U8 *st;
|
||||
if (!dirname) return;
|
||||
if (IsRaw)
|
||||
"%s",dirname;
|
||||
else {
|
||||
if (!full_name)
|
||||
full_name=st=DirNameAbs(dirname);
|
||||
else
|
||||
st=NULL;
|
||||
"$$MA,T=\"%s\",LM=\"Cd(\\\"%s\\\");Dir;\n\"$$",dirname,full_name;
|
||||
Free(st);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
U0 HomeSet(U8 *dirname)
|
||||
{//Change home directory.
|
||||
dirname=DirNameAbs(dirname);
|
||||
Free(blkdev.home_dir);
|
||||
blkdev.home_dir=AStrNew(dirname);
|
||||
Free(dirname);
|
||||
}
|
||||
|
||||
Bool Cd(U8 *dirname=NULL,Bool make_dirs=FALSE)
|
||||
{//Change directory. Optionally, make directories, too.
|
||||
I64 maxlen,cur_dir_cluster=0;
|
||||
U8 *chg_to_buf,*new_cur_dir,*buf;
|
||||
CDrv *dv;
|
||||
Bool res=TRUE;
|
||||
if (!dirname)
|
||||
dirname="~";
|
||||
else if (!*dirname)
|
||||
return TRUE;
|
||||
if (dirname[1]==':') {
|
||||
if (*dirname==':') {
|
||||
if (Fs->cur_dv!=Let2Drv(':') && !Drv(*dirname))
|
||||
return FALSE;
|
||||
} else if (Fs->cur_dv!=Let2Drv(*dirname) && !Drv(*dirname))
|
||||
return FALSE;
|
||||
dirname+=2;
|
||||
}
|
||||
if (*dirname=='/' || !*dirname || !Fs->cur_dir) {
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew("/");
|
||||
if (*dirname=='/')
|
||||
dirname++;
|
||||
}
|
||||
chg_to_buf=MStrUtil(dirname,
|
||||
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
maxlen=StrLen(Fs->cur_dir)+1+StrLen(chg_to_buf)+1;
|
||||
new_cur_dir=MAlloc(maxlen);
|
||||
buf=MAlloc(maxlen);
|
||||
StrCpy(new_cur_dir,Fs->cur_dir);
|
||||
while (*chg_to_buf && res) {
|
||||
StrFirstRem(chg_to_buf,"/",buf);
|
||||
if (!*buf)
|
||||
StrCpy(new_cur_dir,"/");
|
||||
else if (!StrCmp(buf,"..")) {
|
||||
StrLastRem(new_cur_dir,"/");
|
||||
if (!*new_cur_dir)
|
||||
StrCpy(new_cur_dir,"/");
|
||||
} else if (!StrCmp(buf,"~")) {
|
||||
Free(new_cur_dir);
|
||||
new_cur_dir=MAlloc(StrLen(blkdev.home_dir+2)+1+StrLen(chg_to_buf)+1);
|
||||
StrCpy(new_cur_dir,blkdev.home_dir+2);
|
||||
if (Fs->cur_dv!=Let2Drv('~') && !Drv('~'))
|
||||
return FALSE;
|
||||
} else if (StrCmp(buf,".") && *buf) {
|
||||
dv=Fs->cur_dv;
|
||||
cur_dir_cluster=Name2DirCluster(dv,new_cur_dir);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaCd(buf,cur_dir_cluster);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32Cd(buf,cur_dir_cluster);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1Cd(buf,cur_dir_cluster);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
res=FALSE;
|
||||
}
|
||||
if (!res && make_dirs) {
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew(new_cur_dir);
|
||||
res=MkDir(buf);
|
||||
}
|
||||
if (res) {
|
||||
if (StrCmp(new_cur_dir,"/"))
|
||||
CatPrint(new_cur_dir,"/");
|
||||
CatPrint(new_cur_dir,buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew(new_cur_dir);
|
||||
Free(buf);
|
||||
Free(chg_to_buf);
|
||||
Free(new_cur_dir);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool IsDir(U8 *dir_name)
|
||||
{//Is a str a valid, existing Dir?
|
||||
U8 *mask=MStrPrint("%s/*",dir_name);
|
||||
Bool res,old_silent=Silent;
|
||||
CDirContext *dirc;
|
||||
if (dirc=DirContextNew(mask)) {
|
||||
DirContextDel(dirc);
|
||||
res=TRUE;
|
||||
} else
|
||||
res=FALSE;
|
||||
Free(mask);
|
||||
Silent(old_silent);
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 Dir(U8 *files_find_mask,Bool full)
|
||||
{//List directory.
|
||||
CDirEntry *tmpde1=NULL,*tmpde2;
|
||||
U8 *st;
|
||||
CDateStruct ds;
|
||||
I64 csize=0xFFFF,c=0xFFFF,res=0;
|
||||
tmpde1=FilesFind(files_find_mask);
|
||||
if (!(st=CurDir))
|
||||
PrintErr("Invalid Drive\n");
|
||||
else {
|
||||
if (tmpde1) {
|
||||
Free(st);
|
||||
st=MAllocIdent(tmpde1->full_name);
|
||||
StrLastRem(st,"/");
|
||||
if (!st[2])
|
||||
StrCpy(st+2,"/");
|
||||
//Find max columns
|
||||
tmpde2=tmpde1;
|
||||
while (tmpde2) {
|
||||
if (tmpde2->size>csize)
|
||||
csize=tmpde2->size;
|
||||
if (tmpde2->cluster>c)
|
||||
c=tmpde2->cluster;
|
||||
tmpde2=tmpde2->next;
|
||||
}
|
||||
csize=Bsr(csize)/4+1;
|
||||
c=Bsr(c)/4+1;
|
||||
|
||||
"$$MA,T=\"Directory\",LM=\"PopUpCd;Dir;\n\"$$ of %s\n",st;
|
||||
if (full)
|
||||
"__DATE__ __TIME__ %*ts %*ts\n",
|
||||
csize,"SIZE",c,"CLUSTER";
|
||||
else
|
||||
"DATE_ TIME_ %*ts\n",csize,"SIZE";
|
||||
while (tmpde1) {
|
||||
tmpde2=tmpde1->next;
|
||||
res++;
|
||||
if (full)
|
||||
"%D %T %0*tX %0*tX ",tmpde1->datetime,tmpde1->datetime,
|
||||
csize,tmpde1->size,c,tmpde1->cluster;
|
||||
else {
|
||||
Date2Struct(&ds,tmpde1->datetime+local_time_offset);
|
||||
"%02d/%02d %02d:%02d %0*tX ",ds.mon,ds.day_of_mon,ds.hour,ds.min,
|
||||
csize,tmpde1->size;
|
||||
}
|
||||
if (tmpde1->attr & RS_ATTR_DIR)
|
||||
PutDirLink(tmpde1->name,tmpde1->full_name);
|
||||
else
|
||||
PutFileLink(tmpde1->name,tmpde1->full_name);
|
||||
'\n';
|
||||
DirEntryDel(tmpde1);
|
||||
tmpde1=tmpde2;
|
||||
}
|
||||
} else
|
||||
"No matching entries\n";
|
||||
Free(st);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool MkDir(U8 *filename,I64 entry_cnt=0)
|
||||
{//Make directory. $LK,"Cd",A="MN:Cd"$() can also make directories.
|
||||
//entry_cnt is for preallocating dir blks, leave it zero if you like.
|
||||
U8 *name;
|
||||
CDirContext *dirc;
|
||||
Bool res=FALSE;
|
||||
if (FileFind(filename,,FUF_JUST_DIRS))
|
||||
return FALSE;
|
||||
if (dirc=DirContextNew(filename)) {
|
||||
if (*dirc->mask) {
|
||||
if (!FileNameChk(dirc->mask))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else {
|
||||
"Make Directory:%s\n",filename;
|
||||
name=MStrUtil(dirc->mask,
|
||||
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaMkDir(dirc->dv,Fs->cur_dir,name,entry_cnt);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32MkDir(dirc->dv,Fs->cur_dir,name,entry_cnt);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
Free(name);
|
||||
}
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
U0 DirContextDel(CDirContext *dirc,Bool restore=TRUE)
|
||||
{//Change back to old cur_dir and drv.
|
||||
CBlkDev *bd;
|
||||
if (!dirc) return;
|
||||
if (restore) {
|
||||
bd=dirc->old_dv->bd;
|
||||
if (!(bd->flags & BDF_INIT_IN_PROGRESS)) {
|
||||
if (dirc->old_dir) {
|
||||
Drv(Drv2Let(dirc->old_dv));
|
||||
Cd(dirc->old_dir);
|
||||
}
|
||||
} else {
|
||||
Fs->cur_dv=dirc->old_dv;
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew("/");
|
||||
}
|
||||
}
|
||||
Free(dirc->old_dir);
|
||||
Free(dirc->mask);
|
||||
Free(dirc);
|
||||
}
|
||||
|
||||
CDirContext *DirContextNew(U8 *_mask,Bool make_mask=FALSE,
|
||||
Bool make_dirs=FALSE,Bool no_mask=FALSE)
|
||||
{//Save cur_dir and drv. Change to new dir.
|
||||
Bool valid=TRUE,old_silent;
|
||||
I64 mask_len=StrLen(_mask);
|
||||
U8 *buf,*mask,*tmp_mask,*semicolon_mask;
|
||||
CDirContext *dirc=CAlloc(sizeof(CDirContext));
|
||||
dirc->old_dir=StrNew(Fs->cur_dir);
|
||||
dirc->old_dv=Fs->cur_dv;
|
||||
mask=MStrUtil(_mask,SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
tmp_mask=mask;
|
||||
if (*mask && mask[1]==':') {
|
||||
if (Fs->cur_dv!=Let2Drv(*mask) && !Drv(*mask))
|
||||
valid=FALSE;
|
||||
mask+=2;
|
||||
}
|
||||
if (*mask=='~' && Fs->cur_dv!=Let2Drv('~') && !Drv('~'))
|
||||
valid=FALSE;
|
||||
dirc->dv=Fs->cur_dv;
|
||||
DrvChk(dirc->dv);
|
||||
buf=MAlloc(mask_len+2);
|
||||
StrCpy(buf,mask);
|
||||
|
||||
dirc->mask=MAlloc(mask_len+2);
|
||||
if (no_mask)
|
||||
*dirc->mask=0;
|
||||
else if (StrOcc(buf,';')) {
|
||||
semicolon_mask=MAlloc(mask_len+2);
|
||||
StrCpy(semicolon_mask,mask);
|
||||
StrFirstRem(semicolon_mask,";",buf);
|
||||
StrLastRem(buf,"/",dirc->mask);
|
||||
CatPrint(dirc->mask,";%s",semicolon_mask);
|
||||
Free(semicolon_mask);
|
||||
} else
|
||||
StrLastRem(buf,"/",dirc->mask);
|
||||
|
||||
if (*mask=='/' && !*buf)
|
||||
StrCpy(buf,"/");
|
||||
//If began with Dir, change to Dir.
|
||||
if (*buf && !Cd(buf,make_dirs))
|
||||
valid=FALSE;
|
||||
if (valid && make_mask) {
|
||||
if (!*dirc->mask) {
|
||||
Free(dirc->mask);
|
||||
dirc->mask=StrNew("*");
|
||||
} else {
|
||||
if (!make_dirs || FileNameChk(dirc->mask)) {
|
||||
old_silent=Silent;
|
||||
//Try mask to see if Dir. If Dir, change to dir and set to "*".
|
||||
if (Cd(dirc->mask,make_dirs)) {
|
||||
Free(dirc->mask);
|
||||
dirc->mask=StrNew("*");
|
||||
}
|
||||
Silent(old_silent);
|
||||
}
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
Free(tmp_mask);
|
||||
if (!valid) {
|
||||
DirContextDel(dirc);
|
||||
dirc=NULL;
|
||||
}
|
||||
return dirc;
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
Bool DrvLock(CDrv *dv)
|
||||
{//Make this task have exclusive access to drv & BlkDev.
|
||||
DrvChk(dv);
|
||||
BlkDevLock(dv->bd);
|
||||
if (!Bt(&dv->locked_flags,DVlf_LOCKED) || dv->owning_task!=Fs) {
|
||||
while (LBts(&dv->locked_flags,DVlf_LOCKED))
|
||||
Yield;
|
||||
dv->owning_task=Fs;
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool DrvUnlock(CDrv *dv,Bool rst=FALSE)
|
||||
{//Release exclusive lock on access to drv & BlkDev.
|
||||
DrvChk(dv);
|
||||
if (Bt(&dv->locked_flags,DVlf_LOCKED) && dv->owning_task==Fs) {
|
||||
BlkDevUnlock(dv->bd,rst);
|
||||
dv->owning_task=NULL;
|
||||
LBtr(&dv->locked_flags,DVlf_LOCKED);
|
||||
Yield; //Prevent deadlock
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 DrvsRelease()
|
||||
{//When task dies, release all owned drvs.
|
||||
I64 i;
|
||||
CDrv *dv;
|
||||
for (i=0;i<DRVS_NUM;i++) {
|
||||
dv=&blkdev.drvs[i];
|
||||
if (dv->owning_task==Fs && dv->dv_signature==DRV_SIGNATURE_VAL)
|
||||
DrvUnlock(dv,TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
CDrv *DrvMakeFreeSlot(U8 drv_let)
|
||||
{//Make a slot free for a new drv, like during $LK,"Mount",A="MN:Mount"$().
|
||||
//!!! drv_let is not a $LK,"remapped",A="MN:DrvMap"$ drv.
|
||||
I64 i=Let2Let(drv_let)-'A';
|
||||
CDrv *res;
|
||||
if (!(0<=i<DRVS_NUM))
|
||||
throw('Drv');
|
||||
res=&blkdev.drvs[i];
|
||||
MemSet(res,0,sizeof(CDrv));
|
||||
res->drv_let='A'+i;
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 DrvNextFreeLet(U8 first_drv_let='C')
|
||||
{//Locate free slot for new drv, like during $LK,"Mount",A="MN:Mount"$().
|
||||
//!!! first_drv_let is not a $LK,"remapped",A="MN:DrvMap"$ drv.
|
||||
I64 i=Let2Let(first_drv_let)-'A',type=Let2BlkDevType(first_drv_let);
|
||||
if (!(0<=i<DRVS_NUM))
|
||||
throw('Drv');
|
||||
do
|
||||
if (blkdev.drvs[i].dv_signature!=DRV_SIGNATURE_VAL) {
|
||||
if (Let2BlkDevType(i+'A')!=type)
|
||||
throw('Drv');
|
||||
else
|
||||
return i+'A';
|
||||
}
|
||||
while (++i<DRVS_NUM);
|
||||
throw('Drv');
|
||||
return 0; //Never gets here.
|
||||
}
|
||||
|
||||
U0 DrvDel(CDrv *dv)
|
||||
{//Delete drv
|
||||
if (dv->fs_type==FSt_REDSEA && dv->next_free)
|
||||
RedSeaFreeFreeLst(dv);
|
||||
Free(dv->cur_fat_blk);
|
||||
Free(dv->fis);
|
||||
MemSet(dv,0,sizeof(CDrv));
|
||||
}
|
||||
|
||||
U0 DrvBlkDevDel(CBlkDev *bd)
|
||||
{//Delete drv's of BlkDev
|
||||
I64 i;
|
||||
CDrv *dv;
|
||||
for (i=0;i<DRVS_NUM;i++) {
|
||||
dv=&blkdev.drvs[i];
|
||||
if (dv->bd==bd)
|
||||
DrvDel(dv);
|
||||
}
|
||||
}
|
||||
|
||||
U0 DrvFATBlkAlloc(CDrv *dv)
|
||||
{
|
||||
DrvChk(dv);
|
||||
Free(dv->cur_fat_blk);
|
||||
dv->cur_fat_blk=AMAlloc(BLK_SIZE);
|
||||
dv->cur_fat_blk_num=0;
|
||||
dv->fat_blk_dirty=0;
|
||||
RBlks(dv,dv->cur_fat_blk,dv->fat1,1);
|
||||
}
|
||||
|
||||
U0 DrvFATBlkClean(CDrv *dv,I64 fat_sel=3)
|
||||
{
|
||||
if ((dv->fs_type==FSt_FAT32 || dv->fs_type==FSt_REDSEA) &&
|
||||
Bt(&dv->fat_blk_dirty,0)) {
|
||||
if (dv->fat1==dv->fat2) {
|
||||
WBlks(dv,dv->cur_fat_blk,dv->fat1+dv->cur_fat_blk_num,1);
|
||||
LBtr(&dv->fat_blk_dirty,0);
|
||||
} else {
|
||||
if (fat_sel==3 || !fat_sel)
|
||||
WBlks(dv,dv->cur_fat_blk,dv->fat1+dv->cur_fat_blk_num,1);
|
||||
if (fat_sel==3 || fat_sel==1) {
|
||||
WBlks(dv,dv->cur_fat_blk,dv->fat2+dv->cur_fat_blk_num,1);
|
||||
LBtr(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
U0 DrvFATBlkSet(CDrv *dv,I64 c,I64 fat_sel=3)
|
||||
{
|
||||
I64 fat_blk_num;
|
||||
if (c==INVALID_CLUSTER)
|
||||
throw('Drv');
|
||||
switch (dv->fs_type) {
|
||||
case FSt_FAT32:
|
||||
fat_blk_num=c>>(BLK_SIZE_BITS-2);
|
||||
break;
|
||||
case FSt_REDSEA:
|
||||
fat_blk_num=(c-dv->data_area)>>(BLK_SIZE_BITS+3);
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
if (fat_blk_num!=dv->cur_fat_blk_num) {
|
||||
DrvFATBlkClean(dv,fat_sel);
|
||||
dv->cur_fat_blk_num=fat_blk_num;
|
||||
if (fat_sel==3 || !fat_sel)
|
||||
RBlks(dv,dv->cur_fat_blk,dv->fat1+dv->cur_fat_blk_num,1);
|
||||
else
|
||||
RBlks(dv,dv->cur_fat_blk,dv->fat2+dv->cur_fat_blk_num,1);
|
||||
}
|
||||
}
|
||||
|
||||
CDrv *DrvChk(CDrv *dv,Bool except=TRUE)
|
||||
{//Check for valid drv. Throw exception.
|
||||
if (!dv || dv->dv_signature!=DRV_SIGNATURE_VAL) {
|
||||
if (except)
|
||||
throw('Drv');
|
||||
else
|
||||
return NULL;
|
||||
} else
|
||||
return dv;
|
||||
}
|
||||
|
||||
U8 Drv2Let(CDrv *dv=NULL)
|
||||
{//Drv ptr to Drv letter.
|
||||
if (!dv)
|
||||
dv=Fs->cur_dv;
|
||||
DrvChk(dv);
|
||||
return dv->drv_let;
|
||||
}
|
||||
|
||||
U8 Let2Let(U8 drv_let=0)
|
||||
{//Drv letter to Drv letter.
|
||||
if (!drv_let)
|
||||
drv_let=Drv2Let(Fs->cur_dv);
|
||||
else if (drv_let==':')
|
||||
drv_let=blkdev.boot_drv_let;
|
||||
else if (drv_let=='~')
|
||||
drv_let=*blkdev.home_dir;
|
||||
return ToUpper(drv_let);
|
||||
}
|
||||
|
||||
I64 Let2BlkDevType(U8 drv_let)
|
||||
{//Drv letter to BlkDev Type. drv_let=0 not allowed. See $LK,"BDT_NULL",A="MN:BDT_NULL"$.
|
||||
drv_let=Let2Let(drv_let);
|
||||
if ('A'<=drv_let<='B')
|
||||
return BDT_RAM;
|
||||
if ('C'<=drv_let<='L')
|
||||
return BDT_ATA;
|
||||
if ('M'<=drv_let<='P')
|
||||
return BDT_ISO_FILE_READ;
|
||||
if ('Q'<=drv_let<='S')
|
||||
return BDT_ISO_FILE_WRITE;
|
||||
if ('T'<=drv_let<='Z')
|
||||
return BDT_ATAPI;
|
||||
return BDT_NULL;
|
||||
}
|
||||
|
||||
CDrv *Let2Drv(U8 drv_let=0,Bool except=TRUE)
|
||||
{//Drv letter to Drv ptr.
|
||||
CDrv *dv;
|
||||
if (!drv_let)
|
||||
dv=Fs->cur_dv;
|
||||
else {
|
||||
drv_let=Let2Let(drv_let);
|
||||
if (!('A'<=drv_let<='Z')) {
|
||||
if (except)
|
||||
throw('Drv');
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
dv=blkdev.let_to_drv[drv_let-'A'];
|
||||
}
|
||||
return DrvChk(dv,except);
|
||||
}
|
||||
|
||||
CBlkDev *DrvIsWritable(U8 drv_let=0,Bool except=FALSE)
|
||||
{//Is drive writable?
|
||||
CBlkDev *bd;
|
||||
if (!(bd=Let2BlkDev(drv_let,except)) || bd->flags & BDF_READ_ONLY) {
|
||||
if (except)
|
||||
throw('Drv');
|
||||
else
|
||||
return NULL;
|
||||
} else
|
||||
return bd;
|
||||
}
|
||||
|
||||
U0 DskCacheInvalidate(CDrv *dv)
|
||||
{//Needed for removable media. Called by $LK,"ChgDsk",A="MN:ChgDsk"$().
|
||||
Bool unlock;
|
||||
CBlkDev *bd=dv->bd;
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
BlkDevInit(bd);
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
DskCacheInvalidate2(dv);
|
||||
if (bd->type==BDT_ATAPI && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
|
||||
ISOInit(dv,(32767/bd->blk_size+1)*bd->blk_size>>BLK_SIZE_BITS);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
U0 ChgDsk(U8 drv_let=0)
|
||||
{//Change disk. (Needed for removable media.)
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
CBlkDev *bd=dv->bd;
|
||||
if (!(bd->flags&BDF_INITIALIZED))
|
||||
BlkDevInit(bd);
|
||||
else if (bd->flags&BDF_REMOVABLE) {
|
||||
if (bd->type==BDT_ATAPI)
|
||||
ATAInit(bd); //TODO: This is a kludge for QEMU?
|
||||
DskCacheInvalidate(dv);
|
||||
}
|
||||
Drv(drv_let);
|
||||
RedSeaFreeFreeLst(dv);
|
||||
}
|
||||
|
||||
Bool DrvMap(U8 drv_let,CDrv *dv)
|
||||
{//Make drive letter map to another.
|
||||
drv_let=Let2Let(drv_let);
|
||||
if ('A'<=drv_let<='Z') {
|
||||
blkdev.let_to_drv[drv_let-'A']=dv;
|
||||
dv->drv_let=drv_let;
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool Drv(U8 drv_let)
|
||||
{//Change drive. You can set drive with $LK,"Cd",A="MN:Cd"$() as well.
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
CBlkDev *bd;
|
||||
bd=BlkDevChk(dv->bd);
|
||||
if (dv!=Fs->cur_dv) {
|
||||
if (bd->flags & BDF_REMOVABLE && !(bd->flags & BDF_INITIALIZED))
|
||||
ChgDsk(Drv2Let(dv));
|
||||
if (bd->type==BDT_RAM ||
|
||||
bd->type==BDT_ISO_FILE_READ || bd->type==BDT_ISO_FILE_WRITE)
|
||||
BlkDevInit(bd);
|
||||
}
|
||||
Fs->cur_dv=dv;
|
||||
Free(Fs->cur_dir);
|
||||
Fs->cur_dir=StrNew("/");
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
case FSt_FAT32:
|
||||
case FSt_ISO9660:
|
||||
return TRUE;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
U8 *DrvSerialNum(U8 drv_let=0)
|
||||
{//20 bytes max.
|
||||
CBlkDev *bd=Let2BlkDev(drv_let);
|
||||
U16 *st,*res=NULL;
|
||||
I64 i;
|
||||
if (bd->dev_id_record) {
|
||||
st=CAlloc(20+1);
|
||||
for (i=0;i<10;i++)
|
||||
st[i]=EndianU16(bd->dev_id_record[10+i]);
|
||||
res=MStrUtil(st,SUF_REM_LEADING|SUF_REM_TRAILING);
|
||||
Free(st);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *DrvModelNum(U8 drv_let=0)
|
||||
{//40 bytes max.
|
||||
CBlkDev *bd=Let2BlkDev(drv_let);
|
||||
U16 *st,*res=NULL;
|
||||
I64 i;
|
||||
if (bd->dev_id_record) {
|
||||
st=CAlloc(40+1);
|
||||
for (i=0;i<20;i++)
|
||||
st[i]=EndianU16(bd->dev_id_record[27+i]);
|
||||
res=MStrUtil(st,SUF_REM_LEADING|SUF_REM_TRAILING);
|
||||
Free(st);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 blkdev_text_attr[BDT_TYPES_NUM]={BLACK,LTCYAN,WHITE,LTGREEN,LTRED,LTBLUE};
|
||||
U8 drv_text_attr[3]={BLACK,BLUE,RED};
|
||||
|
||||
U8 DrvTextAttrGet(U8 drv_let=0)
|
||||
{//Get color of drive.
|
||||
drv_let=Let2Let(drv_let);
|
||||
if ('A'<=drv_let<='Z')
|
||||
return blkdev_text_attr[Let2BlkDevType(drv_let)]<<4|
|
||||
drv_text_attr[drv_let%sizeof(drv_text_attr)];
|
||||
else
|
||||
return BLACK<<4|WHITE;
|
||||
}
|
||||
|
||||
U0 DrvRep()
|
||||
{//Drive report.
|
||||
CDrv *dv;
|
||||
CBlkDev *bd;
|
||||
I64 ch,i,drv_let,attr;
|
||||
U8 *st;
|
||||
"\nDefined Drives:\n";
|
||||
for (i=0,dv=blkdev.drvs;i<DRVS_NUM;i++,dv++) {
|
||||
if (dv->dv_signature==DRV_SIGNATURE_VAL) {
|
||||
bd=dv->bd;
|
||||
drv_let=Drv2Let(dv);
|
||||
if (Bt(&dv->fs_type,FStf_DISABLE))
|
||||
ch='-';
|
||||
else if (drv_let==blkdev.boot_drv_let)
|
||||
ch=':';
|
||||
else
|
||||
ch='+';
|
||||
attr=DrvTextAttrGet(drv_let);
|
||||
"$$FG,%d$$$$BG,%d$$%C %-8Z %-10Z %04X %04X %02X\n",
|
||||
attr&15,attr>>4,drv_let,dv->fs_type&FSG_TYPE_MASK,"ST_DRV_TYPES",
|
||||
bd->type,"ST_BLKDEV_TYPES",bd->base0,bd->base1,bd->unit;
|
||||
if (st=DrvModelNum(drv_let)) {
|
||||
" Model# :%s\n",st;
|
||||
Free(st);
|
||||
}
|
||||
if (st=DrvSerialNum(drv_let)) {
|
||||
" Serial#:%s\n",st;
|
||||
Free(st);
|
||||
}
|
||||
if (bd->type==BDT_ISO_FILE_READ || bd->type==BDT_ISO_FILE_WRITE)
|
||||
" File=\"%s\"\n",bd->file_dsk_name;
|
||||
" %016X-%016X\n$$FG$$$$BG$$",dv->drv_offset,dv->drv_offset+dv->size-1;
|
||||
}
|
||||
}
|
||||
"Home Dir:\"%s\"\n",blkdev.home_dir;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
U8 *FileRead(U8 *filename,I64 *_size=NULL,I64 *_attr=NULL)
|
||||
{//Read whole file from disk.
|
||||
CHashGeneric *tmph;
|
||||
U8 *absname,*altname,*curname,*res=NULL;
|
||||
I64 i,size=0,attr=0;
|
||||
CDirContext *dirc;
|
||||
CArcCompress *arc;
|
||||
absname=FileNameAbs(filename);
|
||||
altname=ToggleZorNotZ(absname);
|
||||
if ((tmph=HashFind(absname,adam_task->hash_table,HTT_FILE))||
|
||||
(tmph=HashFind(altname,adam_task->hash_table,HTT_FILE))) {
|
||||
size=tmph->user_data1;
|
||||
res=MAlloc(size+1);
|
||||
MemCpy(res,tmph->user_data0,size);
|
||||
res[size]=0; //Terminate
|
||||
attr=FileAttr(tmph->str,attr);
|
||||
} else {
|
||||
for (i=0;i<2 && !res;i++) {//Try name, then altname
|
||||
if (!i)
|
||||
curname=absname;
|
||||
else
|
||||
curname=altname;
|
||||
if (dirc=DirContextNew(curname)) {
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
}
|
||||
|
||||
//Search parent directories.
|
||||
for (i=0;i<2 && !res;i++) {//Try name, then altname
|
||||
if (!i)
|
||||
curname=absname;
|
||||
else
|
||||
curname=altname;
|
||||
if (dirc=DirContextNew(curname)) {
|
||||
while (!res && StrCmp(Fs->cur_dir,"/")) {
|
||||
Cd("..");
|
||||
switch (Fs->cur_dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FileRead(dirc->dv,Fs->cur_dir,dirc->mask,&size,&attr);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
"%s ",filename;
|
||||
PrintErr("File not found.\n");
|
||||
}
|
||||
if (res && attr & RS_ATTR_RESIDENT)
|
||||
HashGenericAdd(curname,HTT_FILE,AMAllocIdent(res),size,0,adam_task);
|
||||
}
|
||||
if (res && attr & RS_ATTR_COMPRESSED) {
|
||||
arc=res;
|
||||
size=arc->expanded_size;
|
||||
res=ExpandBuf(arc);
|
||||
Free(arc);
|
||||
}
|
||||
if (_attr) *_attr=attr;
|
||||
if (_size) *_size=size;
|
||||
Free(absname);
|
||||
Free(altname);
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 FileWrite(U8 *filename,U8 *fbuf,I64 size,CDate cdt=0,I64 attr=0)
|
||||
{//Write whole file to disk.
|
||||
I64 c=0;
|
||||
CHashGeneric *tmph;
|
||||
CDirContext *dirc;
|
||||
U8 *fbuf2,*absname=FileNameAbs(filename);
|
||||
if (dirc=DirContextNew(filename,FALSE,TRUE)) {
|
||||
attr=FileAttr(dirc->mask,attr);
|
||||
if (attr&RS_ATTR_COMPRESSED) {
|
||||
fbuf=CompressBuf(fbuf,size);
|
||||
size=fbuf(CArcCompress *)->compressed_size;
|
||||
fbuf2=fbuf;
|
||||
} else
|
||||
fbuf2=NULL;
|
||||
if (!cdt) cdt=Now;
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
c=RedSeaFileWrite(dirc->dv,Fs->cur_dir,dirc->mask,fbuf,size,cdt,attr);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
c=FAT32FileWrite(dirc->dv,Fs->cur_dir,dirc->mask,fbuf,size,cdt,attr);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
if (tmph=HashFind(absname,adam_task->hash_table,HTT_FILE)) {
|
||||
if (attr & RS_ATTR_RESIDENT) {
|
||||
Free(tmph->user_data0);
|
||||
tmph->user_data0=AMAllocIdent(fbuf);
|
||||
tmph->user_data1=size;
|
||||
} else
|
||||
HashRemDel(tmph,adam_task->hash_table);
|
||||
} else if (attr & RS_ATTR_RESIDENT)
|
||||
HashGenericAdd(absname,HTT_FILE,AMAllocIdent(fbuf),size,0,adam_task);
|
||||
Free(fbuf2);
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
Free(absname);
|
||||
return c;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
CDirEntry *FilesFind2(U8 *files_find_mask,I64 fuf_flags)
|
||||
{
|
||||
CDrv *dv=Fs->cur_dv;
|
||||
CDirEntry *res=NULL;
|
||||
DrvChk(dv);
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFilesFind(files_find_mask,fuf_flags);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FilesFind(files_find_mask,fuf_flags);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FilesFind(files_find_mask,fuf_flags);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
res=NULL;
|
||||
}
|
||||
if (res) {
|
||||
DirFilesSort(&res,SK_NAME);
|
||||
if (fuf_flags&(FUF_FLATTEN_TREE|FUF_JUST_FILES))
|
||||
DirFilesFlatten(res,&res,fuf_flags);
|
||||
if (fuf_flags&FUF_CLUSTER_ORDER)
|
||||
DirFilesSort(&res,SK_CLUSTER);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
CDirEntry *FilesFind(U8 *files_find_mask,I64 fuf_flags=0)
|
||||
{/* See $LK,"::/Doc/FileUtils.DD"$.
|
||||
|
||||
Find files and make a directory tree in memory.
|
||||
|
||||
When done, you free with $LK,"DirEntryDel",A="MN:DirEntryDel"$(),$LK,"DirEntryDel2",A="MN:DirEntryDel2"$(),
|
||||
$LK,"DirTreeDel",A="MN:DirTreeDel"$() or $LK,"DirTreeDel2",A="MN:DirTreeDel2"$().
|
||||
|
||||
*/
|
||||
CDirEntry *res;
|
||||
CDirContext *dirc;
|
||||
if (fuf_flags&~FUG_FILES_FIND)
|
||||
throw('FUF');
|
||||
if (fuf_flags&FUF_SINGLE) {
|
||||
res=MAlloc(sizeof(CDirEntry));
|
||||
if (!FileFind(files_find_mask,res)) {
|
||||
Free(res);
|
||||
return NULL;
|
||||
}
|
||||
} else if (dirc=DirContextNew(files_find_mask,TRUE)) {
|
||||
res=FilesFind2(dirc->mask,fuf_flags);
|
||||
DirContextDel(dirc);
|
||||
} else
|
||||
return NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FileFind(U8 *filename,CDirEntry *_de=NULL,I64 fuf_flags=0)
|
||||
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$, $LK,"FUF_Z_OR_NOT_Z",A="MN:FUF_Z_OR_NOT_Z"$, $LK,"FUF_SCAN_PARENTS",A="MN:FUF_SCAN_PARENTS"$
|
||||
//If you pass _de, you must Free(_de->full_name);
|
||||
I64 i,j,cur_dir_cluster;
|
||||
U8 *altname,*curname,*full_name=NULL;
|
||||
CDirEntry de;
|
||||
CDirContext *dirc;
|
||||
Bool res=FALSE,old_silent;
|
||||
if (fuf_flags&~FUG_FILE_FIND)
|
||||
throw('FUF');
|
||||
if (!filename || *filename && filename[1]==':' && !Let2Drv(*filename,FALSE))
|
||||
return FALSE;
|
||||
altname=ToggleZorNotZ(filename);
|
||||
if (fuf_flags&FUF_Z_OR_NOT_Z)
|
||||
j=2;
|
||||
else
|
||||
j=1;
|
||||
for (i=0;i<j && !res;i++) {
|
||||
if (!i)
|
||||
curname=filename;
|
||||
else
|
||||
curname=altname;
|
||||
old_silent=Silent;
|
||||
if (!(dirc=DirContextNew(curname)))
|
||||
Silent(old_silent);
|
||||
else {
|
||||
Silent(old_silent);
|
||||
cur_dir_cluster=Name2DirCluster(dirc->dv,Fs->cur_dir);
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFileFind(dirc->dv,cur_dir_cluster,dirc->mask,
|
||||
&de,fuf_flags);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FileFind(dirc->dv,cur_dir_cluster,dirc->mask,
|
||||
&de,fuf_flags);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FileFind(dirc->dv,cur_dir_cluster,dirc->mask,
|
||||
&de,fuf_flags);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
if (res && _de) {
|
||||
if (StrCmp(Fs->cur_dir,"/"))
|
||||
full_name=MStrPrint("%C:%s/%s",
|
||||
Drv2Let(Fs->cur_dv),Fs->cur_dir,de.name);
|
||||
else
|
||||
full_name=MStrPrint("%C:/%s",Drv2Let(Fs->cur_dv),de.name);
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
}
|
||||
for (i=0;i<j && !res && fuf_flags&FUF_SCAN_PARENTS;i++) {
|
||||
if (!i)
|
||||
curname=filename;
|
||||
else
|
||||
curname=altname;
|
||||
old_silent=Silent;
|
||||
if (!(dirc=DirContextNew(curname)))
|
||||
Silent(old_silent);
|
||||
else {
|
||||
Silent(old_silent);
|
||||
cur_dir_cluster=Name2DirCluster(dirc->dv,Fs->cur_dir);
|
||||
while (!res && StrCmp(Fs->cur_dir,"/")) {
|
||||
Cd("..");
|
||||
cur_dir_cluster=Name2DirCluster(dirc->dv,Fs->cur_dir);
|
||||
switch (dirc->dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
res=RedSeaFileFind(dirc->dv,cur_dir_cluster,
|
||||
dirc->mask,&de,fuf_flags);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
res=FAT32FileFind(dirc->dv,cur_dir_cluster,
|
||||
dirc->mask,&de,fuf_flags);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
res=ISO1FileFind(dirc->dv,cur_dir_cluster,
|
||||
dirc->mask,&de,fuf_flags);
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
}
|
||||
if (res && _de) {
|
||||
if (StrCmp(Fs->cur_dir,"/"))
|
||||
full_name=MStrPrint("%C:%s/%s",
|
||||
Drv2Let(Fs->cur_dv),Fs->cur_dir,de.name);
|
||||
else
|
||||
full_name=MStrPrint("%C:/%s",
|
||||
Drv2Let(Fs->cur_dv),de.name);
|
||||
}
|
||||
DirContextDel(dirc);
|
||||
}
|
||||
}
|
||||
if (_de) {
|
||||
if (res) {
|
||||
MemCpy(_de,&de,sizeof(CDirEntry));
|
||||
_de->full_name=full_name;
|
||||
} else
|
||||
MemSet(_de,0,sizeof(CDirEntry));
|
||||
}
|
||||
Free(altname);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
Bool DrvTypeSet(U8 drv_let,I64 type=FSt_REDSEA)
|
||||
{//Very dangerous
|
||||
I64 i,j,ext_base,drv_num,offset,cur_type;
|
||||
CMasterBoot mbr;
|
||||
CBlkDev *bd;
|
||||
drv_let=Let2Let(drv_let);
|
||||
bd=Let2BlkDev(drv_let);
|
||||
drv_num=bd->first_drv_let-'A';
|
||||
switch (bd->type) {
|
||||
case BDT_ATA:
|
||||
offset=0;
|
||||
ext_base=INVALID_CLUSTER;
|
||||
while (TRUE) {
|
||||
ATAReadBlks(bd,&mbr,offset,1);
|
||||
j=-1;
|
||||
for (i=0;i<4;i++) {
|
||||
cur_type=mbr.p[i].type;
|
||||
if (cur_type) {
|
||||
if (cur_type==5 || cur_type==15)
|
||||
j=i;
|
||||
else {
|
||||
if (drv_num+'A'==drv_let) {
|
||||
switch (type) {
|
||||
case FSt_REDSEA:
|
||||
mbr.p[i].type=MBR_PT_REDSEA;
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
mbr.p[i].type=MBR_PT_FAT32a;
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
mbr.p[i].active=0x80;
|
||||
ATAWriteBlks(bd,&mbr,offset,1);
|
||||
return TRUE;
|
||||
}
|
||||
drv_num++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (j<0)
|
||||
break;
|
||||
if (!mbr.p[j].offset)
|
||||
break;
|
||||
if (ext_base==INVALID_CLUSTER) {
|
||||
offset=mbr.p[j].offset;
|
||||
ext_base=offset;
|
||||
} else
|
||||
offset=mbr.p[j].offset+ext_base;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
U0 Fmt(I64 drv_let,Bool quick=TRUE,Bool confirm=TRUE,I64 type=FSt_FAT32)
|
||||
{//Format hard drive or RAM drive.
|
||||
//$BK,1$Warning:$BK,0$ Destroys all prev info.
|
||||
//quick=FALSE means fill entire drive with zeros.
|
||||
//Choose $LK,"FSt_FAT32",A="MN:FSt_FAT32"$ or $LK,"FSt_REDSEA",A="MN:FSt_REDSEA"$.
|
||||
//You don't format a CD/DVD with this.
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
Bool old_silent=IsSilent;
|
||||
if (confirm && !AreYouSure)
|
||||
return;
|
||||
if (!dv) {
|
||||
PrintErr("Invalid Drive\n");
|
||||
return;
|
||||
}
|
||||
switch (type) {
|
||||
case FSt_FAT32:
|
||||
if (dv->bd->type==BDT_ATA) {
|
||||
Silent;
|
||||
Drv(drv_let);
|
||||
Silent(old_silent);
|
||||
FAT32Fmt(drv_let,quick);
|
||||
DskCacheInvalidate(Let2Drv(drv_let));
|
||||
Drv(drv_let);
|
||||
break;
|
||||
}
|
||||
"Using RedSea File System.\n";
|
||||
case FSt_REDSEA:
|
||||
Silent;
|
||||
Drv(drv_let);
|
||||
Silent(old_silent);
|
||||
RedSeaFmt(drv_let,quick);
|
||||
DskCacheInvalidate(Let2Drv(drv_let));
|
||||
Drv(drv_let);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
PrintErr("Not Writable\n");
|
||||
break;
|
||||
default:
|
||||
PrintErr("File System Not Supported\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
U8 *FileExtDot(U8 *src)
|
||||
{//Find dot char in name.
|
||||
I64 ch;
|
||||
while (ch=*src++)
|
||||
if (ch=='.' && *src!='/' && *src!='.')
|
||||
return src-1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
U8 *FileExtRem(U8 *src,U8 *dst=NULL)
|
||||
{//Remove filename extension from str.
|
||||
U8 *ptr;
|
||||
if (ptr=FileExtDot(src)) {
|
||||
if (dst)
|
||||
StrCpy(dst,ptr+1);
|
||||
*ptr=0;
|
||||
} else if (dst)
|
||||
*dst=0;
|
||||
return dst;
|
||||
}
|
||||
|
||||
Bool IsDotZ(U8 *filename)
|
||||
{//Does name end in .Z?
|
||||
I64 i=StrLen(filename);
|
||||
if (StrOcc(filename,'.')>1 && filename[i-1]=='Z' && filename[i-2]=='.')
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool IsDotC(U8 *filename)
|
||||
{//Does name end in .C?
|
||||
I64 i=StrLen(filename);
|
||||
if (StrOcc(filename,'.')>1 && filename[i-1]=='C' && filename[i-2]=='.')
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool FilesFindMatch(U8 *_test_name,U8 *files_find_mask,I64 fuf_flags=0)
|
||||
{//Does filename meet $LK,"Files Find",A="FI:::/Doc/FileUtils.DD"$ mask?
|
||||
I64 tn_len=StrLen(_test_name),mask_len=StrLen(files_find_mask);
|
||||
U8 *mask1=MAlloc(mask_len+1),*mask2=MAlloc(mask_len+1),
|
||||
*ptr,*test_name1,*test_name2;
|
||||
Bool res=FALSE;
|
||||
StrCpy(mask1,files_find_mask);
|
||||
if (StrOcc(_test_name,'/')) {
|
||||
test_name1=MAlloc(tn_len+1);
|
||||
test_name2=MAlloc(tn_len+1);
|
||||
StrCpy(test_name1,_test_name);
|
||||
StrLastRem(test_name1,"/",test_name2);
|
||||
} else {
|
||||
test_name1=NULL;
|
||||
test_name2=NULL;
|
||||
}
|
||||
while (TRUE) {
|
||||
StrFirstRem(mask1,";",mask2);
|
||||
if (!test_name2 || StrOcc(mask2,'/'))
|
||||
ptr=_test_name;
|
||||
else
|
||||
ptr=test_name2;
|
||||
if (*mask2) {
|
||||
if (*mask2=='!') {
|
||||
if (WildMatch(ptr,mask2+1)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (WildMatch(ptr,mask2)) {
|
||||
if (Bt(&fuf_flags,FUf_JUST_TXT) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_TXT)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_DD) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_DD)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_SRC) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_SRC)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_AOT) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_AOT)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_JIT) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_JIT)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else if (Bt(&fuf_flags,FUf_JUST_GR) &&
|
||||
!FilesFindMatch(_test_name,FILEMASK_GR)) {
|
||||
res=FALSE;
|
||||
break;
|
||||
} else
|
||||
res=TRUE;
|
||||
}
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
Free(test_name1);
|
||||
Free(test_name2);
|
||||
Free(mask1);
|
||||
Free(mask2);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *DirNameAbs(U8 *_dirname)
|
||||
{//MAlloc absolute dir string with drv letter.
|
||||
I64 maxlen;
|
||||
U8 drv[3],*res,*buf,*buf2,*buf3,*buf4,*dirname,*free_dirname;
|
||||
if (!Fs->cur_dir || !*Fs->cur_dir)
|
||||
return StrNew(_dirname);
|
||||
free_dirname=dirname=MStrUtil(_dirname,
|
||||
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
*drv=Drv2Let;
|
||||
drv[1]=':';
|
||||
drv[2]=0;
|
||||
if (*dirname && dirname[1]==':') {
|
||||
if (*dirname==':')
|
||||
*drv=blkdev.boot_drv_let;
|
||||
else if (*dirname=='~')
|
||||
*drv=*blkdev.home_dir;
|
||||
else
|
||||
*drv=*dirname;
|
||||
dirname=dirname+2;
|
||||
buf=StrNew("/");
|
||||
} else
|
||||
buf=StrNew(Fs->cur_dir);
|
||||
if (*dirname=='/') {
|
||||
Free(buf);
|
||||
buf=StrNew("/");
|
||||
dirname++;
|
||||
}
|
||||
buf2=StrNew(dirname);
|
||||
maxlen=StrLen(buf)+1+StrLen(buf2)+1;
|
||||
buf3=MAlloc(maxlen);
|
||||
buf4=MAlloc(maxlen);
|
||||
StrCpy(buf3,buf);
|
||||
while (*buf2) {
|
||||
StrFirstRem(buf2,"/",buf4);
|
||||
if (!*buf4)
|
||||
StrCpy(buf3,"/");
|
||||
else if (!StrCmp(buf4,"..")) {
|
||||
StrLastRem(buf3,"/");
|
||||
if (!*buf3)
|
||||
StrCpy(buf3,"/");
|
||||
} else if (!StrCmp(buf4,"~")) {
|
||||
Free(buf3);
|
||||
buf3=MAlloc(StrLen(blkdev.home_dir+2)+1+StrLen(buf2)+1);
|
||||
StrCpy(buf3,blkdev.home_dir+2);
|
||||
*drv=*blkdev.home_dir;
|
||||
} else if (!StrCmp(buf4,"."));
|
||||
else if (*buf4) {
|
||||
if (StrCmp(buf3,"/"))
|
||||
CatPrint(buf3,"/");
|
||||
CatPrint(buf3,buf4);
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
res=MAlloc(StrLen(buf3)+3);
|
||||
StrCpy(res,drv);
|
||||
StrCpy(res+2,buf3);
|
||||
Free(buf2);
|
||||
Free(buf3);
|
||||
Free(buf4);
|
||||
Free(free_dirname);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *FileNameAbs(U8 *_filename,I64 fuf_flags=0)
|
||||
{//Absolute filename. Accepts $LK,"FUF_Z_OR_NOT_Z",A="MN:FUF_Z_OR_NOT_Z"$, $LK,"FUF_SCAN_PARENTS",A="MN:FUF_SCAN_PARENTS"$.
|
||||
U8 *res,*filename,*buf,*buf_file,*buf_dir,*free_filename,*free_buf;
|
||||
CDirEntry de;
|
||||
free_filename=filename=MStrUtil(_filename,
|
||||
SUF_REM_LEADING|SUF_REM_TRAILING|SUF_REM_CTRL_CHARS);
|
||||
free_buf=buf=StrNew(filename);
|
||||
if (*buf && buf[1]==':') {
|
||||
buf+=2;
|
||||
filename+=2;
|
||||
}
|
||||
buf_file=MAlloc(StrLen(free_filename)+1);
|
||||
StrLastRem(buf,"/",buf_file);
|
||||
if (*filename=='/' && !*buf)
|
||||
StrCpy(buf,"/");
|
||||
buf_dir=DirNameAbs(free_buf);
|
||||
Free(free_buf);
|
||||
res=MAlloc(StrLen(buf_dir)+1+StrLen(buf_file)+1);
|
||||
StrCpy(res,buf_dir);
|
||||
if (res[StrLen(res)-1]!='/')
|
||||
CatPrint(res,"/");
|
||||
CatPrint(res,buf_file);
|
||||
Free(buf_file);
|
||||
Free(buf_dir);
|
||||
Free(free_filename);
|
||||
if (fuf_flags && FileFind(res,&de,fuf_flags|FUF_JUST_FILES)) {
|
||||
Free(res);
|
||||
res=de.full_name;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *ChgExt(U8 *filename,U8 *extension)
|
||||
{//Change filename extension.
|
||||
U8 *res=MAlloc(StrLen(filename)+1+StrLen(extension)+1);
|
||||
StrCpy(res,filename);
|
||||
if (FileExtDot(filename))
|
||||
FileExtRem(res);
|
||||
return CatPrint(res,".%s",extension);
|
||||
}
|
||||
|
||||
U8 *DftExt(U8 *filename,U8 *extension)
|
||||
{//Give extension if has none.
|
||||
U8 *res=MAlloc(StrLen(filename)+1+StrLen(extension)+1);
|
||||
StrCpy(res,filename);
|
||||
if (!FileExtDot(filename))
|
||||
CatPrint(res,".%s",extension);
|
||||
return res;
|
||||
}
|
||||
|
||||
CDirEntry *Cd2DirEntry(CDirEntry *tmpde,U8 *abs_name)
|
||||
{
|
||||
I64 i;
|
||||
while (tmpde) {
|
||||
i=StrLen(tmpde->full_name);
|
||||
if (StrNCmp(tmpde->full_name,abs_name,i)||
|
||||
i && tmpde->full_name[i-1]!='/' && abs_name[i] && abs_name[i]!='/')
|
||||
tmpde=tmpde->next;
|
||||
else
|
||||
if (StrLen(abs_name)==i)
|
||||
return tmpde;
|
||||
else
|
||||
return Cd2DirEntry(tmpde->sub,abs_name);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
I64 FileAttr(U8 *name,I64 attr=0)
|
||||
{
|
||||
if (IsDotZ(name))
|
||||
attr|=RS_ATTR_COMPRESSED;
|
||||
else
|
||||
attr&=~RS_ATTR_COMPRESSED;
|
||||
if (IsDotC(name))
|
||||
attr|=RS_ATTR_CONTIGUOUS;
|
||||
return attr;
|
||||
}
|
||||
|
||||
Bool FileNameChk(U8 *filename)
|
||||
{//Return check for valid filename, not checking existence.
|
||||
U8 *ptr=filename;
|
||||
if (!filename) return FALSE;
|
||||
if (!*ptr) return FALSE;
|
||||
if (*ptr=='.') {
|
||||
if (!ptr[1]) return TRUE;
|
||||
if (ptr[1]=='.' && !ptr[2]) return TRUE;
|
||||
}
|
||||
if (StrLen(filename)>=CDIR_FILENAME_LEN) return FALSE;
|
||||
while (*ptr)
|
||||
if (!Bt(char_bmp_filename,*ptr++))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U8 *ToggleZorNotZ(U8 *name)
|
||||
{//MAlloc name with Z if not Z or vice versa.
|
||||
U8 *res;
|
||||
if (IsDotZ(name)) {
|
||||
res=StrNew(name);
|
||||
res[StrLen(name)-2]=0;
|
||||
} else
|
||||
res=MStrPrint("%s.Z",name);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *FileNameTmpTxt()
|
||||
{//Make pretty-safe tmp filename in home dir.
|
||||
return MStrPrint("~/SysTmp%X.DD.Z",GetTSC>>8&0xFFFFFFFF);
|
||||
}
|
||||
|
||||
U8 *CurDir(CTask *task=NULL,CTask *mem_task=NULL)
|
||||
{//MAlloc copy of cur dir with drv letter.
|
||||
U8 *st;
|
||||
if (!task) task=Fs;
|
||||
if (!task->cur_dir)
|
||||
return NULL;
|
||||
st=MAlloc(StrLen(task->cur_dir)+3,mem_task);
|
||||
*st=Drv2Let(task->cur_dv);
|
||||
st[1]=':';
|
||||
StrCpy(st+2,task->cur_dir);
|
||||
return st;
|
||||
}
|
||||
|
||||
U8 *DirFile(U8 *dirname,U8 *name=NULL,U8 *_extension=NULL)
|
||||
{/*Strips file from dirname, scans for file upward until found or
|
||||
returns default.
|
||||
|
||||
("/Kernel/KHashA.HC.Z",NULL,NULL) returns "D:/Kernel"
|
||||
("/Kernel",NULL,"PRJ.Z") returns "D:/Kernel/Kernel.PRJ.Z"
|
||||
("/Kernel/BlkDev",NULL,"PRJ.Z") returns "D:/Kernel/Kernel.PRJ.Z"
|
||||
("/Apps/Psalmody","Load","HC.Z") returns "D:/Apps/Psalmody/Load.HC.Z"
|
||||
*/
|
||||
U8 *st=DirNameAbs(dirname),*st2,*st3,*res,*dft=NULL,*ext;
|
||||
if (_extension && *_extension) {
|
||||
if (*_extension=='.')
|
||||
ext=StrNew(_extension);
|
||||
else
|
||||
ext=MStrPrint(".%s",_extension);
|
||||
} else
|
||||
ext=StrNew("");
|
||||
while (StrOcc(st,'/')&&!IsDir(st))
|
||||
StrLastRem(st,"/");
|
||||
while (StrOcc(st,'/')) {
|
||||
st2=StrNew(st);
|
||||
st3=StrNew(st);
|
||||
StrLastRem(st2,"/",st3);
|
||||
|
||||
if (name)
|
||||
res=MStrPrint("%s/%s%s",st,name,ext);
|
||||
else {
|
||||
if (*ext)
|
||||
res=MStrPrint("%s/%s%s",st,st3,ext);
|
||||
else
|
||||
res=StrNew(st);
|
||||
}
|
||||
if (!dft)
|
||||
dft=StrNew(res);
|
||||
if (!*ext && (!name||!*name) || FileFind(res)) {
|
||||
Free(st3);
|
||||
Free(st2);
|
||||
Free(st);
|
||||
Free(dft);
|
||||
Free(ext);
|
||||
return res;
|
||||
}
|
||||
Free(st);
|
||||
st=st2;
|
||||
Free(st3);
|
||||
}
|
||||
Free(st);
|
||||
Free(ext);
|
||||
return dft;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
Bool CFileNameTo(U8 *dst,U8 *src)
|
||||
{
|
||||
MemSet(dst,0,CDIR_FILENAME_LEN);
|
||||
if (!FileNameChk(src))
|
||||
return FALSE;
|
||||
StrCpy(dst,src);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
I64 Name2DirCluster(CDrv *dv,U8 *dirname)
|
||||
{
|
||||
Bool cont=TRUE,unlock;
|
||||
I64 cur_dir_cluster;
|
||||
CDirEntry de;
|
||||
U8 *buf=StrNew(dirname),*buf2=StrNew(dirname);
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
cur_dir_cluster=dv->root_cluster;
|
||||
while (*buf && cont) {
|
||||
StrFirstRem(buf,"/",buf2);
|
||||
if (*buf2) {
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
cont=RedSeaFileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
cont=FAT32FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
cont=ISO1FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
cur_dir_cluster=de.cluster;
|
||||
}
|
||||
}
|
||||
if (!cont) {
|
||||
"%s ",dirname;
|
||||
PrintErr("File not found.\n");
|
||||
cur_dir_cluster=0;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
Free(buf);
|
||||
Free(buf2);
|
||||
return cur_dir_cluster;
|
||||
}
|
||||
|
||||
I64 Name2ParentDirCluster(CDrv *dv,U8 *dirname)
|
||||
{
|
||||
Bool cont=TRUE,unlock;
|
||||
I64 cur_dir_cluster,cur_dir_cluster2;
|
||||
CDirEntry de;
|
||||
U8 *buf=StrNew(dirname),*buf2=StrNew(dirname);
|
||||
DrvChk(dv);
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
cur_dir_cluster=cur_dir_cluster2=dv->root_cluster;
|
||||
while (*buf && cont) {
|
||||
cur_dir_cluster2=cur_dir_cluster;
|
||||
StrFirstRem(buf,"/",buf2);
|
||||
if (*buf2) {
|
||||
switch (dv->fs_type) {
|
||||
case FSt_REDSEA:
|
||||
cont=RedSeaFileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
case FSt_FAT32:
|
||||
cont=FAT32FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
case FSt_ISO9660:
|
||||
cont=ISO1FileFind(dv,cur_dir_cluster,buf2,&de,FUF_JUST_DIRS);
|
||||
break;
|
||||
default:
|
||||
throw('Drv');
|
||||
}
|
||||
cur_dir_cluster=de.cluster;
|
||||
}
|
||||
}
|
||||
if (!cont) {
|
||||
"%s ",dirname;
|
||||
PrintErr("File not found.\n");
|
||||
cur_dir_cluster2=0;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
Free(buf);
|
||||
Free(buf2);
|
||||
return cur_dir_cluster2;
|
||||
}
|
||||
@@ -0,0 +1,961 @@
|
||||
U0 CDate2Dos(U16 *t,U16 *d,CDate cdt)
|
||||
{
|
||||
CDateStruct ds;
|
||||
Date2Struct(&ds,cdt);
|
||||
*d=ds.day_of_mon+(ds.mon+(ds.year-1980)<<4)<<5;
|
||||
*t=ds.sec>>1+(ds.min+ds.hour<<6)<<5;
|
||||
}
|
||||
|
||||
CDate Dos2CDate(U16 t,U16 d)
|
||||
{
|
||||
CDateStruct ds;
|
||||
MemSet(&ds,0,sizeof(CDateStruct));
|
||||
ds.day_of_mon=d&0x1F; d=d>>5;
|
||||
ds.mon=d&0xF;
|
||||
ds.year=d>>4+1980;
|
||||
ds.sec=(t&0x1F)*2; t=t>>5;
|
||||
ds.min=t&0x3F;
|
||||
ds.hour=t>>6;
|
||||
return Struct2Date(&ds);
|
||||
}
|
||||
|
||||
U0 FAT32Init(CDrv *dv)
|
||||
{
|
||||
CFAT32Boot br32;
|
||||
Bool unlock;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
dv->fs_type=FSt_FAT32;
|
||||
RBlks(dv,&br32,dv->drv_offset,1);
|
||||
dv->file_system_info_sect=dv->drv_offset+br32.file_system_info_sect;
|
||||
dv->fat1=dv->drv_offset+br32.reserved_sects;
|
||||
dv->fat2=dv->fat1+br32.sects_per_fat;
|
||||
dv->data_area=dv->fat2+br32.sects_per_fat
|
||||
-2*br32.sects_per_cluster; //Starts at Cluster 2
|
||||
dv->spc=br32.sects_per_cluster;
|
||||
dv->root_cluster=br32.root_cluster;
|
||||
DrvFATBlkAlloc(dv);
|
||||
Free(dv->fis);
|
||||
dv->fis=AMAlloc(BLK_SIZE);
|
||||
RBlks(dv,dv->fis,dv->file_system_info_sect,1);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
U0 FAT32Fmt(U8 drv_let,Bool quick=TRUE)
|
||||
{
|
||||
CFAT32Boot *br=CAlloc(BLK_SIZE);
|
||||
CFAT32FileInfoSect *fis=CAlloc(BLK_SIZE);
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
I64 i,l;
|
||||
try {
|
||||
DrvLock(dv);
|
||||
DrvTypeSet(drv_let,FSt_FAT32);
|
||||
dv->fs_type=FSt_FAT32;
|
||||
br->jump_and_nop[0]=OC_JMP_REL8;
|
||||
br->jump_and_nop[1]=offset(CFAT32Boot.code)-2;
|
||||
br->jump_and_nop[2]=OC_NOP;
|
||||
br->oem_name[0](I64)='MSWIN4.1';
|
||||
br->bytes_per_sect=BLK_SIZE;
|
||||
if (dv->size<= 500000)
|
||||
br->sects_per_cluster=1;
|
||||
else if (dv->size<=2000000)
|
||||
br->sects_per_cluster=2;
|
||||
else if (dv->size<=6000000)
|
||||
br->sects_per_cluster=4;
|
||||
else if (dv->size<=12000000)
|
||||
br->sects_per_cluster=8;
|
||||
else if (dv->size<=33000000)
|
||||
br->sects_per_cluster=16;
|
||||
else if (dv->size<=67000000)
|
||||
br->sects_per_cluster=32;
|
||||
else
|
||||
br->sects_per_cluster=64;
|
||||
|
||||
br->reserved_sects=32;
|
||||
br->copies_of_fat=2;
|
||||
br->media_desc=0xF8;
|
||||
br->sects=dv->size;
|
||||
l=(br->sects/br->sects_per_cluster)>>(BLK_SIZE_BITS-2)+1;
|
||||
br->sects_per_fat=l;
|
||||
br->root_cluster=2;
|
||||
br->file_system_info_sect=1;
|
||||
br->log_drv_num=0x80;
|
||||
br->ext_signature=0x29;
|
||||
br->serial_num=RandU32;
|
||||
MemCpy(br->vol_name,"NO NAME ",11);
|
||||
br->fat_name[0](I64)='FAT32 ';
|
||||
br->signature=0xAA55;
|
||||
fis->signature1='RRaA';
|
||||
fis->signature2='rrAa';
|
||||
fis->free_clusters=-1;
|
||||
fis->most_recently_alloced=0;
|
||||
fis->signature3=0xAA550000;
|
||||
|
||||
if (quick)
|
||||
i=br->reserved_sects+2*l+4*br->sects_per_cluster;
|
||||
else
|
||||
i=dv->size;
|
||||
WZeroBlks(dv,dv->drv_offset,i);
|
||||
|
||||
WBlks(dv,fis,dv->drv_offset+br->file_system_info_sect,1);
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
FAT32Init(dv);
|
||||
ClustersAlloc(dv,0,1,FALSE); //Alloc #1
|
||||
br->root_cluster=ClustersAlloc(dv,0,1,FALSE);
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
FAT32Init(dv);
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
Free(br);
|
||||
Free(fis);
|
||||
}
|
||||
|
||||
Bool FATNameTo(U8 *dst,U8 *src)
|
||||
{
|
||||
I64 i;
|
||||
MemSet(dst,CH_SPACE,11);
|
||||
if (!FileNameChk(src))
|
||||
return FALSE;
|
||||
if (!StrCmp(src,"..")) {
|
||||
*dst='.';
|
||||
dst[1]='.';
|
||||
return TRUE;
|
||||
} else if (!StrCmp(src,".")) {
|
||||
*dst='.';
|
||||
return TRUE;
|
||||
}
|
||||
i=0;
|
||||
while (i<8 && *src && *src!='.')
|
||||
dst[i++]=ToUpper(*src++);
|
||||
i=8;
|
||||
if (*src=='.') src++;
|
||||
while (*src)
|
||||
if (*src!='.')
|
||||
dst[i++]=ToUpper(*src++);
|
||||
else
|
||||
src++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
I64 FATNameXSum(U8 *src)
|
||||
{
|
||||
I64 i,res=0;
|
||||
for (i=0;i<11;i++)
|
||||
if (res&1)
|
||||
res.u8[0]=0x80+res>>1+*src++;
|
||||
else
|
||||
res.u8[0]=res>>1+*src++;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FATFromName(U8 *dst,U8 *src)
|
||||
{
|
||||
I64 i,j,k=0;
|
||||
for (j=7;j>=0 && src[j]==CH_SPACE;j--);
|
||||
for(i=0;i<=j;i++)
|
||||
dst[k++]=src[i];
|
||||
for (j=10;j>=8 && src[j]==CH_SPACE;j--);
|
||||
if (*src!='.' && j!=7)
|
||||
dst[k++]='.';
|
||||
for(i=8;i<=j;i++)
|
||||
dst[k++]=src[i];
|
||||
dst[k++]=0;
|
||||
return FileNameChk(dst);
|
||||
}
|
||||
|
||||
U8 fat_long_name_map[13]={
|
||||
offset(CFAT32DirEntryLong.name1),
|
||||
offset(CFAT32DirEntryLong.name1)+2,
|
||||
offset(CFAT32DirEntryLong.name1)+4,
|
||||
offset(CFAT32DirEntryLong.name1)+6,
|
||||
offset(CFAT32DirEntryLong.name1)+8,
|
||||
offset(CFAT32DirEntryLong.name2),
|
||||
offset(CFAT32DirEntryLong.name2)+2,
|
||||
offset(CFAT32DirEntryLong.name2)+4,
|
||||
offset(CFAT32DirEntryLong.name2)+6,
|
||||
offset(CFAT32DirEntryLong.name2)+8,
|
||||
offset(CFAT32DirEntryLong.name2)+10,
|
||||
offset(CFAT32DirEntryLong.name3),
|
||||
offset(CFAT32DirEntryLong.name3)+2
|
||||
};
|
||||
|
||||
Bool DirLongNameFill(CDirEntry *tmpde,CFAT32DirEntryLong *de,I64 *xsum)
|
||||
{
|
||||
I64 i;
|
||||
U8 *ptr=de;
|
||||
if (de->ord&0x40) {
|
||||
MemSet(tmpde,0,sizeof(CDirEntry));
|
||||
*xsum=de->xsum;
|
||||
} else if (de->type || de->zero || de->xsum!=*xsum) {
|
||||
MemSet(tmpde,0,sizeof(CDirEntry));
|
||||
*xsum=0;
|
||||
return FALSE;
|
||||
}
|
||||
switch (de->ord&0x3F) {
|
||||
case 1:
|
||||
for (i=0;i<13;i++)
|
||||
if (!(tmpde->name[i]=ptr[fat_long_name_map[i]]))
|
||||
return TRUE;
|
||||
break;
|
||||
case 2:
|
||||
for (i=0;i<12;i++)
|
||||
if (!(tmpde->name[i+13]=ptr[fat_long_name_map[i]]))
|
||||
return TRUE;
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool FAT32CDirFill(CDirEntry *tmpde,
|
||||
CFAT32DirEntry *de,CDate _local_time_offset)
|
||||
{
|
||||
Bool res;
|
||||
if (*tmpde->name)
|
||||
res=TRUE;
|
||||
else
|
||||
res=FATFromName(tmpde->name,de->name);
|
||||
tmpde->cluster=de->cluster_lo+de->cluster_hi<<16;
|
||||
tmpde->size=de->size;
|
||||
tmpde->attr=de->attr;
|
||||
tmpde->datetime=Dos2CDate(de->WrtTime,de->WrtDate)-_local_time_offset;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FAT32DirFill(CFAT32DirEntry *de,
|
||||
CDirEntry *tmpde,I64 *_de_cnt,CDate _local_time_offset)
|
||||
{//Fill up to 3 entries and store cnt of entries.
|
||||
I64 de_cnt=0,i,l,xsum,ord;
|
||||
U8 *ptr,dname[16];
|
||||
CFAT32DirEntryLong *ld=de;
|
||||
Bool res;
|
||||
|
||||
MemSet(de,0,sizeof(CFAT32DirEntry));
|
||||
res=FATNameTo(de->name,tmpde->name);
|
||||
FATFromName(dname,de->name);
|
||||
if (StrCmp(dname,tmpde->name)) {
|
||||
ord=0x41;
|
||||
xsum=FATNameXSum(de->name);
|
||||
if ((l=StrLen(tmpde->name))>13) {
|
||||
ptr=&ld[de_cnt];
|
||||
MemSet(ptr,0,sizeof(CFAT32DirEntryLong));
|
||||
ld[de_cnt].attr=RS_ATTR_LONG_NAME;
|
||||
ld[de_cnt].xsum=xsum;
|
||||
ld[de_cnt].ord=0x42;
|
||||
for (i=13;i<l;i++)
|
||||
ptr[fat_long_name_map[i-13]]=tmpde->name[i];
|
||||
i++;
|
||||
for (;i<26;i++)
|
||||
ptr[fat_long_name_map[i-13]](U16)=0xFFFF;
|
||||
ord=1;
|
||||
l=13;
|
||||
de_cnt++;
|
||||
}
|
||||
ptr=&de[de_cnt];
|
||||
MemSet(ptr,0,sizeof(CFAT32DirEntryLong));
|
||||
ld[de_cnt].attr=RS_ATTR_LONG_NAME;
|
||||
ld[de_cnt].xsum=xsum;
|
||||
ld[de_cnt].ord=ord;
|
||||
for (i=0;i<l;i++)
|
||||
ptr[fat_long_name_map[i]]=tmpde->name[i];
|
||||
i++;
|
||||
for (;i<13;i++)
|
||||
ptr[fat_long_name_map[i]](U16)=0xFFFF;
|
||||
de_cnt++;
|
||||
MemSet(&de[de_cnt],0,sizeof(CFAT32DirEntry));
|
||||
res=FATNameTo(de[de_cnt].name,tmpde->name);
|
||||
}
|
||||
de[de_cnt].cluster_lo=tmpde->cluster.u16[0];
|
||||
de[de_cnt].cluster_hi=tmpde->cluster.u16[1];
|
||||
if (!(tmpde->attr&RS_ATTR_DIR))
|
||||
de[de_cnt].size=tmpde->size;
|
||||
de[de_cnt].attr=tmpde->attr;
|
||||
if (!tmpde->datetime)
|
||||
tmpde->datetime=Now;
|
||||
CDate2Dos(&de[de_cnt].WrtTime,&de[de_cnt].WrtDate,
|
||||
tmpde->datetime+_local_time_offset);
|
||||
if (_de_cnt)
|
||||
*_de_cnt=de_cnt+1;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FAT32FileFind(CDrv *dv,I64 cur_dir_cluster,
|
||||
U8 *name,CDirEntry *_res,I64 fuf_flags=0)
|
||||
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$
|
||||
Bool res=FALSE,unlock;
|
||||
CFAT32DirEntry *buf;
|
||||
I64 xsum=0,attr,cur_dir_entry,entries_per_cluster;
|
||||
U8 dname[CDIR_FILENAME_LEN],ch;
|
||||
CDirEntry long_name;
|
||||
if (fuf_flags&~FUG_FILE_FIND)
|
||||
throw('FUF');
|
||||
MemSet(_res,0,sizeof(CDirEntry));
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
DrvChk(dv);
|
||||
if (dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else if (!CFileNameTo(dname,name))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
buf=MAlloc(BLK_SIZE*dv->spc);
|
||||
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
while (ch=*buf[cur_dir_entry].name) {
|
||||
attr=buf[cur_dir_entry].attr;
|
||||
if (ch!=0xE5) {
|
||||
if (attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
|
||||
else {
|
||||
if (!(attr&RS_ATTR_VOL_ID)) {
|
||||
if (xsum==FATNameXSum(buf[cur_dir_entry].name))
|
||||
MemCpy(_res,&long_name,sizeof(CDirEntry));
|
||||
else
|
||||
MemSet(_res,0,sizeof(CDirEntry));
|
||||
if (!(fuf_flags&FUF_JUST_DIRS && !(attr & RS_ATTR_DIR)) &&
|
||||
!(fuf_flags&FUF_JUST_FILES && attr & RS_ATTR_DIR) &&
|
||||
FAT32CDirFill(_res,&buf[cur_dir_entry],
|
||||
dv->fat32_local_time_offset) &&
|
||||
!StrCmp(dname,_res->name)) {
|
||||
res=TRUE;
|
||||
goto fff_done;
|
||||
}
|
||||
}
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
}
|
||||
} else
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (++cur_dir_entry==entries_per_cluster) {
|
||||
cur_dir_cluster=ClusterNumNext(dv,cur_dir_cluster);
|
||||
if (!(0<cur_dir_cluster<0x0FFFFFF8))
|
||||
break;
|
||||
else {
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
MemSet(_res,0,sizeof(CDirEntry));
|
||||
fff_done:
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *FAT32FileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)
|
||||
{
|
||||
U8 *buf=NULL;
|
||||
CDirEntry de;
|
||||
I64 c,blk_cnt,cur_dir_cluster;
|
||||
DrvChk(dv);
|
||||
*_size=0;
|
||||
*_attr=0;
|
||||
if (dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else
|
||||
try {
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
if (FAT32FileFind(dv,cur_dir_cluster,filename,&de,FUF_JUST_FILES)) {
|
||||
blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;
|
||||
buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);
|
||||
c=de.cluster;
|
||||
if (!(0<c<0x0FFFFFF8))
|
||||
c=0x0FFFFFFF;
|
||||
else
|
||||
c=RClustersBlks(dv,buf,c,blk_cnt);
|
||||
buf[de.size]=0; //Terminate
|
||||
*_size=de.size;
|
||||
*_attr=FileAttr(de.name,de.attr);
|
||||
}
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
Bool FAT32Cd(U8 *name,I64 cur_dir_cluster)
|
||||
{
|
||||
CDirEntry de;
|
||||
if (Fs->cur_dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else if (FAT32FileFind(Fs->cur_dv,cur_dir_cluster,name,&de,FUF_JUST_DIRS))
|
||||
return TRUE;
|
||||
else {
|
||||
"%s ",name;
|
||||
PrintErr("File not found.\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 FAT32FreeClusters(CDrv *dv,I64 c)
|
||||
{
|
||||
I64 next,saved_c=c;
|
||||
Bool unlock,unlock_break;
|
||||
DrvChk(dv);
|
||||
if (!(0<c<0x0FFFFFF8)) return;
|
||||
if (dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
DrvFATBlkClean(dv);
|
||||
do {
|
||||
DrvFATBlkSet(dv,c,0);
|
||||
next=dv->cur_fat_blk[c&(BLK_SIZE/4-1)];
|
||||
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=0;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
c=next;
|
||||
} while (0<c<0x0FFFFFF8);
|
||||
DrvFATBlkClean(dv,0);
|
||||
|
||||
c=saved_c;
|
||||
do {
|
||||
DrvFATBlkSet(dv,c,1);
|
||||
next=dv->cur_fat_blk[c&(BLK_SIZE/4-1)];
|
||||
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=0;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
c=next;
|
||||
} while (0<c<0x0FFFFFF8);
|
||||
DrvFATBlkClean(dv,1);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
}
|
||||
|
||||
I64 FAT32AllocClusters(CDrv *dv,I64 c,I64 cnt)
|
||||
{
|
||||
Bool wrap_around=FALSE,unlock,unlock_break;
|
||||
I64 first=INVALID_CLUSTER,j,l;
|
||||
|
||||
if (cnt<=0) return 0x0FFFFFFF;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
l=(dv->size+dv->drv_offset-dv->data_area)/dv->spc-1;
|
||||
j=dv->fis->most_recently_alloced;
|
||||
while (cnt-->0) {
|
||||
while (TRUE) {
|
||||
j++;
|
||||
if (j<1) j=1;
|
||||
if (j>=l) {
|
||||
if (wrap_around)
|
||||
throw('Drv');
|
||||
j=1;
|
||||
wrap_around=TRUE;
|
||||
}
|
||||
DrvFATBlkSet(dv,j);
|
||||
if (!dv->cur_fat_blk[j&(BLK_SIZE/4-1)])
|
||||
break;
|
||||
}
|
||||
if (!(0<first<0x0FFFFFF8))
|
||||
first=j;
|
||||
if (0<c<l) {
|
||||
DrvFATBlkSet(dv,c);
|
||||
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=j;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
c=j;
|
||||
}
|
||||
|
||||
if (0<c<l) {
|
||||
DrvFATBlkSet(dv,c);
|
||||
dv->cur_fat_blk[c&(BLK_SIZE/4-1)]=0x0FFFFFFF;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
DrvFATBlkClean(dv);
|
||||
|
||||
dv->fis->most_recently_alloced=j;
|
||||
dv->fis->free_clusters=-1;
|
||||
WBlks(dv,dv->fis,dv->file_system_info_sect,1);
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
return first;
|
||||
}
|
||||
|
||||
I64 FAT32AllocContiguousClusters(CDrv *dv,I64 cnt)
|
||||
{
|
||||
I64 i,first=1;
|
||||
Bool cont,unlock,unlock_break;
|
||||
|
||||
if (cnt<=0) return 0x0FFFFFFF;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
while (TRUE) {
|
||||
first++;
|
||||
i=0;
|
||||
cont=TRUE;
|
||||
while (cont && i<cnt) {
|
||||
if ((first+i+1)*dv->spc+dv->data_area>dv->size+dv->drv_offset)
|
||||
throw('Drv');
|
||||
DrvFATBlkSet(dv,first+i);
|
||||
if (dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)])
|
||||
cont=FALSE;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
if (!cont)
|
||||
first=first+i;
|
||||
else {
|
||||
DrvFATBlkClean(dv);
|
||||
|
||||
for (i=0;i<cnt;i++) {
|
||||
DrvFATBlkSet(dv,first+i,0);
|
||||
if (i+1==cnt)
|
||||
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=0x0FFFFFFF;
|
||||
else
|
||||
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=first+i+1;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
DrvFATBlkClean(dv,0);
|
||||
|
||||
for (i=0;i<cnt;i++) {
|
||||
DrvFATBlkSet(dv,first+i,1);
|
||||
if (i+1==cnt)
|
||||
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=0x0FFFFFFF;
|
||||
else
|
||||
dv->cur_fat_blk[(first+i)&(BLK_SIZE/4-1)]=first+i+1;
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
DrvFATBlkClean(dv,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
return first;
|
||||
}
|
||||
|
||||
Bool FAT32DirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain)
|
||||
{
|
||||
//See $LK,"::/Doc/CutCorners.DD"$.
|
||||
CFAT32DirEntry *buf,*last_buf,*tmp_buf,de[3];
|
||||
I64 i,attr,avail_cnt,de_cnt,c,
|
||||
cur_dir_entry,entries_per_cluster,
|
||||
cur_dir_cluster,xsum=0,last_dir_cluster=INVALID_CLUSTER;
|
||||
U8 ch;
|
||||
Bool written=FALSE,unlock,unlock_break;
|
||||
CDirEntry long_name;
|
||||
FAT32DirFill(&de,tmpde,&de_cnt,dv->fat32_local_time_offset);
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
buf =MAlloc(BLK_SIZE*dv->spc);
|
||||
last_buf=CAlloc(BLK_SIZE*dv->spc);
|
||||
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
while (ch=*buf[cur_dir_entry].name) {
|
||||
attr=buf[cur_dir_entry].attr;
|
||||
if (ch!=0xE5 && attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
|
||||
else {
|
||||
avail_cnt=FAT32_ENTRIES_PER_BLK-cur_dir_entry
|
||||
&(FAT32_ENTRIES_PER_BLK-1);
|
||||
for (i=0;i<avail_cnt;i++)
|
||||
if (*buf[cur_dir_entry+i].name!=0xE5) {
|
||||
if (*buf[cur_dir_entry+i].name)
|
||||
avail_cnt=i;
|
||||
break;
|
||||
}
|
||||
if (ch==0xE5 && !written && avail_cnt>=de_cnt) {
|
||||
MemCpy(&buf[cur_dir_entry],&de,de_cnt*sizeof(CFAT32DirEntry));
|
||||
WBlks(dv,&buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
cur_dir_entry+=de_cnt-1; //gets inc'ed
|
||||
written=TRUE;
|
||||
} else if (ch!=0xE5 && !(attr&RS_ATTR_VOL_ID)) {
|
||||
if (xsum!=FATNameXSum(buf[cur_dir_entry].name))
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (!*long_name.name)
|
||||
FATFromName(long_name.name,buf[cur_dir_entry].name);
|
||||
//Del old entry with same name
|
||||
if (!StrCmp(long_name.name,tmpde->name)) {
|
||||
if (free_old_chain)
|
||||
FAT32FreeClusters(dv,buf[cur_dir_entry].cluster_lo+
|
||||
buf[cur_dir_entry].cluster_hi<<16);
|
||||
if (!written) {
|
||||
MemCpy(&buf[cur_dir_entry],&de[de_cnt-1],sizeof(CFAT32DirEntry));
|
||||
WBlks(dv,&buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
written=TRUE;
|
||||
} else {
|
||||
*buf[cur_dir_entry].name=0xE5;
|
||||
i=1;
|
||||
while (i<=cur_dir_entry &&
|
||||
buf[cur_dir_entry-i].attr&RS_ATTR_LONG_NAME_MASK
|
||||
==RS_ATTR_LONG_NAME)
|
||||
*buf[cur_dir_entry-i++].name=0xE5;
|
||||
i--;
|
||||
WBlks(dv,&buf[(cur_dir_entry-i)&-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+(cur_dir_entry-i)>>FAT32_ENTRIES_BITS,
|
||||
(i+FAT32_ENTRIES_PER_BLK)>>FAT32_ENTRIES_BITS);
|
||||
if (i==cur_dir_entry && 0<last_dir_cluster<0x0FFFFFF8) {
|
||||
i=1;
|
||||
while (i<=entries_per_cluster &&
|
||||
last_buf[entries_per_cluster-i].attr
|
||||
&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
*last_buf[entries_per_cluster-i++].name=0xE5;
|
||||
if (--i>0)
|
||||
WBlks(dv,&buf[(entries_per_cluster-i)&-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+last_dir_cluster*dv->spc
|
||||
+(entries_per_cluster-i)>>FAT32_ENTRIES_BITS,
|
||||
(i+FAT32_ENTRIES_PER_BLK-1)>>FAT32_ENTRIES_BITS);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
}
|
||||
if (++cur_dir_entry==entries_per_cluster) {
|
||||
last_dir_cluster=cur_dir_cluster;
|
||||
tmp_buf=buf; buf=last_buf; last_buf=tmp_buf;
|
||||
c=ClusterNumNext(dv,cur_dir_cluster);
|
||||
if (!(0<c<0x0FFFFFF8)) {
|
||||
c=ClustersAlloc(dv,cur_dir_cluster,1,FALSE);
|
||||
MemSet(buf,0,BLK_SIZE*dv->spc);
|
||||
WClusters(dv,buf,c,1);
|
||||
} else
|
||||
RClusters(dv,buf,c,1);
|
||||
cur_dir_cluster=c;
|
||||
cur_dir_entry=0;
|
||||
}
|
||||
}
|
||||
if (!written) {
|
||||
avail_cnt=FAT32_ENTRIES_PER_BLK-cur_dir_entry & (FAT32_ENTRIES_PER_BLK-1);
|
||||
if (avail_cnt<de_cnt) {
|
||||
for (i=0;i<avail_cnt;i++)
|
||||
*buf[cur_dir_entry+i].name=0xE5;
|
||||
WBlks(dv,&buf[cur_dir_entry &-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
cur_dir_entry+=avail_cnt;
|
||||
if (cur_dir_entry==entries_per_cluster) {
|
||||
last_dir_cluster=cur_dir_cluster;
|
||||
tmp_buf=buf; buf=last_buf; last_buf=tmp_buf;
|
||||
cur_dir_cluster=ClustersAlloc(dv,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
MemSet(buf,0,BLK_SIZE*dv->spc);
|
||||
WClusters(dv,buf,cur_dir_cluster,1);
|
||||
}
|
||||
}
|
||||
MemCpy(&buf[cur_dir_entry],&de,de_cnt*sizeof(CFAT32DirEntry));
|
||||
WBlks(dv,&buf[cur_dir_entry &-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc+
|
||||
cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
cur_dir_entry+=de_cnt;
|
||||
if (cur_dir_entry==entries_per_cluster) {
|
||||
cur_dir_cluster=ClustersAlloc(dv,cur_dir_cluster,1);
|
||||
MemSet(buf,0,BLK_SIZE*dv->spc);
|
||||
WClusters(dv,buf,cur_dir_cluster,1);
|
||||
} else {
|
||||
MemSet(&buf[cur_dir_entry],0,sizeof(CFAT32DirEntry));
|
||||
WBlks(dv,&buf[cur_dir_entry &-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+cur_dir_entry>>FAT32_ENTRIES_BITS,1);
|
||||
}
|
||||
}
|
||||
Free(last_buf);
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 FAT32FilesDel(CDrv *dv,U8 *cur_dir,U8 *files_find_mask,I64 fuf_flags,
|
||||
Bool del_dir,Bool print_msg)
|
||||
{
|
||||
CFAT32DirEntry *buf,*last_buf,*tmp_buf;
|
||||
I64 i,res=0,attr,xsum=0,last_dir_cluster=INVALID_CLUSTER,
|
||||
cur_dir_entry,entries_per_cluster,cur_dir_cluster;
|
||||
U8 ch;
|
||||
Bool unlock_break;
|
||||
CDirEntry long_name;
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
buf =MAlloc(BLK_SIZE*dv->spc);
|
||||
last_buf=CAlloc(BLK_SIZE*dv->spc);
|
||||
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
while (ch=*buf[cur_dir_entry].name) {
|
||||
attr=buf[cur_dir_entry].attr;
|
||||
if (ch!=0xE5 && ch!='.') {
|
||||
if (attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
|
||||
else {
|
||||
if (!(attr & RS_ATTR_VOL_ID) &&
|
||||
(del_dir || !(attr & RS_ATTR_DIR))) {
|
||||
if (xsum!=FATNameXSum(buf[cur_dir_entry].name))
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (!*long_name.name)
|
||||
FATFromName(long_name.name,buf[cur_dir_entry].name);
|
||||
if (FilesFindMatch(long_name.name,files_find_mask,fuf_flags)) {
|
||||
if (!(attr & RS_ATTR_DIR)) res++;
|
||||
if (print_msg)
|
||||
"Del %s\n",long_name.name;
|
||||
*buf[cur_dir_entry].name=0xE5;
|
||||
i=1;
|
||||
while (i<=cur_dir_entry &&
|
||||
buf[cur_dir_entry-i].attr&RS_ATTR_LONG_NAME_MASK
|
||||
==RS_ATTR_LONG_NAME)
|
||||
*buf[cur_dir_entry-i++].name=0xE5;
|
||||
i--;
|
||||
WBlks(dv,&buf[(cur_dir_entry-i)&-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+cur_dir_cluster*dv->spc
|
||||
+(cur_dir_entry-i)>>FAT32_ENTRIES_BITS,
|
||||
(i+FAT32_ENTRIES_PER_BLK)>>FAT32_ENTRIES_BITS);
|
||||
if (i==cur_dir_entry && last_dir_cluster!=INVALID_CLUSTER) {
|
||||
i=1;
|
||||
while (i<=entries_per_cluster &&
|
||||
last_buf[entries_per_cluster-i].attr
|
||||
&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
*last_buf[entries_per_cluster-i++].name=0xE5;
|
||||
if (--i>0)
|
||||
WBlks(dv,&buf[(entries_per_cluster-i)&-FAT32_ENTRIES_PER_BLK],
|
||||
dv->data_area+last_dir_cluster*dv->spc
|
||||
+(entries_per_cluster-i)>>FAT32_ENTRIES_BITS,
|
||||
(i+FAT32_ENTRIES_PER_BLK-1)>>FAT32_ENTRIES_BITS);
|
||||
}
|
||||
FAT32FreeClusters(dv,buf[cur_dir_entry].cluster_lo+
|
||||
buf[cur_dir_entry].cluster_hi<<16);
|
||||
}
|
||||
}
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
}
|
||||
} else
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (++cur_dir_entry==entries_per_cluster) {
|
||||
last_dir_cluster=cur_dir_cluster;
|
||||
cur_dir_cluster=ClusterNumNext(dv,cur_dir_cluster,1);
|
||||
tmp_buf=buf; buf=last_buf; last_buf=tmp_buf;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
cur_dir_entry=0;
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
Free(last_buf);
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 FAT32FileWrite(CDrv *dv,U8 *cur_dir,U8 *name,U8 *buf,I64 size,
|
||||
CDate cdt,I64 attr)
|
||||
{
|
||||
CDirEntry de;
|
||||
I64 c=0,blk_cnt;
|
||||
Bool contiguous;
|
||||
MemSet(&de,0,sizeof(CDirEntry));
|
||||
if (size<0) size=0;
|
||||
if (dv->fs_type!=FSt_FAT32)
|
||||
PrintErr("Not FAT32 Drv\n");
|
||||
else if (!CFileNameTo(de.name,name))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else {
|
||||
FAT32FilesDel(dv,cur_dir,de.name,0,FALSE,FALSE);
|
||||
if (attr & RS_ATTR_CONTIGUOUS)
|
||||
contiguous=TRUE;
|
||||
else
|
||||
contiguous=FALSE;
|
||||
de.size=size;
|
||||
if (blk_cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS)
|
||||
c=ClustersAlloc(dv,0,(blk_cnt+dv->spc-1)/dv->spc,contiguous);
|
||||
else
|
||||
c=0x0FFFFFFF;
|
||||
de.cluster=c;
|
||||
de.attr=attr;
|
||||
de.datetime=cdt;
|
||||
if (blk_cnt)
|
||||
WClustersBlks(dv,buf,c,blk_cnt);
|
||||
FAT32DirNew(dv,cur_dir,&de,TRUE);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
CDirEntry *FAT32FilesFind(U8 *files_find_mask,
|
||||
I64 fuf_flags,CDirEntry *parent=NULL,I64 *_dir_size=NULL)
|
||||
{
|
||||
CDrv *dv=Fs->cur_dv;
|
||||
CFAT32DirEntry *buf;
|
||||
I64 attr,xsum=0,dir_size=0,sub_dir_size,
|
||||
cur_dir_cluster,cur_dir_entry,entries_per_cluster;
|
||||
U8 ch;
|
||||
CDirEntry *res=NULL,*tmpde,long_name;
|
||||
if (fuf_flags&~FUG_FILES_FIND)
|
||||
throw('FUF');
|
||||
try {
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,Fs->cur_dir);
|
||||
buf=MAlloc(BLK_SIZE*dv->spc);
|
||||
entries_per_cluster=dv->spc<<FAT32_ENTRIES_BITS;
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
dir_size+=dv->spc*BLK_SIZE;
|
||||
cur_dir_entry=0;
|
||||
while (ch=*buf[cur_dir_entry].name) {
|
||||
attr=buf[cur_dir_entry].attr;
|
||||
if (ch!=0xE5) {
|
||||
if (attr&RS_ATTR_LONG_NAME_MASK==RS_ATTR_LONG_NAME)
|
||||
DirLongNameFill(&long_name,&buf[cur_dir_entry],&xsum);
|
||||
else {
|
||||
if (!(attr&RS_ATTR_VOL_ID)) {
|
||||
tmpde=MAlloc(sizeof(CDirEntry));
|
||||
if (xsum==FATNameXSum(buf[cur_dir_entry].name))
|
||||
MemCpy(tmpde,&long_name,sizeof(CDirEntry));
|
||||
else
|
||||
MemSet(tmpde,0,sizeof(CDirEntry));
|
||||
if (FAT32CDirFill(tmpde,&buf[cur_dir_entry],
|
||||
dv->fat32_local_time_offset)) {
|
||||
tmpde->parent=parent;
|
||||
if (Bt(&fuf_flags,FUf_RECURSE) && attr&RS_ATTR_DIR &&
|
||||
*tmpde->name!='.') {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
tmpde->full_name=DirNameAbs(tmpde->name);
|
||||
DrvUnlock(dv);
|
||||
if (Cd(tmpde->name)) {
|
||||
tmpde->sub=FAT32FilesFind(files_find_mask,fuf_flags,
|
||||
tmpde,&sub_dir_size);
|
||||
tmpde->size=sub_dir_size;
|
||||
Cd("..");
|
||||
}
|
||||
DrvLock(dv);
|
||||
} else {
|
||||
tmpde->full_name=FileNameAbs(tmpde->name);
|
||||
if ((attr&RS_ATTR_DIR || !Bt(&fuf_flags,FUf_JUST_DIRS)) &&
|
||||
!(Bt(&fuf_flags,FUf_RECURSE) &&
|
||||
*tmpde->name=='.' && attr&RS_ATTR_DIR) &&
|
||||
FilesFindMatch(tmpde->full_name,files_find_mask,
|
||||
fuf_flags)) {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
}
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
}
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
}
|
||||
} else
|
||||
MemSet(&long_name,0,sizeof(CDirEntry));
|
||||
if (++cur_dir_entry==entries_per_cluster) {
|
||||
cur_dir_cluster=ClusterNumNext(dv,cur_dir_cluster);
|
||||
if (cur_dir_cluster==INVALID_CLUSTER)
|
||||
break;
|
||||
else {
|
||||
RClusters(dv,buf,cur_dir_cluster,1);
|
||||
dir_size+=dv->spc*BLK_SIZE;
|
||||
cur_dir_entry=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
if (_dir_size)
|
||||
*_dir_size=dir_size;
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool FAT32MkDir(CDrv *dv,U8 *cur_dir,U8 *name,I64 entry_cnt)
|
||||
{
|
||||
I64 c,cur_dir_cluster=Name2DirCluster(dv,cur_dir),
|
||||
//Rough estimate of size
|
||||
size=CeilU64((entry_cnt+2)<<FAT32_ENTRIES_BITS,dv->spc<<BLK_SIZE_BITS);
|
||||
U8 *buf=CAlloc(size);
|
||||
CDirEntry d_native;
|
||||
CFAT32DirEntry *dFAT=buf;
|
||||
Bool unlock_break;
|
||||
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
c=FileWrite(name,buf,size,0,RS_ATTR_DIR);
|
||||
MemSet(&d_native,0,sizeof(CDirEntry));
|
||||
d_native.attr=RS_ATTR_DIR;
|
||||
*d_native.name='.';
|
||||
d_native.name[1]=0;
|
||||
d_native.cluster=c;
|
||||
d_native.size=0;
|
||||
d_native.datetime=Now;
|
||||
FAT32DirFill(dFAT,&d_native,NULL,dv->fat32_local_time_offset);
|
||||
dFAT++;
|
||||
|
||||
MemSet(&d_native,0,sizeof(CDirEntry));
|
||||
d_native.attr=RS_ATTR_DIR;
|
||||
*d_native.name='.';
|
||||
d_native.name[1]='.';
|
||||
d_native.name[2]=0;
|
||||
d_native.cluster=cur_dir_cluster;
|
||||
d_native.size=0;
|
||||
d_native.datetime=Now;
|
||||
FAT32DirFill(dFAT,&d_native,NULL,dv->fat32_local_time_offset);
|
||||
WClusters(dv,buf,c,1);
|
||||
Free(buf);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
U0 Date2ISO1(CISO1Date *dst,CDate cdt)
|
||||
{
|
||||
CDateStruct ds;
|
||||
Date2Struct(&ds,cdt);
|
||||
dst->year=ds.year-ISO1_BASE_YEAR;
|
||||
dst->mon=ds.mon;
|
||||
dst->day=ds.day_of_mon;
|
||||
dst->hour=ds.hour;
|
||||
dst->min=ds.min;
|
||||
dst->sec=ds.sec;
|
||||
dst->sec100=ds.sec100;
|
||||
}
|
||||
|
||||
CDate ISO1DateStruct2CDate(CISO1Date *dt)
|
||||
{
|
||||
CDateStruct ds;
|
||||
MemSet(&ds,0,sizeof(CDateStruct));
|
||||
ds.day_of_mon=dt->day;
|
||||
ds.mon=dt->mon;
|
||||
ds.year=dt->year+ISO1_BASE_YEAR;
|
||||
ds.sec100=dt->sec100;
|
||||
ds.sec=dt->sec;
|
||||
ds.min=dt->min;
|
||||
ds.hour=dt->hour;
|
||||
return Struct2Date(&ds);
|
||||
}
|
||||
|
||||
Bool ISO1FromName(U8 *dst,U8 *src)
|
||||
{
|
||||
I64 i,j,n;
|
||||
MemSet(dst,0,CDIR_FILENAME_LEN);
|
||||
n=*src++;
|
||||
if (n==1 && !*src) {
|
||||
*dst='.';
|
||||
} else if (n==1 && *src==1) {
|
||||
*dst='.';
|
||||
dst[1]='.';
|
||||
} else {
|
||||
n>>=1;
|
||||
j=0;
|
||||
for (i=0;i<n;i++) {
|
||||
src++;
|
||||
if (*src==';')
|
||||
break;
|
||||
if (Bt(char_bmp_filename,*src)) {
|
||||
if (j>=CDIR_FILENAME_LEN-1)
|
||||
return FALSE;
|
||||
dst[j++]=*src++;
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return FileNameChk(dst);
|
||||
}
|
||||
|
||||
Bool ISO1CDirFill(CDirEntry *tmpde,CISO1DirEntry *de)
|
||||
{
|
||||
Bool res;
|
||||
MemSet(tmpde,0,sizeof(CDirEntry));
|
||||
res=ISO1FromName(tmpde->name,&de->name_len);
|
||||
tmpde->cluster=de->loc.little;
|
||||
tmpde->size=de->size.little;
|
||||
tmpde->attr=FileAttr(tmpde->name);
|
||||
if (de->flags & ISO1_ATTR_DIR)
|
||||
tmpde->attr|=RS_ATTR_DIR;
|
||||
tmpde->datetime=ISO1DateStruct2CDate(&de->date);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool ISO1FileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
|
||||
CDirEntry *_res,I64 fuf_flags=0)
|
||||
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$
|
||||
CISO1DirEntry *isoptr,*buf;
|
||||
U8 dname[CDIR_FILENAME_LEN];
|
||||
Bool res=FALSE,unlock;
|
||||
I64 i;
|
||||
if (fuf_flags&~FUG_FILE_FIND)
|
||||
throw('FUF');
|
||||
DrvChk(dv);
|
||||
if (dv->fs_type!=FSt_ISO9660)
|
||||
PrintErr("Not ISO9660 Drv\n");
|
||||
else
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
isoptr=MAlloc(dv->spc<<BLK_SIZE_BITS);
|
||||
RClusters(dv,isoptr,cur_dir_cluster,1);
|
||||
if (isoptr->name_len==1 && !isoptr->name) {//curdir
|
||||
i=(isoptr->size.little+dv->spc<<BLK_SIZE_BITS-1)/dv->spc<<BLK_SIZE_BITS;
|
||||
buf=MAlloc(dv->spc<<BLK_SIZE_BITS*i);
|
||||
RClusters(dv,buf,cur_dir_cluster,i);
|
||||
Free(isoptr);
|
||||
} else {
|
||||
buf=isoptr;
|
||||
i=1;
|
||||
}
|
||||
i*=dv->spc<<BLK_SIZE_BITS;
|
||||
isoptr=buf;
|
||||
while (i>0) {
|
||||
if (!isoptr->len) {
|
||||
isoptr(U8 *)++;
|
||||
i--;
|
||||
} else {
|
||||
ISO1FromName(dname,&isoptr->name_len);
|
||||
if (*dname) {
|
||||
if (!StrCmp(name,dname)) {
|
||||
res=ISO1CDirFill(_res,isoptr);
|
||||
if (res &&
|
||||
!(fuf_flags&FUF_JUST_DIRS &&
|
||||
!(_res->attr & RS_ATTR_DIR)) &&
|
||||
!(fuf_flags&FUF_JUST_FILES && _res->attr & RS_ATTR_DIR) )
|
||||
goto iff_done;
|
||||
else
|
||||
res=FALSE;
|
||||
}
|
||||
}
|
||||
i-=isoptr->len;
|
||||
isoptr(U8 *)+=isoptr->len;
|
||||
}
|
||||
}
|
||||
iff_done:
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *ISO1FileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)
|
||||
{
|
||||
U8 *buf=NULL;
|
||||
CDirEntry de;
|
||||
I64 c,blk_cnt,cur_dir_cluster;
|
||||
DrvChk(dv);
|
||||
*_size=0;
|
||||
*_attr=0;
|
||||
if (dv->fs_type!=FSt_ISO9660)
|
||||
PrintErr("Not ISO9660 Drv\n");
|
||||
else
|
||||
try {
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
if (ISO1FileFind(dv,cur_dir_cluster,filename,&de,FUF_JUST_FILES)) {
|
||||
blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;
|
||||
buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);
|
||||
c=de.cluster;
|
||||
c=RClustersBlks(dv,buf,c,blk_cnt);
|
||||
buf[de.size]=0; //Terminate
|
||||
*_size=de.size;
|
||||
*_attr=FileAttr(de.name,de.attr);
|
||||
}
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
Bool ISO1Cd(U8 *name,I64 cur_dir_cluster)
|
||||
{
|
||||
CDirEntry de;
|
||||
if (Fs->cur_dv->fs_type!=FSt_ISO9660)
|
||||
PrintErr("Not ISO9660 Drv\n");
|
||||
else if (ISO1FileFind(Fs->cur_dv,cur_dir_cluster,name,&de,FUF_JUST_DIRS))
|
||||
return TRUE;
|
||||
else {
|
||||
"%s ",name;
|
||||
PrintErr("File not found.\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CDirEntry *ISO1FilesFind(U8 *files_find_mask,
|
||||
I64 fuf_flags,CDirEntry *parent=NULL)
|
||||
{
|
||||
CDrv *dv=Fs->cur_dv;
|
||||
CISO1DirEntry *buf,*buf2,*isoptr;
|
||||
I64 i,cur_dir_cluster=Name2DirCluster(dv,Fs->cur_dir);
|
||||
CDirEntry *res=NULL,*tmpde;
|
||||
if (fuf_flags&~FUG_FILES_FIND)
|
||||
throw('FUF');
|
||||
isoptr=MAlloc(dv->spc<<BLK_SIZE_BITS);
|
||||
RClusters(dv,isoptr,cur_dir_cluster,1);
|
||||
if (isoptr->name_len==1 && !isoptr->name) {//curdir
|
||||
i=(isoptr->size.little+dv->spc<<BLK_SIZE_BITS-1)/dv->spc<<BLK_SIZE_BITS;
|
||||
buf=MAlloc(dv->spc<<BLK_SIZE_BITS*i);
|
||||
RClusters(dv,buf,cur_dir_cluster,i);
|
||||
Free(isoptr);
|
||||
} else {
|
||||
buf=isoptr;
|
||||
i=1;
|
||||
}
|
||||
buf2=buf;
|
||||
i*=dv->spc<<BLK_SIZE_BITS;
|
||||
while (i>0) {
|
||||
if (!buf->len) {
|
||||
buf(U8 *)++;
|
||||
i--;
|
||||
} else {
|
||||
tmpde=MAlloc(sizeof(CDirEntry));
|
||||
if (ISO1CDirFill(tmpde,buf)) {
|
||||
tmpde->parent=parent;
|
||||
if (Bt(&fuf_flags,FUf_RECURSE) && tmpde->attr&RS_ATTR_DIR &&
|
||||
*tmpde->name!='.') {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
tmpde->full_name=DirNameAbs(tmpde->name);
|
||||
if (Cd(tmpde->name)) {
|
||||
tmpde->sub=ISO1FilesFind(files_find_mask,fuf_flags,tmpde);
|
||||
Cd("..");
|
||||
}
|
||||
} else {
|
||||
tmpde->full_name=FileNameAbs(tmpde->name);
|
||||
if ((tmpde->attr & RS_ATTR_DIR ||
|
||||
!Bt(&fuf_flags,FUf_JUST_DIRS)) &&
|
||||
!(Bt(&fuf_flags,FUf_RECURSE) &&
|
||||
*tmpde->name=='.' && tmpde->attr&RS_ATTR_DIR) &&
|
||||
FilesFindMatch(tmpde->full_name,files_find_mask,fuf_flags)) {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
}
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
i-=buf->len;
|
||||
buf(U8 *)+=buf->len;
|
||||
}
|
||||
}
|
||||
Free(buf2);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,637 @@
|
||||
// See $LK,"RedSea File System",A="FI:::/Doc/RedSea.DD"$
|
||||
|
||||
U0 RedSeaFreeFreeLst(CDrv *dv)
|
||||
{
|
||||
CFreeLst *tmpf,*tmpf1;
|
||||
Bool unlock;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
if (tmpf=dv->next_free) {
|
||||
while (tmpf!=&dv->next_free) {
|
||||
tmpf1=tmpf->next;
|
||||
Free(tmpf);
|
||||
tmpf=tmpf1;
|
||||
}
|
||||
}
|
||||
dv->next_free=NULL;
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
U0 RedSeaFreeLstBuild(CDrv *dv)
|
||||
{
|
||||
Bool unlock;
|
||||
CFreeLst *tmpf;
|
||||
I64 i,first=dv->data_area,max_blk=dv->size+dv->drv_offset;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
if (dv->next_free)
|
||||
RedSeaFreeFreeLst(dv);
|
||||
QueInit(&dv->next_free);
|
||||
while (first<max_blk) {
|
||||
i=0; //count free clusters
|
||||
while (first+i<max_blk) {
|
||||
DrvFATBlkSet(dv,first+i);
|
||||
if (Bt(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1)))
|
||||
break;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
if (i) {
|
||||
tmpf=AMAlloc(sizeof(CFreeLst));
|
||||
tmpf->size=i;
|
||||
tmpf->start=first;
|
||||
QueIns(tmpf,dv->last_free);
|
||||
}
|
||||
first+=i+1;
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
U0 RedSeaInit(CDrv *dv)
|
||||
{
|
||||
CRedSeaBoot br;
|
||||
Bool unlock;
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
RBlks(dv,&br,dv->drv_offset,1);
|
||||
if (br.signature!=MBR_PT_REDSEA || br.signature2!=0xAA55)
|
||||
throw('Drv');
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
RedSeaFreeFreeLst(dv);
|
||||
dv->spc=1;
|
||||
dv->size=br.sects;
|
||||
dv->data_area=dv->drv_offset+br.bitmap_sects;
|
||||
dv->root_cluster=br.root_cluster;
|
||||
dv->fat1=dv->fat2=dv->drv_offset+1;
|
||||
DrvFATBlkAlloc(dv);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
}
|
||||
|
||||
Bool RedSeaValidate(U8 drv_let)
|
||||
{
|
||||
CDrv *dv;
|
||||
CRedSeaBoot br;
|
||||
if ((dv=Let2Drv(drv_let,FALSE)) && dv->fs_type==FSt_REDSEA &&
|
||||
RBlks(dv,&br,dv->drv_offset,1) && br.signature==MBR_PT_REDSEA &&
|
||||
br.signature2==0xAA55 && br.sects==dv->size)
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 RedSeaFmt(U8 drv_let,Bool quick=TRUE)
|
||||
{
|
||||
U8 *root_dir;
|
||||
CDirEntry *d_native;
|
||||
CRedSeaBoot *br=CAlloc(BLK_SIZE);
|
||||
CDrv *dv=Let2Drv(drv_let);
|
||||
I64 i,n,root_dir_blks;
|
||||
try {
|
||||
DrvLock(dv);
|
||||
// DrvTypeSet(drv_let,FSt_REDSEA);
|
||||
DrvTypeSet(drv_let,FSt_FAT32);
|
||||
dv->fs_type=FSt_REDSEA;
|
||||
br->signature=MBR_PT_REDSEA;
|
||||
br->signature2=0xAA55;
|
||||
br->drv_offset=dv->drv_offset; //For CD/DVD image copy.
|
||||
br->sects=dv->size;
|
||||
n=(br->sects+BLK_SIZE<<3-1)/BLK_SIZE<<3;
|
||||
br->bitmap_sects=n;
|
||||
br->unique_id=GetTSC^Now()(U64);
|
||||
br->root_cluster=0;
|
||||
|
||||
if (quick)
|
||||
i=n+1;
|
||||
else
|
||||
i=dv->size;
|
||||
WZeroBlks(dv,dv->drv_offset,i);
|
||||
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
RedSeaInit(dv);
|
||||
ClustersAlloc(dv,0,1,FALSE); //Alloc #1
|
||||
|
||||
root_dir_blks=MaxI64(1,dv->bd->init_root_dir_blks);
|
||||
br->root_cluster=ClustersAlloc(dv,0,root_dir_blks,FALSE);
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
root_dir=CAlloc(BLK_SIZE*root_dir_blks);
|
||||
|
||||
d_native=root_dir-offset(CDirEntry.start);
|
||||
|
||||
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
|
||||
*d_native->name='.';
|
||||
d_native->cluster=br->root_cluster;
|
||||
d_native->size=BLK_SIZE*root_dir_blks;
|
||||
d_native->datetime=Now;
|
||||
|
||||
d_native(U8 *)+=CDIR_SIZE;
|
||||
|
||||
*d_native->name='.';
|
||||
d_native->name[1]='.';
|
||||
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
|
||||
d_native->cluster=br->root_cluster;
|
||||
d_native->datetime=Now;
|
||||
|
||||
WBlks(dv,root_dir,br->root_cluster,root_dir_blks);
|
||||
RedSeaInit(dv);
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
Free(br);
|
||||
Free(root_dir);
|
||||
}
|
||||
|
||||
Bool RedSeaFileFind(CDrv *dv,I64 cur_dir_cluster,U8 *name,
|
||||
CDirEntry *_res,I64 fuf_flags=0)
|
||||
{//$LK,"FUF_JUST_DIRS",A="MN:FUF_JUST_DIRS"$, $LK,"FUF_JUST_FILES",A="MN:FUF_JUST_FILES"$
|
||||
CDirEntry *buf,*buf2,*ptr;
|
||||
U8 dname[CDIR_FILENAME_LEN];
|
||||
I64 ch;
|
||||
Bool res=FALSE,unlock;
|
||||
if (fuf_flags&~FUG_FILE_FIND)
|
||||
throw('FUF');
|
||||
MemSet(_res,0,sizeof(CDirEntry));
|
||||
DrvChk(dv);
|
||||
if (dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else if (!CFileNameTo(dname,name))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else
|
||||
try {
|
||||
unlock=DrvLock(dv);
|
||||
buf2=MAlloc(BLK_SIZE);
|
||||
RBlks(dv,buf2,cur_dir_cluster,1);
|
||||
|
||||
ptr=buf2(U8 *)-offset(CDirEntry.start);
|
||||
buf=MAlloc(ptr->size);
|
||||
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
|
||||
Free(buf2);
|
||||
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start);
|
||||
*ptr->name='.';
|
||||
ptr->name[1]=0;
|
||||
while (TRUE) {
|
||||
if (!(ch=*ptr->name))
|
||||
break;
|
||||
else if (!(ptr->attr & RS_ATTR_DELETED) &&
|
||||
!(fuf_flags&FUF_JUST_DIRS && !(ptr->attr & RS_ATTR_DIR)) &&
|
||||
!(fuf_flags&FUF_JUST_FILES && ptr->attr & RS_ATTR_DIR) &&
|
||||
!StrCmp(dname,ptr->name)) {
|
||||
MemCpy(&_res->attr,&ptr->attr,CDIR_SIZE);
|
||||
res=TRUE;
|
||||
goto rsff_done;
|
||||
}
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
}
|
||||
rsff_done:
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
U8 *RedSeaFileRead(CDrv *dv,U8 *cur_dir,U8 *filename,I64 *_size,I64 *_attr)
|
||||
{
|
||||
U8 *buf=NULL;
|
||||
CDirEntry de;
|
||||
I64 c,blk_cnt,cur_dir_cluster;
|
||||
DrvChk(dv);
|
||||
*_size=0;
|
||||
*_attr=0;
|
||||
if (dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else
|
||||
try {
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
if (RedSeaFileFind(dv,cur_dir_cluster,filename,&de,FUF_JUST_FILES)) {
|
||||
blk_cnt=(de.size+BLK_SIZE-1)>>BLK_SIZE_BITS;
|
||||
buf=MAlloc(blk_cnt<<BLK_SIZE_BITS+1);
|
||||
c=de.cluster;
|
||||
c=RBlks(dv,buf,c,blk_cnt);
|
||||
buf[de.size]=0; //Terminate
|
||||
*_size=de.size;
|
||||
*_attr=FileAttr(de.name,de.attr);
|
||||
}
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
return buf;
|
||||
}
|
||||
|
||||
Bool RedSeaCd(U8 *name,I64 cur_dir_cluster)
|
||||
{
|
||||
CDirEntry de;
|
||||
if (Fs->cur_dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else if (RedSeaFileFind(Fs->cur_dv,cur_dir_cluster,name,&de,FUF_JUST_DIRS))
|
||||
return TRUE;
|
||||
else {
|
||||
"%s ",name;
|
||||
PrintErr("File not found.\n");
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 RedSeaFreeClusters(CDrv *dv,I64 c,I64 cnt)
|
||||
{
|
||||
CFreeLst *tmpf;
|
||||
Bool found=FALSE,unlock,unlock_break;
|
||||
DrvChk(dv);
|
||||
if (!c) return;
|
||||
if (dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
if (!dv->next_free)
|
||||
RedSeaFreeLstBuild(dv);
|
||||
tmpf=dv->next_free;
|
||||
while (!found && tmpf!=&dv->next_free) {
|
||||
if (tmpf->start+tmpf->size==c) {
|
||||
tmpf->size+=cnt;
|
||||
found=TRUE;
|
||||
} else if (c+cnt==tmpf->start) {
|
||||
tmpf->size+=cnt;
|
||||
tmpf->start=c;
|
||||
found=TRUE;
|
||||
}
|
||||
tmpf=tmpf->next;
|
||||
}
|
||||
if (!found) {
|
||||
tmpf=AMAlloc(sizeof(CFreeLst));
|
||||
tmpf->size=cnt;
|
||||
tmpf->start=c;
|
||||
QueIns(tmpf,dv->last_free);
|
||||
}
|
||||
while (cnt-->0) {
|
||||
DrvFATBlkSet(dv,c);
|
||||
LBtr(dv->cur_fat_blk,(c-dv->data_area)&(BLK_SIZE<<3-1));
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
c++;
|
||||
}
|
||||
DrvFATBlkClean(dv);
|
||||
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
}
|
||||
|
||||
I64 RedSeaAllocClusters(CDrv *dv,I64 cnt)
|
||||
{
|
||||
CFreeLst *tmpf,*best_free=NULL;
|
||||
I64 i,first,best_size=I64_MAX;
|
||||
Bool unlock,unlock_break;
|
||||
if (cnt<=0)
|
||||
throw('Drv');
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
unlock=DrvLock(dv);
|
||||
if (!dv->next_free)
|
||||
RedSeaFreeLstBuild(dv);
|
||||
tmpf=dv->next_free;
|
||||
while (tmpf!=&dv->next_free) {
|
||||
if (tmpf->size>=cnt && tmpf->size<best_size) {
|
||||
best_free=tmpf;
|
||||
best_size=tmpf->size;
|
||||
if (tmpf->size==cnt)
|
||||
break;
|
||||
}
|
||||
tmpf=tmpf->next;
|
||||
}
|
||||
if (!best_free)
|
||||
throw('Drv');
|
||||
first=best_free->start;
|
||||
for (i=0;i<cnt;i++) {
|
||||
DrvFATBlkSet(dv,first+i);
|
||||
LBts(dv->cur_fat_blk,(first+i-dv->data_area)&(BLK_SIZE<<3-1));
|
||||
LBts(&dv->fat_blk_dirty,0);
|
||||
}
|
||||
DrvFATBlkClean(dv);
|
||||
if (best_free->size-=cnt)
|
||||
best_free->start+=cnt;
|
||||
else {
|
||||
QueRem(best_free);
|
||||
Free(best_free);
|
||||
}
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
Bool RedSeaDirNew(CDrv *dv,U8 *cur_dir,CDirEntry *tmpde,Bool free_old_chain)
|
||||
{
|
||||
CDirEntry *buf,*buf2,*ptr,de2;
|
||||
CRedSeaBoot *br;
|
||||
I64 c,ch,i=1,j=0,n=BLK_SIZE/CDIR_SIZE,dir_size,cur_dir_cluster;
|
||||
Bool written=FALSE,unlock,unlock_break;
|
||||
U8 *tmp,*parent_dir;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
tmpde->attr|=RS_ATTR_CONTIGUOUS;
|
||||
unlock=DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
buf2=MAlloc(BLK_SIZE);
|
||||
RBlks(dv,buf2,cur_dir_cluster,1);
|
||||
|
||||
ptr=buf2(U8 *)-offset(CDirEntry.start);
|
||||
buf=MAlloc(ptr->size);
|
||||
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
|
||||
|
||||
dir_size=ptr->size;
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start)+CDIR_SIZE;
|
||||
Free(buf2);
|
||||
while (TRUE) {
|
||||
if (!(ch=*ptr->name)) {
|
||||
if (!written)
|
||||
MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);
|
||||
if ((i+1)*CDIR_SIZE+j<<BLK_SIZE_BITS<dir_size)
|
||||
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
|
||||
else {
|
||||
buf2=CAlloc(dir_size+BLK_SIZE);
|
||||
MemCpy(buf2,buf,dir_size);
|
||||
RedSeaFreeClusters(dv,cur_dir_cluster,dir_size>>BLK_SIZE_BITS);
|
||||
dir_size+=BLK_SIZE;
|
||||
c=ClustersAlloc(dv,0,dir_size>>BLK_SIZE_BITS,TRUE);
|
||||
Free(buf);
|
||||
buf=buf2;
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start);
|
||||
ptr->size=dir_size;
|
||||
ptr->cluster=c;
|
||||
WBlks(dv,buf,c,dir_size>>BLK_SIZE_BITS);
|
||||
if (cur_dir_cluster==dv->root_cluster) {
|
||||
br=CAlloc(BLK_SIZE);
|
||||
RBlks(dv,br,dv->drv_offset,1);
|
||||
br->root_cluster=c;
|
||||
WBlks(dv,br,dv->drv_offset,1);
|
||||
Free(br);
|
||||
dv->root_cluster=c;
|
||||
} else {
|
||||
tmp=StrNew(cur_dir);
|
||||
parent_dir=StrNew(cur_dir);
|
||||
StrLastRem(parent_dir,"/",tmp);
|
||||
if (!*parent_dir) {
|
||||
Free(parent_dir);
|
||||
parent_dir=StrNew("/");
|
||||
}
|
||||
if (RedSeaFileFind(dv,Name2DirCluster(dv,parent_dir),
|
||||
tmp,&de2,FUF_JUST_DIRS)) {
|
||||
de2.cluster=c;
|
||||
de2.size=dir_size;
|
||||
RedSeaDirNew(dv,parent_dir,&de2,FALSE);
|
||||
} else
|
||||
throw('Drv');
|
||||
Free(tmp);
|
||||
Free(parent_dir);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else if (ptr->attr & RS_ATTR_DELETED) {
|
||||
if (!written) {
|
||||
MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);
|
||||
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
|
||||
written=TRUE;
|
||||
}
|
||||
} else {
|
||||
if (!StrCmp(tmpde->name,ptr->name)) {
|
||||
if (free_old_chain)
|
||||
RedSeaFreeClusters(dv,ptr->cluster,
|
||||
(ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS);
|
||||
if (!written)
|
||||
MemCpy(&ptr->start,&tmpde->start,CDIR_SIZE);
|
||||
else
|
||||
ptr->attr|=RS_ATTR_DELETED;
|
||||
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
if (++i>=n) {
|
||||
j++;
|
||||
i=0;
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
if (unlock)
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 RedSeaFilesDel(CDrv *dv,U8 *cur_dir,U8 *files_find_mask,I64 fuf_flags,
|
||||
Bool del_dir,Bool print_msg)
|
||||
{
|
||||
CDirEntry *buf,*buf2,*ptr;
|
||||
I64 i=0,res=0,ch,j=0,n=BLK_SIZE/CDIR_SIZE,cur_dir_cluster;
|
||||
Bool unlock_break;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,cur_dir);
|
||||
buf2=MAlloc(BLK_SIZE);
|
||||
RBlks(dv,buf2,cur_dir_cluster,1);
|
||||
|
||||
ptr=buf2(U8 *)-offset(CDirEntry.start);
|
||||
buf=MAlloc(ptr->size);
|
||||
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
|
||||
Free(buf2);
|
||||
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start);
|
||||
*ptr->name='.';
|
||||
ptr->name[1]=0;
|
||||
while (TRUE) {
|
||||
if (!(ch=*ptr->name))
|
||||
break;
|
||||
else if (!(ptr->attr & RS_ATTR_DELETED) && ch!='.' && (del_dir ||
|
||||
!(ptr->attr & RS_ATTR_DIR)) &&
|
||||
FilesFindMatch(ptr->name,files_find_mask,fuf_flags)) {
|
||||
if (!(ptr->attr & RS_ATTR_DIR)) res++;
|
||||
if (print_msg)
|
||||
"Del %s\n",ptr->name;
|
||||
ptr->attr|=RS_ATTR_DELETED;
|
||||
WBlks(dv,buf(U8 *)+j<<BLK_SIZE_BITS,cur_dir_cluster+j,1);
|
||||
RedSeaFreeClusters(dv,ptr->cluster,
|
||||
(ptr->size+BLK_SIZE-1)>>BLK_SIZE_BITS);
|
||||
}
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
if (++i>=n) {
|
||||
j++;
|
||||
i=0;
|
||||
}
|
||||
}
|
||||
Free(buf);
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch {
|
||||
DrvUnlock(dv);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 RedSeaFileWrite(CDrv *dv,U8 *cur_dir,U8 *name,U8 *buf,I64 size,
|
||||
CDate cdt,I64 attr)
|
||||
{
|
||||
CDirEntry de;
|
||||
I64 c=0,blk_cnt;
|
||||
MemSet(&de,0,sizeof(CDirEntry));
|
||||
if (size<0) size=0;
|
||||
if (dv->fs_type!=FSt_REDSEA)
|
||||
PrintErr("Not RedSea Drv\n");
|
||||
else if (!CFileNameTo(de.name,name))
|
||||
PrintErr("Invalid FileName.\n");
|
||||
else {
|
||||
RedSeaFilesDel(dv,cur_dir,de.name,0,FALSE,FALSE);
|
||||
de.size=size;
|
||||
if (blk_cnt=(size+BLK_SIZE-1)>>BLK_SIZE_BITS)
|
||||
c=ClustersAlloc(dv,0,blk_cnt,TRUE); //Always contiguous
|
||||
else
|
||||
c=INVALID_CLUSTER;
|
||||
de.cluster=c;
|
||||
de.attr=attr|RS_ATTR_CONTIGUOUS;
|
||||
de.datetime=cdt;
|
||||
if (blk_cnt)
|
||||
WBlks(dv,buf,c,blk_cnt);
|
||||
RedSeaDirNew(dv,cur_dir,&de,TRUE);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
CDirEntry *RedSeaFilesFind(U8 *files_find_mask,I64 fuf_flags,
|
||||
CDirEntry *parent=NULL)
|
||||
{
|
||||
CDrv *dv=Fs->cur_dv;
|
||||
CDirEntry *buf,*buf2,*ptr,*res=NULL,*tmpde;
|
||||
I64 ch,cur_dir_cluster;
|
||||
if (fuf_flags&~FUG_FILES_FIND)
|
||||
throw('FUF');
|
||||
try {
|
||||
DrvLock(dv);
|
||||
cur_dir_cluster=Name2DirCluster(dv,Fs->cur_dir);
|
||||
buf2=MAlloc(BLK_SIZE);
|
||||
RBlks(dv,buf2,cur_dir_cluster,1);
|
||||
|
||||
ptr=buf2(U8 *)-offset(CDirEntry.start);
|
||||
buf=MAlloc(ptr->size);
|
||||
RBlks(dv,buf,cur_dir_cluster,ptr->size>>BLK_SIZE_BITS);
|
||||
Free(buf2);
|
||||
|
||||
ptr=buf(U8 *)-offset(CDirEntry.start);
|
||||
*ptr->name='.';
|
||||
ptr->name[1]=0;
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
ptr->cluster=Name2ParentDirCluster(dv,Fs->cur_dir);
|
||||
ptr(U8 *)-=CDIR_SIZE;
|
||||
while (TRUE) {
|
||||
if (!(ch=*ptr->name))
|
||||
break;
|
||||
else if (!(ptr->attr & RS_ATTR_DELETED)) {
|
||||
tmpde=CAlloc(sizeof(CDirEntry));
|
||||
MemCpy(&tmpde->start,&ptr->start,CDIR_SIZE);
|
||||
tmpde->parent=parent;
|
||||
if (Bt(&fuf_flags,FUf_RECURSE) && tmpde->attr&RS_ATTR_DIR &&
|
||||
*tmpde->name!='.') {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
tmpde->full_name=DirNameAbs(tmpde->name);
|
||||
DrvUnlock(dv);
|
||||
if (Cd(tmpde->name)) {
|
||||
tmpde->sub=RedSeaFilesFind(files_find_mask,fuf_flags,tmpde);
|
||||
Cd("..");
|
||||
}
|
||||
DrvLock(dv);
|
||||
} else {
|
||||
tmpde->full_name=FileNameAbs(tmpde->name);
|
||||
if ((tmpde->attr&RS_ATTR_DIR ||
|
||||
!Bt(&fuf_flags,FUf_JUST_DIRS)) &&
|
||||
!(Bt(&fuf_flags,FUf_RECURSE) && *tmpde->name=='.' &&
|
||||
tmpde->attr&RS_ATTR_DIR) &&
|
||||
FilesFindMatch(tmpde->full_name,files_find_mask,fuf_flags)) {
|
||||
tmpde->next=res;
|
||||
res=tmpde;
|
||||
} else
|
||||
DirEntryDel(tmpde);
|
||||
}
|
||||
}
|
||||
ptr(U8 *)+=CDIR_SIZE;
|
||||
}
|
||||
Free(buf);
|
||||
DrvUnlock(dv);
|
||||
} catch
|
||||
DrvUnlock(dv);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool RedSeaMkDir(CDrv *dv,U8 *cur_dir,U8 *name,I64 entry_cnt)
|
||||
{//entry_cnt is for preallocating dir blks.
|
||||
I64 c,cur_dir_cluster=Name2DirCluster(dv,cur_dir),
|
||||
size=CeilU64((entry_cnt+3)<<6,BLK_SIZE);
|
||||
#assert CDIR_SIZE==64
|
||||
U8 *buf=CAlloc(size);
|
||||
CDirEntry *d_native=buf-offset(CDirEntry.start);
|
||||
Bool unlock_break;
|
||||
try {
|
||||
unlock_break=BreakLock;
|
||||
c=FileWrite(name,buf,size,0,RS_ATTR_DIR);
|
||||
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
|
||||
StrCpy(d_native->name,name);
|
||||
d_native->cluster=c;
|
||||
d_native->size=size;
|
||||
d_native->datetime=Now;
|
||||
d_native(U8 *)+=CDIR_SIZE;
|
||||
|
||||
d_native->attr=RS_ATTR_DIR|RS_ATTR_CONTIGUOUS;
|
||||
*d_native->name='.';
|
||||
d_native->name[1]='.';
|
||||
d_native->name[2]=0;
|
||||
d_native->cluster=cur_dir_cluster;
|
||||
d_native->size=0;
|
||||
d_native->datetime=Now;
|
||||
WBlks(dv,buf,c,1);
|
||||
Free(buf);
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
} catch
|
||||
if (unlock_break)
|
||||
BreakUnlock;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#exe {Cd(__DIR__);};
|
||||
#include "DskStrA"
|
||||
#include "DskCache"
|
||||
#include "DskATA"
|
||||
#include "DskATAId"
|
||||
#include "DskBlkDev"
|
||||
#include "DskDrv"
|
||||
#include "DskBlk"
|
||||
#include "DskCluster"
|
||||
#include "DskStrB"
|
||||
#include "DskAddDev"
|
||||
#include "DskDirA"
|
||||
#include "FileSysISO"
|
||||
#include "FileSysRedSea"
|
||||
#include "FileSysFAT"
|
||||
#include "DskDirContext"
|
||||
#include "DskFind"
|
||||
#include "DskDirB"
|
||||
#include "DskFile"
|
||||
#include "DskCFile"
|
||||
#include "DskCopy"
|
||||
#include "DskCDDVD"
|
||||
#include "DskFmt"
|
||||
#exe {Cd("..");};
|
||||
Reference in new issue
Block a user