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 count=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 (count > 0) f->max_blk = count - 1; else f->max_blk = I64_MAX; f->file_clus_num = INVALID_CLUS; full_name = FileNameAbs(filename); f->drive = Letter2Drive(*full_name); if (f->drive->fs_type == FSt_REDSEA) contiguous = TRUE; if (contiguous) { f->flags |= FF_CONTIGUOUS; if (f->drive->fs_type != FSt_REDSEA && !(FileAttr(filename) & RS_ATTR_CONTIGUOUS)) throw('File'); } f->clus_buf = CAlloc(f->drive->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)) { StrCopy(f->de.name, dirc->mask); if (count > 0) {//We pre-alloc the whole thing. f->de.clus = ClusAlloc(f->drive,0, (count + f->drive->spc - 1) / f->drive->spc, contiguous); f->de.size = count << BLK_SIZE_BITS; DirNew(dirc->drive, 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->drive, 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->drive, Fs->cur_dir, &f->de, TRUE); else DirNew(dirc->drive, 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) { CDrive *drive = f->drive; I64 i; if (f->clus != c) { if (f->flags & FF_BUF_DIRTY) { i = drive->spc; if (f->max_blk != I64_MAX) { i = f->max_blk + 1 - f->file_clus_num * drive->spc; if (i > drive->spc) i = drive->spc; } ClusBlkWrite(drive, f->clus_buf, f->clus, i); f->flags = f->flags & ~FF_BUF_DIRTY; } f->clus = c; f->file_clus_num = blk / drive->spc; if (read) { i = drive->spc; if (f->max_blk != I64_MAX) { i = f->max_blk + 1 - f->file_clus_num * drive->spc; if (i > drive->spc) i = drive->spc; } c = ClusBlkRead(drive, f->clus_buf, c, i); } } return c; } Bool FBlkRead(CFile *f, U8 *buf, I64 blk=FFB_NEXT_BLK, I64 count=1) {//Read [nth,n+count) blocks of file. CDrive *drive = f->drive; I64 spc = drive->spc, i, j, c = f->de.clus; if (!f || !drive) return FALSE; if (blk == FFB_NEXT_BLK) blk = f->fblk_num; if (blk + count - 1 > f->max_blk) return FALSE; if (count <= 0) return TRUE; if (f->flags & FF_CONTIGUOUS) { BlkRead(drive, buf, Clus2Blk(drive, c) + blk, count); blk += count; } else { i = blk / spc; if (0 <= f->file_clus_num <= i) { c = f->clus; i -= f->file_clus_num; } if (i > 0) c = ClusNumNext(drive, c, i); if (i = blk % spc) { c = FSetClus(f, c, blk, TRUE); if (count < spc - i) j = count; else j = spc - i; MemCopy(buf, f->clus_buf + i << BLK_SIZE_BITS, j << BLK_SIZE_BITS); buf += j << BLK_SIZE_BITS; count -= j; blk += j; } while (count >= spc) { c = FSetClus(f, c, blk, TRUE); MemCopy(buf, f->clus_buf, spc << BLK_SIZE_BITS); buf += spc << BLK_SIZE_BITS; count -= spc; blk += spc; } if (count > 0) { c = FSetClus(f, c, blk, TRUE); MemCopy(buf, f->clus_buf, count << BLK_SIZE_BITS); buf += count<<BLK_SIZE_BITS; blk += count; } } f->fblk_num = blk; return TRUE; } Bool FBlkWrite(CFile *f, U8 *buf, I64 blk=FFB_NEXT_BLK, I64 count=1) {//Write [nth,n+count) blocks of file. CDrive *drive = f->drive; I64 spc = drive->spc, i, j, c = f->de.clus, c1; if (!f || !drive) return FALSE; if (blk == FFB_NEXT_BLK) blk = f->fblk_num; if (blk + count - 1 > f->max_blk) return FALSE; if (!(f->flags & FF_WRITE)) return FALSE; if (count <= 0) return TRUE; if (f->flags & FF_CONTIGUOUS) { BlkWrite(drive, buf, Clus2Blk(drive, c) + blk, count); blk += count; } else { if (!c) { c = ClusAlloc(drive, 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(drive, c1, 1); if (c == INVALID_CLUS) { c = ClusAlloc(drive, c1, i, FALSE); if (i > 1) c = ClusNumNext(drive, c, i - 1); break; } else i--; } if (i = blk % spc) { FSetClus(f, c, blk, TRUE); if (count < spc - i) j = count; else j = spc - i; MemCopy(f->clus_buf + BLK_SIZE * i, buf, j << BLK_SIZE_BITS); f->flags |= FF_BUF_DIRTY; buf += j << BLK_SIZE_BITS; count -= j; blk += j; if (count > 0) { c1 = c; c = ClusNumNext(drive, c1, 1); if (c == INVALID_CLUS) c = ClusAlloc(drive, c1, 1, FALSE); } } while (count >= spc) { FSetClus(f, c, blk, FALSE); MemCopy(f->clus_buf, buf, spc << BLK_SIZE_BITS); f->flags |= FF_BUF_DIRTY; buf += spc << BLK_SIZE_BITS; count -= spc; blk += spc; if (count > 0) { c1 = c; c = ClusNumNext(drive, c1, 1); if (c == INVALID_CLUS) c = ClusAlloc(drive, c1, 1, FALSE); } } if (count > 0) { FSetClus(f, c, blk, TRUE); MemCopy(f->clus_buf, buf, count << BLK_SIZE_BITS); f->flags |= FF_BUF_DIRTY; buf += count << BLK_SIZE_BITS; blk += count; } if (f->de.size < blk << BLK_SIZE_BITS) f->de.size = blk << BLK_SIZE_BITS; } f->fblk_num = blk; return TRUE; }