I64 ClusNumNext(CDrv *dv,I64 c,I64 cnt=1)
{//Return next cnt'th clus in chain.
Bool unlock;
DrvChk(dv);
if (cnt<=0) return c;
try {
unlock=DrvLock(dv);
switch (dv->fs_type) {
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_CLUS;
break;
default:
throw('Drv');
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return c;
}
I64 Clus2Blk(CDrv *dv,I64 c)
{//Drv clus num to blk num.
DrvChk(dv);
switch (dv->fs_type) {
case FSt_REDSEA:
return c;
case FSt_FAT32:
return dv->data_area+c*dv->spc;
default:
throw('Drv');
}
}
I64 ClusBlkRead(CDrv *dv,U8 *buf,I64 c,I64 blks)
{//Accepts blk count, so padding on last clus is not read.
I64 i;
Bool unlock;
DrvChk(dv);
if (blks<=0) return c;
try {
unlock=DrvLock(dv);
switch (dv->fs_type) {
case FSt_REDSEA:
BlkRead(dv,buf,c,blks);
c+=blks;
break;
case FSt_FAT32:
while (blks && 0<c<0x0FFFFFF8) {
i=blks;
if (i>dv->spc)
i=dv->spc;
BlkRead(dv,buf,dv->data_area+c*dv->spc,i);
buf+=i<<BLK_SIZE_BITS;
c=ClusNumNext(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 ClusRead(CDrv *dv,U8 *buf,I64 c,I64 cnt)
{//Read clus cnt from drv to buf.
return ClusBlkRead(dv,buf,c,cnt*dv->spc);
}
I64 ClusBlkWrite(CDrv *dv,U8 *buf,I64 c,I64 blks)
{//Accepts blk count, so padding on last clus 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:
BlkWrite(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;
BlkWrite(dv,buf,dv->data_area+c*dv->spc,i);
buf+=i<<BLK_SIZE_BITS;
c=ClusNumNext(dv,c);
blks-=i;
}
break;
default:
throw('Drv');
}
if (unlock)
DrvUnlock(dv);
} catch
if (unlock)
DrvUnlock(dv);
return c;
}
I64 ClusWrite(CDrv *dv,U8 *buf,I64 c,I64 cnt)
{//Write clus cnt from buf to drv.
return ClusBlkWrite(dv,buf,c,cnt*dv->spc);
}
I64 ClusAlloc(CDrv *dv,I64 c=0,I64 cnt=1,Bool contiguous=FALSE)
{//Alloc clus cnt into chain.
//c=0 means first clus in chain
DrvChk(dv);
if (cnt<=0) return c;
switch (dv->fs_type) {
case FSt_REDSEA:
return RedSeaAllocClus(dv,cnt);
case FSt_FAT32:
if (contiguous) {
if (c) throw('File');
return FAT32AllocContiguousClus(dv,cnt);
} else
return FAT32AllocClus(dv,c,cnt);
default:
throw('Drv');
}
}