📄 cat.c
字号:
/* Check to see if we have it already */ LocalCat_p = *ReturnCat_p; if ((LocalCat_p == NULL) || (LocalCat_p->InvalidData) || (LocalCat_p->ClusterBlockId != ClusterBlockId) || (LocalCat_p < Cache_p->LCatCache) || (LocalCat_p >= Cache_p->LCatCache + LCAT_CACHE_SIZE)) { /* We don't already have it */ LocalCat_p = NULL; } /* Locate in the Cache */ for (idx = 0; (idx < LCAT_CACHE_SIZE) && (LocalCat_p == NULL); idx++) { if ((ClusterBlockId == Cache_p->LCatCache[idx].ClusterBlockId) && !Cache_p->LCatCache[idx].InvalidData) { LocalCat_p = Cache_p->LCatCache +idx; } else if (InvalidCat_p != NULL) { /* We already know which entry to use */ } else if (Cache_p->LCatCache[idx].RefCount > 0) { /* This entry is in use */ } else if (Cache_p->LCatCache[idx].InvalidData) { InvalidCat_p = Cache_p->LCatCache +idx; } else { U16 Age = Cache_p->LCatTime - Cache_p->LCatCache[idx].TimeStamp; if (Age > OldestCat) { OldestCat = Age; OldCat_p = Cache_p->LCatCache +idx; } } } /* Did we find an entry */ if (LocalCat_p == NULL) { /* Allocate from Cache */ if (InvalidCat_p != NULL) { LocalCat_p = InvalidCat_p; } else if (OldCat_p != NULL) { LocalCat_p = OldCat_p; } else { /* This is bad */ /* The Cache is full */ Error = STAVFS_ERROR_CACHE_FULL; STTBX_Print(("LCat Cache is FULL\n")); } if (LocalCat_p != NULL) { /* Set up the entry */ LocalCat_p->ClusterBlockId = ClusterBlockId; LocalCat_p->RefCount = 0; LocalCat_p->InvalidData = 1; stavfs_GetLCatLBA(Device_p, ClusterBlockId, &(LocalCat_p->LBA)); } } /* Update the Cache State */ if (LocalCat_p != NULL) { LocalCat_p->RefCount++; LocalCat_p->TimeStamp = Cache_p->LCatTime; /* Ensure the data in Cache is correct */ if (LocalCat_p->InvalidData) { if (ST_NO_ERROR != (Error = stavfs_BOWCATRead(Device_p, &(LocalCat_p->LBA), (U8*)&(LocalCat_p->Data)))) { /* This is a bad CAT - return nothing */ LocalCat_p->RefCount--; LocalCat_p->InvalidData = 1; LocalCat_p = NULL; } else { LocalCat_p->InvalidData = 0; } } } *ReturnCat_p = LocalCat_p; return (Error);}/******************************************************************************Function Name : stavfs_SetLocalCat Description : Write the Local CAT to disk. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_SetLocalCat(stavfs_LocalCatCache_t *LocalCat_p, stavfs_Device_t *Device_p){ ST_ErrorCode_t Error = ST_NO_ERROR; assert(Device_p != NULL); assert(LocalCat_p != NULL); Error = stavfs_BOWCATWrite(Device_p, &(LocalCat_p->LBA), (U8*)&(LocalCat_p->Data)); return (Error);}/******************************************************************************Function Name : stavfs_InvalidLocalCat Description : The data in this Local CAT has been invalidated. Reload from disk when next requesting this Local CAT. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_InvalidLocalCat(stavfs_LocalCatCache_t *LocalCat_p){ LocalCat_p->InvalidData = 1; return (ST_NO_ERROR);}/******************************************************************************Function Name : stavfs_ReleaseLocalCat Description : Decrement the reference count so we know when it is free. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_ReleaseLocalCat(stavfs_LocalCatCache_t *LocalCat_p){ if (LocalCat_p == NULL) { /* NULL pointer - just ignore it */ return (ST_NO_ERROR); } else if (LocalCat_p->RefCount > 0) { LocalCat_p->RefCount--; return (ST_NO_ERROR); } else { /* This is a coding error and should never happen */ STTBX_Print(("Local CAT Cache %X has negative reference count\n", LocalCat_p->ClusterBlockId)); assert (LocalCat_p->RefCount != 0); return (!ST_NO_ERROR); }}/******************************************************************************Function Name : stavfs_WalkTheChain Description : Walk down the file cluster chain to the end do any fixes to the chain. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_WalkTheChain(stavfs_Device_t *Device_p, BOOL CheckMCat, U64 *LBA_p, U32 *Count_p){ ST_ErrorCode_t Error = ST_NO_ERROR; stavfs_MCatCache_t *Cache_p = NULL; U32 ThisClusterBlockId = 0; U32 ThisClusterIdx = 0; U32 LastClusterBlockId = 0; U32 LastClusterIdx = 0; U64 LastLBA = *LBA_p; U64 ThisLBA = *LBA_p; stavfs_LocalCatCache_t *LastLocalCat_p = NULL; stavfs_LocalCatCache_t *ThisLocalCat_p = NULL; assert (Device_p != NULL); assert (Device_p->MCat != NULL); assert (LBA_p != NULL); Cache_p = (stavfs_MCatCache_t*)Device_p->MCat; /* Sanity check */ if (INT_I64_AreEqual(*LBA_p, InvalidLBA)) { /* There is no chain !! */ Error = ST_ERROR_BAD_PARAMETER; } while ((Error == ST_NO_ERROR) && INT_I64_AreNotEqual(ThisLBA, NullLBA)) { /* Find the Local CAT entry for this LBA */ stavfs_GetClusterIdx(Device_p, &ThisClusterBlockId, &ThisClusterIdx, &ThisLBA); if (ST_NO_ERROR == (Error = stavfs_GetLocalCat(Device_p, ThisClusterBlockId, &ThisLocalCat_p))) { /* We could check the Master CAT here */ if (CheckMCat && ((LastLocalCat_p == NULL) || (LastClusterBlockId != ThisClusterBlockId))) { /* New Local CAT - Update the Master CAT */ stavfs_RebuildLocalCAT(Device_p, ThisLocalCat_p, FALSE); stavfs_UpdateMasterCAT(Device_p, ThisClusterBlockId, ThisLocalCat_p); } /* Do we link back correctly */ if ((LastLocalCat_p != NULL) && INT_I64_AreNotEqual(LastLBA, ThisLocalCat_p->Data.Cat[ThisClusterIdx].PrevLBA)) { /* Clean the Bad link */ STTBX_Print(("Fix a bad forward link\n")); LastLocalCat_p->Data.Cat[LastClusterIdx].NextLBA = NullLBA; ThisLBA = NullLBA; /* Flush the fix to disk */ stavfs_SetLocalCat(LastLocalCat_p, Device_p); /* Clean up */ stavfs_ReleaseLocalCat(ThisLocalCat_p); } else if (INT_I64_AreEqual(ThisLocalCat_p->Data.Cat[ThisClusterIdx].NextLBA, InvalidLBA) || INT_I64_AreEqual(ThisLocalCat_p->Data.Cat[ThisClusterIdx].PrevLBA, InvalidLBA)) { /* Unallocated Cluster (First Cluster) */ /* Correct the first cluster in the chain */ STTBX_Print(("Correct the first cluster in the chain\n")); ThisLBA = NullLBA; LastLBA = NullLBA; } else { stavfs_ReleaseLocalCat(LastLocalCat_p); LastClusterBlockId = ThisClusterBlockId; LastClusterIdx = ThisClusterIdx; LastLBA = ThisLBA; ThisLBA = ThisLocalCat_p->Data.Cat[ThisClusterIdx].NextLBA; LastLocalCat_p = ThisLocalCat_p; ThisLocalCat_p = NULL; /* Count the clusters */ if (Count_p != NULL) (*Count_p)++; } } } /* Clean up */ /* Release the local cat */ stavfs_ReleaseLocalCat(LastLocalCat_p); /* Return the last LBA in the chain */ *LBA_p = LastLBA; return (Error);}/******************************************************************************Function Name : stavfs_UpdateMasterCAT Description : Update the Master CAT from the local CAT. Parameters :******************************************************************************/void stavfs_UpdateMasterCAT(stavfs_Device_t *Device_p, U32 ClusterBlockId, stavfs_LocalCatCache_t *LocalCat_p){ /* Update the Master CAT entry for the Cluster Block */ U32 M_CatIdx; U32 M_BlockIdx; stavfs_MCatCache_t *Cache_p = NULL; assert (Device_p != NULL); assert (Device_p->MCat != NULL); assert (LocalCat_p != NULL); M_CatIdx = ClusterBlockId % M_CAT_ENTRIES_PER_BLOCK; M_BlockIdx = ClusterBlockId / M_CAT_ENTRIES_PER_BLOCK; Cache_p = (stavfs_MCatCache_t*)Device_p->MCat; if (Cache_p->Blocks[M_BlockIdx].M_CatData[M_CatIdx] != LocalCat_p->Data.FreeClusters) { Cache_p->Blocks[M_BlockIdx].Unused2 = 1; /* Flag Modified */ Cache_p->Blocks[M_BlockIdx].M_CatData[M_CatIdx] = LocalCat_p->Data.FreeClusters; }}/******************************************************************************Function Name : stavfs_RebuildLocalCAT Description : Rebuild the Local CAT from the local CAT. Parameters :******************************************************************************/ST_ErrorCode_t stavfs_RebuildLocalCAT(stavfs_Device_t *Device_p, stavfs_LocalCatCache_t *LocalCat_p, BOOL Force){ ST_ErrorCode_t Error = ST_NO_ERROR; BOOL Modified = FALSE; U32 Count; int j; #ifndef STAVFS_NO_BACKUP_ON_WRITE if (Force)#endif { /* Check the entries */ Count = 0; for (j = 0; (j < CLUSTERS_PER_BLOCK(Device_p)); j++) { if (INT_I64_AreEqual(LocalCat_p->Data.Cat[j].PrevLBA, InvalidLBA) || INT_I64_AreEqual(LocalCat_p->Data.Cat[j].NextLBA, InvalidLBA)) { /* This entry is free */ Count++; if (INT_I64_AreNotEqual(LocalCat_p->Data.Cat[j].PrevLBA, InvalidLBA)) { STTBX_Print(("Bad free PrevLBA Cluster %d:%d\n", LocalCat_p->ClusterBlockId, j)); LocalCat_p->Data.Cat[j].PrevLBA = InvalidLBA; Modified = TRUE; } else if (INT_I64_AreNotEqual(LocalCat_p->Data.Cat[j].NextLBA, InvalidLBA)) { STTBX_Print(("Bad free NextLBA Cluster %d:%d\n", LocalCat_p->ClusterBlockId, j)); LocalCat_p->Data.Cat[j].NextLBA = InvalidLBA; Modified = TRUE; } } } /* Check the free cluster count */ if (Count != LocalCat_p->Data.FreeClusters) { STTBX_Print(("LCAT %d: Bad free clusters count\n", LocalCat_p->ClusterBlockId)); LocalCat_p->Data.FreeClusters = Count; Modified = TRUE; } /* If we have modified the CAT then rewrite it */ if (Modified) { Error = stavfs_SetLocalCat(LocalCat_p, Device_p); } } return (Error);}/******************************************************************************Function Name : stavfs_ClearUnusedMasterCAT Description : Clear those Master CAT entries for which there are no Cluster Blocks. Parameters :******************************************************************************/void stavfs_ClearUnusedMasterCAT(stavfs_Device_t *Device_p, stavfs_LocalCatCache_t *LocalCat_p){ U32 M_CatIdx; U32 M_BlockIdx; stavfs_MCatCache_t *Cache_p = NULL; assert (Device_p->MCat != NULL); M_CatIdx = Device_p->NumClusterBlock % M_CAT_ENTRIES_PER_BLOCK; M_BlockIdx = Device_p->NumClusterBlock / M_CAT_ENTRIES_PER_BLOCK; Cache_p = (stavfs_MCatCache_t*)Device_p->MCat; for (; (M_CatIdx < M_CAT_ENTRIES_PER_BLOCK); ++M_CatIdx) { if (Cache_p->Blocks[M_BlockIdx].M_CatData[M_CatIdx] != 0) { /* There is no Cluster block so no free clusters */ Cache_p->Blocks[M_BlockIdx].M_CatData[M_CatIdx] = 0; Cache_p->Blocks[M_BlockIdx].Unused2 = 1; /* Flag Modified */ } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -