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 StrOcc() for 'w', 'r', '+', 'c') CFile *f=CAlloc(sizeof(CFile)); CDirContext *dirc; U8 *full_name; Bool contiguous=StrOcc(flags,'c'); f->clus=INVALID_CLUS; f->fblk_num=0; if (cnt>0) f->max_blk=cnt-1; else f->max_blk=I64_MAX; f->file_clus_num=INVALID_CLUS; 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->clus_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.clus=ClusAlloc(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->clus_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) { ClusWrite(f->dv,f->clus_buf,f->clus,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->clus_buf); Free(f->de.full_name); Free(f); } } I64 FSetClus(CFile *f,I64 c,I64 blk,Bool read) { CDrv *dv=f->dv; I64 i; if (f->clus!=c) { if (f->flags & FF_BUF_DIRTY) { i=dv->spc; if (f->max_blk!=I64_MAX) { i=f->max_blk+1-f->file_clus_num*dv->spc; if (i>dv->spc) i=dv->spc; } ClusBlkWrite(dv,f->clus_buf,f->clus,i); f->flags=f->flags & ~FF_BUF_DIRTY; } f->clus=c; f->file_clus_num=blk/dv->spc; if (read) { i=dv->spc; if (f->max_blk!=I64_MAX) { i=f->max_blk+1-f->file_clus_num*dv->spc; if (i>dv->spc) i=dv->spc; } c=ClusBlkRead(dv,f->clus_buf,c,i); } } return c; } Bool FBlkRead(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.clus; 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) { BlkRead(dv,buf,Clus2Blk(dv,c)+blk,cnt); blk+=cnt; } else { i=blk/spc; if (0<=f->file_clus_num<=i) { c=f->clus; i-=f->file_clus_num; } if (i>0) c=ClusNumNext(dv,c,i); if (i=blk%spc) { c=FSetClus(f,c,blk,TRUE); if (cnt<spc-i) j=cnt; else j=spc-i; MemCpy(buf,f->clus_buf+i<<BLK_SIZE_BITS,j<<BLK_SIZE_BITS); buf+=j<<BLK_SIZE_BITS; cnt-=j; blk+=j; } while (cnt>=spc) { c=FSetClus(f,c,blk,TRUE); MemCpy(buf,f->clus_buf,spc<<BLK_SIZE_BITS); buf+=spc<<BLK_SIZE_BITS; cnt-=spc; blk+=spc; } if (cnt>0) { c=FSetClus(f,c,blk,TRUE); MemCpy(buf,f->clus_buf,cnt<<BLK_SIZE_BITS); buf+=cnt<<BLK_SIZE_BITS; blk+=cnt; } } f->fblk_num=blk; return TRUE; } Bool FBlkWrite(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.clus,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) { BlkWrite(dv,buf,Clus2Blk(dv,c)+blk,cnt); blk+=cnt; } else { if (!c) { c=ClusAlloc(dv,0,1,FALSE); f->file_clus_num=0; f->clus=c; f->de.clus=c; f->flags|=FF_NEEDS_WRITE|FF_NEW_FILE; } i=blk/spc; if (0<=f->file_clus_num<=i) { c=f->clus; i-=f->file_clus_num; } while (i>0) { c1=c; c=ClusNumNext(dv,c1,1); if (c==INVALID_CLUS) { c=ClusAlloc(dv,c1,i,FALSE); if (i>1) c=ClusNumNext(dv,c,i-1); break; } else i--; } if (i=blk%spc) { FSetClus(f,c,blk,TRUE); if (cnt<spc-i) j=cnt; else j=spc-i; MemCpy(f->clus_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=ClusNumNext(dv,c1,1); if (c==INVALID_CLUS) c=ClusAlloc(dv,c1,1,FALSE); } } while (cnt>=spc) { FSetClus(f,c,blk,FALSE); MemCpy(f->clus_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=ClusNumNext(dv,c1,1); if (c==INVALID_CLUS) c=ClusAlloc(dv,c1,1,FALSE); } } if (cnt>0) { FSetClus(f,c,blk,TRUE); MemCpy(f->clus_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; }