📄 cat.c
字号:
/****************************************************************************** File Name : cat.c Description : Master/Local CAT support routines.******************************************************************************//* Includes ---------------------------------------------------------------- */#include <stdlib.h>#include <stdio.h>#include <ctype.h>#include <string.h>#include <assert.h>#include "sttbx.h"#include "cat.h"#include "hal.h"#include "backup.h"/* Private Constants ------------------------------------------------------- */#define LCAT_CACHE_SIZE (16)/* Private Types ----------------------------------------------------------- */ typedef struct{ /* Local CAT Cache */ U16 LCatTime; stavfs_LocalCatCache_t LCatCache[LCAT_CACHE_SIZE]; /* Master CAT data */ /* The 'Blocks' field MUST be the last in the structure */ /* We over allocate space for the structure to increase */ /* The size of the 'Blocks' Array. */ U32 NumMCatBlocks; stavfs_MCatBlock_t Blocks[1];}stavfs_MCatCache_t;/* Private Variables ------------------------------------------------------- */static U64 const InvalidLBA = {INVALID_LBA, INVALID_LBA};static U64 const NullLBA = {NULL_LBA, NULL_LBA}; /* Private Macros ---------------------------------------------------------- *//* Private Function Prototypes --------------------------------------------- *//* Functions --------------------------------------------------------------- *//******************************************************************************Function Name : stavfs_InitCat Description : Formated the Master CAT for the file system. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_InitCat (stavfs_Device_t *Device_p){ ST_ErrorCode_t Error = ST_NO_ERROR; U32 NumMCatBlocks = 0; assert(Device_p != NULL); if (Device_p->MCat == NULL) { /* Not currently Open */ /* Round up */ NumMCatBlocks = (Device_p->NumClusterBlock/M_CAT_ENTRIES_PER_BLOCK) +1; Device_p->MCat = memory_allocate(Device_p->MemoryPartition, sizeof(stavfs_MCatCache_t) + (NumMCatBlocks-1)*sizeof(stavfs_MCatBlock_t)); if (Device_p->MCat == NULL) { STTBX_Print (("Out of memory.\n")); Error = ST_ERROR_NO_MEMORY; } else { /* Format the Master CAT */ int i; stavfs_MCatCache_t *Cache = (stavfs_MCatCache_t*)Device_p->MCat; Cache->NumMCatBlocks = NumMCatBlocks; /* Set the first block by hand */ /* Unused2 is overloaded to flag modified blocks */ /* Modified block */ Cache->Blocks[0].Unused2 = 1; for (i = 0; (i < M_CAT_ENTRIES_PER_BLOCK); i++) { Cache->Blocks[0].M_CatData[i] = CLUSTERS_PER_BLOCK(Device_p); } /* Copy the first block to all the others */ for (i = 1; (i < NumMCatBlocks); i++) { memcpy(Cache->Blocks+i, Cache->Blocks, sizeof(Cache->Blocks)); } /* Clear entries for missing Cluster blocks at the end */ for (i = Device_p->NumClusterBlock%M_CAT_ENTRIES_PER_BLOCK; (i < M_CAT_ENTRIES_PER_BLOCK); i++) { Cache->Blocks[NumMCatBlocks-1].M_CatData[i] = 0; } /* Initialise the LCAT Cache */ for (i = 0; (i < LCAT_CACHE_SIZE); i++) { Cache->LCatCache[i].RefCount = 0; Cache->LCatCache[i].InvalidData = 1; } if (Error != ST_NO_ERROR) { /* Free up the allocated space */ memory_deallocate(Device_p->MemoryPartition, Device_p->MCat); Device_p->MCat = NULL; } } } return (Error);}/******************************************************************************Function Name : stavfs_OpenCat Description : Open the Master CAT for the file system. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_OpenCat (stavfs_Device_t *Device_p){ ST_ErrorCode_t Error = ST_NO_ERROR; U32 NumMCatBlocks = 0; assert(Device_p != NULL); if (Device_p->MCat == NULL) { /* Not currently Open */ /* Round up */ NumMCatBlocks = (Device_p->NumClusterBlock/M_CAT_ENTRIES_PER_BLOCK) +1; Device_p->MCat = memory_allocate(Device_p->MemoryPartition, sizeof(stavfs_MCatCache_t) + (NumMCatBlocks-1)*sizeof(stavfs_MCatBlock_t)); if (Device_p->MCat == NULL) { STTBX_Print (("Out of memory.\n")); Error = ST_ERROR_NO_MEMORY; } else { /* Read the Master CAT */ int i; U64 LBA; stavfs_MCatCache_t *Cache = (stavfs_MCatCache_t*)Device_p->MCat; Cache->NumMCatBlocks = NumMCatBlocks; /* Skip the root sector */ INT_I64_AddLit(Device_p->RootSectorLBA, ROOT_SECTOR_AREA_SIZE, LBA); for (i = 0; (i < NumMCatBlocks); i++) { /* Skip to the next MCat Block (skips over backup area on first iter) */ INT_I64_AddLit(LBA, M_CAT_BLOCK_SIZE, LBA); if (ST_NO_ERROR != stavfs_BOWMCATRead(Device_p, &LBA, (U8*)(Cache->Blocks+i))) { /* Failed to read the MCat Block */ STTBX_Print (("Failed to read MCat Block %d. %X\n", i, LBA.LSW)); Error = STAVFS_ERROR_UNREADABLE_DISK; } } /* Initialise the LCAT Cache */ for (i = 0; (i < LCAT_CACHE_SIZE); i++) { Cache->LCatCache[i].RefCount = 0; Cache->LCatCache[i].InvalidData = 1; } if (Error != ST_NO_ERROR) { /* Free up the allocated space */ memory_deallocate(Device_p->MemoryPartition, Device_p->MCat); Device_p->MCat = NULL; } } } return (Error);}/******************************************************************************Function Name : stavfs_CloseCat Description : Close the Master CAT for the file system. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_CloseCat (stavfs_Device_t *Device_p){ ST_ErrorCode_t Error = ST_NO_ERROR; if ((Device_p != NULL) && (Device_p->MCat != NULL)) { Error = stavfs_FlushCat (Device_p); /* Free up any allocated space */ memory_deallocate(Device_p->MemoryPartition, Device_p->MCat); Device_p->MCat = NULL; } return (Error);}/******************************************************************************Function Name : stavfs_FlushCat Description : Flush any changes to disk. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_FlushCat(stavfs_Device_t *Device_p){ ST_ErrorCode_t Error = ST_NO_ERROR; stavfs_MCatCache_t *Cache_p = NULL; U64 LBA; assert(Device_p != NULL); if (Device_p->MCat != NULL) { int i; Cache_p = (stavfs_MCatCache_t*)Device_p->MCat; INT_I64_AddLit(Device_p->RootSectorLBA, ROOT_SECTOR_AREA_SIZE + M_CAT_BLOCK_SIZE, LBA); for (i = 0; (i < Cache_p->NumMCatBlocks); i++) { if (Cache_p->Blocks[i].Unused2) { /* Unused2 is overloaded to flag modified blocks */ /* Modified block */ Cache_p->Blocks[i].Unused2 = 0; if (ST_NO_ERROR != stavfs_BOWMCATWrite(Device_p, &LBA, (U8*)(Cache_p->Blocks+i))) { /* Failed to write the MCat Block */ STTBX_Print (("Failed to flush MCat Block %d.\n", i)); Error = STAVFS_ERROR_UNWRITABLE_DISK; Cache_p->Blocks[i].Unused2 = 1; } } INT_I64_AddLit(LBA, M_CAT_BLOCK_SIZE, LBA); } } return (Error);}/******************************************************************************Function Name : stavfs_GetNumFreeClusters Description : Return the number of free clusters. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_GetNumFreeClusters(stavfs_Device_t *Device_p, U64 *FreeClusters){ ST_ErrorCode_t Error = ST_NO_ERROR; stavfs_MCatCache_t *Cache_p = NULL; int i; int j; assert (Device_p != NULL); assert (Device_p->MCat != NULL); assert (FreeClusters != NULL); Cache_p = (stavfs_MCatCache_t*)Device_p->MCat; INT_I64_SetValue(0,0,*FreeClusters); for (i = 0; (i < Cache_p->NumMCatBlocks); i++) { for (j = 0; (j < M_CAT_ENTRIES_PER_BLOCK); j++) { INT_I64_AddLit(*FreeClusters, Cache_p->Blocks[i].M_CatData[j], *FreeClusters); } } return (Error);}/******************************************************************************Function Name : stavfs_GetFreeClusters Description : Find space in a Cluster Block for the required number of clusters. The LBA of the first Cluster is returned. This is need to link to the cluster before allocating the cluster. Parameters :******************************************************************************/U8 stavfs_GetFreeClusters(stavfs_Device_t *Device_p, U8 NumClusters, U64 const *PrevLBA_p, U64 *FreeLBA_p){ stavfs_MCatCache_t *Cache_p = NULL; U32 ClusterBlockId = 0; U32 ClusterIdx = 0; U32 M_CatBlockId = 0; U32 M_CatIdx = 0; assert (Device_p != NULL); assert (Device_p->MCat != NULL); assert (FreeLBA_p != NULL); Cache_p = (stavfs_MCatCache_t*)Device_p->MCat; INT_I64_SetValue(0,0,*FreeLBA_p); /* Find the Master CAT entry for the Prev LBA */ if (INT_I64_AreEqual(NullLBA, *PrevLBA_p)) { /* Default start position */ M_CatIdx = 0; M_CatBlockId = 0; } else { stavfs_GetClusterIdx(Device_p, &ClusterBlockId, &ClusterIdx, PrevLBA_p); M_CatIdx = ClusterBlockId % M_CAT_ENTRIES_PER_BLOCK; M_CatBlockId = ClusterBlockId / M_CAT_ENTRIES_PER_BLOCK; } /* Find the nearest cluster block with space */ { /* Find the nearest */ int BestFit = 0; int UpBlockId = M_CatBlockId; int UpIdx = M_CatIdx; int DownBlockId = M_CatBlockId; int DownIdx = M_CatIdx; while ((NumClusters > BestFit) && ((UpBlockId < Cache_p->NumMCatBlocks) || (DownBlockId >= 0))) { /* Look upwards */ if (UpBlockId < Cache_p->NumMCatBlocks) { /* Check for space */ if ((UpBlockId < Cache_p->NumMCatBlocks) && (BestFit <= Cache_p->Blocks[UpBlockId].M_CatData[UpIdx])) { /* There is space in this Block */ M_CatBlockId = UpBlockId; M_CatIdx = UpIdx; BestFit = Cache_p->Blocks[UpBlockId].M_CatData[UpIdx]; } /* Increment */ UpIdx++; if (UpIdx >= M_CAT_ENTRIES_PER_BLOCK) { UpBlockId++; UpIdx = 0; } } /* Look downwards */ if (DownBlockId >= 0) { /* Check for space */ if ((DownBlockId >= 0) && (BestFit <= Cache_p->Blocks[DownBlockId].M_CatData[DownIdx])) { /* There is space in this Block */ M_CatBlockId = DownBlockId; M_CatIdx = DownIdx; BestFit = Cache_p->Blocks[DownBlockId].M_CatData[DownIdx]; } /* Decrement */ DownIdx--; if (DownIdx < 0) { DownBlockId--; DownIdx = M_CAT_ENTRIES_PER_BLOCK-1; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -