📄 rwbuffer.c
字号:
/****************************************************************************** File Name : rwbuffer.c Description : Implementaion of the R/W Buffer internal API******************************************************************************//* Includes ---------------------------------------------------------------- */#include <stdlib.h>#include <stdio.h>#include <ctype.h>#include <assert.h>#include <string.h>#include "rwbuffer.h"#include "file.h"#include "hal.h"#include "sttbx.h"/* Private Types ----------------------------------------------------------- */typedef struct RWBuffer_s{ U64 LBA; U16 Flags; U16 ReferenceCount; U8 Buffer[DISK_SECTOR_SIZE];}RWBuffer_t;/* Private Constants ------------------------------------------------------- */#define RWB_FLAG_STREAM (0X0001) /* Stream data */#define RWB_FLAG_MODIFIED (0X0002)#define RWB_FLAG_IN_MEMORY (0X0004)/* Private Variables ------------------------------------------------------- *//* Private Macros ---------------------------------------------------------- *//* Private Function Prototypes --------------------------------------------- *//* Functions --------------------------------------------------------------- *//******************************************************************************Function Name : stavfs_InitRWCache Description : Initialise the R/W Cache. Allocate space for the R/W Buffers and initialise the data. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_InitRWCache(stavfs_Device_t *Device_p){ ST_ErrorCode_t Error = ST_NO_ERROR; Device_p->RWCache = memory_allocate(Device_p->MemoryPartition, 2*MAX_OPEN_FILES*sizeof(RWBuffer_t)); if (Device_p->RWCache == NULL) { Error = ST_ERROR_NO_MEMORY; } else { /* Initialise the buffers */ int i; for (i = 0; (i < 2*MAX_OPEN_FILES); i++) { ((RWBuffer_t*)Device_p->RWCache)[i].Flags = 0; ((RWBuffer_t*)Device_p->RWCache)[i].ReferenceCount = 0; } } return (Error);}/******************************************************************************Function Name : stavfs_TermRWCache Description : Terminate the R/W Cache. Flush data to disk and free any memory allocated. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_TermRWCache(stavfs_Device_t *Device_p){ ST_ErrorCode_t Error = ST_NO_ERROR; assert (NULL != Device_p); if (NULL != Device_p->HALData) { /* Flush any data to disk */ Error = stavfs_FlushRWCache(Device_p); } /* Free up any allocated space */ if (Device_p->RWCache != NULL) { memory_deallocate(Device_p->MemoryPartition, Device_p->RWCache); Device_p->RWCache = NULL; } return (ST_NO_ERROR);}/******************************************************************************Function Name : stavfs_FlushRWCache Description : Flush the R/W Cache. Flush data to disk. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_FlushRWCache(stavfs_Device_t *Device_p){ ST_ErrorCode_t Error = ST_NO_ERROR; int i; RWBuffer_t *BufferTable = NULL; assert (NULL != Device_p); assert (NULL != Device_p->HALData); BufferTable = (RWBuffer_t*)Device_p->RWCache; if (BufferTable != NULL) { /* Look for modified buffers and write the to disk */ for (i = 0; (i < 2*MAX_OPEN_FILES); i++) { if (BufferTable[i].Flags & RWB_FLAG_MODIFIED) { BufferTable[i].Flags &= ~RWB_FLAG_MODIFIED; if (ST_NO_ERROR != stavfs_HalWrite (Device_p->HALData, &(BufferTable[i].LBA), 1, (char*)BufferTable[i].Buffer, BufferTable[i].Flags & RWB_FLAG_STREAM)) { Error = STAVFS_ERROR_UNWRITABLE_DISK; } } } } return (Error);}/******************************************************************************Function Name : stavfs_DiscardRWBuffer Description : Finish with the R/W Cache Buffer. Flush data to disk. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_DiscardRWBuffer(stavfs_Device_t *Device_p, stavfs_RWBufferRef_t *Buff){ ST_ErrorCode_t Error = ST_NO_ERROR; RWBuffer_t *Buffer = NULL; assert (NULL != Device_p); assert (NULL != Device_p->HALData); assert (NULL != Buff); Buffer = *(RWBuffer_t**)Buff; if (NULL != Buffer) { /* If the Buffer is no longer used and has been modified */ if ((--(Buffer->ReferenceCount) == 0) && (Buffer->Flags & RWB_FLAG_MODIFIED)) { /* Flush the buffer to disk */ Buffer->Flags &= ~RWB_FLAG_MODIFIED; Error = stavfs_HalWrite (Device_p->HALData, &(Buffer->LBA), 1, (char*)Buffer->Buffer, Buffer->Flags & RWB_FLAG_STREAM); } *(RWBuffer_t**)Buff = NULL; } return (Error);}/******************************************************************************Function Name : stavfs_AcquireRWBuffer Description : Obtain a R/W Cache Buffer. Flush data to disk. Parameters :******************************************************************************/stavfs_RWBufferRef_t stavfs_AcquireRWBuffer(stavfs_Device_t *Device_p, U64 *Sector, BOOL Streem){ int i; RWBuffer_t *BufferTable = NULL; RWBuffer_t *FreeBuffer = NULL; RWBuffer_t *AssignedBuffer = NULL; assert (NULL != Device_p); assert (NULL != Device_p->RWCache); BufferTable = (RWBuffer_t*)Device_p->RWCache; /* Find any existing Buffer for this Sector */ for (i = 0; (i < 2*MAX_OPEN_FILES) && (AssignedBuffer == NULL); i++) { if (INT_I64_AreEqual(*Sector, BufferTable[i].LBA)) { AssignedBuffer = BufferTable+i; } else if (BufferTable[i].ReferenceCount == 0) { FreeBuffer = BufferTable+i; } } /* If there is no existing buffer allocate the free buffer */ if ((AssignedBuffer == NULL) && (FreeBuffer != NULL)) { /* Allocate the Free Buffer */ AssignedBuffer = FreeBuffer; AssignedBuffer->LBA = *Sector; AssignedBuffer->Flags = (Streem)?(RWB_FLAG_STREAM):(0); } if (AssignedBuffer != NULL) { /* Increment the reference count */ AssignedBuffer->ReferenceCount++; } return (AssignedBuffer);}/******************************************************************************Function Name : stavfs_SetRWBuffer Description : Set the given buffer reference to a buffer for the given LBA. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_SetRWBuffer(stavfs_Device_t *Device_p, U64 *Sector, stavfs_RWBufferRef_t *Buff, BOOL Streem){ ST_ErrorCode_t Error = ST_NO_ERROR; RWBuffer_t *Buffer; assert (NULL != Device_p); assert (NULL != Device_p->RWCache); assert (NULL != Sector); assert (NULL != Buff); Buffer = (RWBuffer_t*)(*Buff); if (Buffer == NULL) { *Buff = stavfs_AcquireRWBuffer (Device_p, Sector, Streem); if (NULL == *Buff) { Error = STAVFS_ERROR_CACHE_FULL; } } else if (INT_I64_AreNotEqual(*Sector, Buffer->LBA)) { if (ST_NO_ERROR != (Error = stavfs_DiscardRWBuffer (Device_p, Buff))) { } else if (NULL == (*Buff = stavfs_AcquireRWBuffer (Device_p, Sector, Streem))) { Error = STAVFS_ERROR_CACHE_FULL; } } return (Error);}/******************************************************************************Function Name : stavfs_RWCacheBlockRead Description : Read a block of sectors from disk. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_RWCacheBlockRead(stavfs_Device_t *Device_p, U64 *FirstSector, U32 NbSectors, char *MemoryDestination, BOOL Streem){ int i; U64 LastSector; ST_ErrorCode_t Error = ST_NO_ERROR; RWBuffer_t *BufferTable = NULL; assert (NULL != Device_p); assert (NULL != Device_p->HALData); assert (NULL != Device_p->RWCache); BufferTable = (RWBuffer_t*)Device_p->RWCache; Error = stavfs_HalRead (Device_p->HALData, FirstSector, NbSectors, MemoryDestination, Streem); if (Error == ST_NO_ERROR) { /* Find all buffers affecting this read */ INT_I64_AddLit(*FirstSector, NbSectors, LastSector); for (i = 0; (i < 2*MAX_OPEN_FILES); i++) { if (INT_I64_IsGreaterOrEqual(BufferTable[i].LBA, *FirstSector) && INT_I64_IsLessThan (BufferTable[i].LBA, LastSector)) { if (BufferTable[i].Flags & RWB_FLAG_MODIFIED) { U32 Offset; INT_I64_LitDiff(BufferTable[i].LBA, *FirstSector, Offset); Offset *= DISK_SECTOR_SIZE; /* Copy from the buffer */ memcpy(MemoryDestination +Offset, BufferTable[i].Buffer, sizeof(BufferTable[i].Buffer)); } } } } return (Error);}/******************************************************************************Function Name : stavfs_RWCacheBlockWrite Description : Write a block of sectors to disk. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_RWCacheBlockWrite(stavfs_Device_t *Device_p, U64 *FirstSector, U32 NbSectors, char const *MemoryDestination, BOOL Streem){ int i; U64 LastSector; ST_ErrorCode_t Error = ST_NO_ERROR; RWBuffer_t *BufferTable = NULL; assert (NULL != Device_p); assert (NULL != Device_p->HALData); assert (NULL != Device_p->RWCache); assert (0 != NbSectors); BufferTable = (RWBuffer_t*)Device_p->RWCache; Error = stavfs_HalWrite (Device_p->HALData, FirstSector, NbSectors, MemoryDestination, Streem); if (Error == ST_NO_ERROR) { /* Find all buffers affected by this write */ INT_I64_AddLit(*FirstSector, NbSectors, LastSector); for (i = 0; (i < 2*MAX_OPEN_FILES); i++) { if (INT_I64_IsGreaterOrEqual(BufferTable[i].LBA, *FirstSector) && INT_I64_IsLessThan (BufferTable[i].LBA, LastSector)) { U32 Offset; INT_I64_LitDiff(BufferTable[i].LBA, *FirstSector, Offset); Offset *= DISK_SECTOR_SIZE; /* Copy from the buffer */ memcpy(BufferTable[i].Buffer, MemoryDestination +Offset, sizeof(BufferTable[i].Buffer)); BufferTable[i].Flags &= ~RWB_FLAG_MODIFIED; /* Not Modified */ BufferTable[i].Flags |= RWB_FLAG_IN_MEMORY; /* Data in Memory */ } } } return (Error);}/******************************************************************************Function Name : stavfs_RWBufferRead Description : Read data from a RWBuffer. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_RWBufferRead(stavfs_Device_t *Device_p, stavfs_RWBufferRef_t Buff, U32 Offset, U32 Size, char *MemoryDestination){ ST_ErrorCode_t Error = ST_NO_ERROR; RWBuffer_t *Buffer = NULL; assert (NULL != Buff); assert (NULL != Device_p); assert (NULL != Device_p->HALData); Buffer = (RWBuffer_t*)Buff; /* Normalise the data */ if (Size+Offset > DISK_SECTOR_SIZE) { Size -= Size+Offset-DISK_SECTOR_SIZE; } if (Offset < DISK_SECTOR_SIZE) { /* Load the data from disk */ if (!(Buffer->Flags & RWB_FLAG_IN_MEMORY)) { Error = stavfs_HalRead (Device_p->HALData, &(Buffer->LBA), 1, (char*)Buffer->Buffer, Buffer->Flags & RWB_FLAG_STREAM); Buffer->Flags |= RWB_FLAG_IN_MEMORY; } if (Error == ST_NO_ERROR) { memcpy(MemoryDestination, Buffer->Buffer+Offset, Size); } } return (Error);}/******************************************************************************Function Name : stavfs_RWBufferWrite Description : Write data to a RWBuffer. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_RWBufferWrite(stavfs_Device_t *Device_p, stavfs_RWBufferRef_t Buff, U32 Offset, U32 Size, char const *MemoryDestination, BOOL EndOfFile){ ST_ErrorCode_t Error = ST_NO_ERROR; RWBuffer_t *Buffer = NULL; assert (NULL != Buff); assert (NULL != Device_p); assert (NULL != Device_p->HALData); Buffer = (RWBuffer_t*)Buff; /* Normalise the data */ if (Size+Offset > DISK_SECTOR_SIZE) { Size -= Size+Offset-DISK_SECTOR_SIZE; } if (Offset < DISK_SECTOR_SIZE) { /* Load the data from disk */ /* If this sector is beyond EOF then it is as good as whats in memory */ if (EndOfFile) Buffer->Flags |= RWB_FLAG_IN_MEMORY; if (!(Buffer->Flags & RWB_FLAG_IN_MEMORY)) { Error = stavfs_HalRead (Device_p->HALData, &(Buffer->LBA), 1, (char*)Buffer->Buffer, Buffer->Flags & RWB_FLAG_STREAM); Buffer->Flags |= RWB_FLAG_IN_MEMORY; } if (Error == ST_NO_ERROR) { memcpy(Buffer->Buffer+Offset, MemoryDestination, Size); Buffer->Flags |= RWB_FLAG_MODIFIED; } } return (Error);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -