diff --git a/.clang-format b/.clang-format index 6eb27b9f2..7f24705c1 100644 --- a/.clang-format +++ b/.clang-format @@ -8,7 +8,8 @@ AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Inline +AllowShortFunctionsOnASingleLine: None +AllowShortIfStatementsOnASingleLine: Never AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false diff --git a/libs/RVL_SDK/include/revolution/vf/pf_cache.h b/libs/RVL_SDK/include/revolution/vf/pf_cache.h index b7a7c1b22..364fa25b9 100644 --- a/libs/RVL_SDK/include/revolution/vf/pf_cache.h +++ b/libs/RVL_SDK/include/revolution/vf/pf_cache.h @@ -7,4 +7,12 @@ s32 VFiPFCACHE_UpdateModifiedSector(PF_VOLUME* p_vol, PF_CACHE_PAGE* p_page, u32 s32 VFiPFCACHE_ReadFATPage(PF_VOLUME* p_vol, u32 sector, PF_CACHE_PAGE** pp_page); +s32 VFiPFCACHE_WriteFATPage(PF_VOLUME* p_vol, PF_CACHE_PAGE* p_page); + +s32 VFiPFCACHE_AllocateDataPage(PF_VOLUME* p_vol, u32 sector, PF_CACHE_PAGE** pp_page); + +s32 VFiPFCACHE_FlushFATCache(PF_VOLUME* p_vol); + +void VFiPFCACHE_FreeDataPage(PF_VOLUME* p_vol, PF_CACHE_PAGE* p_page); + #endif // PF_CACHE_H diff --git a/libs/RVL_SDK/include/revolution/vf/pf_clib.h b/libs/RVL_SDK/include/revolution/vf/pf_clib.h new file mode 100644 index 000000000..e9cd4a923 --- /dev/null +++ b/libs/RVL_SDK/include/revolution/vf/pf_clib.h @@ -0,0 +1,8 @@ +#ifndef PF_CLIB_H +#define PF_CLIB_H + +#include "revolution/types.h" + +void* VFipf_memset(void* dst, long c, unsigned long length); + +#endif // PF_CLIB_H diff --git a/libs/RVL_SDK/include/revolution/vf/pf_driver.h b/libs/RVL_SDK/include/revolution/vf/pf_driver.h new file mode 100644 index 000000000..38e1984e5 --- /dev/null +++ b/libs/RVL_SDK/include/revolution/vf/pf_driver.h @@ -0,0 +1,14 @@ +#ifndef PF_DRIVER_H +#define PF_DRIVER_H + +#include "revolution/vf/vf_struct.h" + +s32 VFiPFDRV_lwrite(PF_VOLUME* p_vol, const u8* buf, u32 sector, u32 num_sectors, u32* p_num_success); + +s32 VFiPFDRV_GetFSINFOInformation(PF_VOLUME* p_vol); + +s32 VFiPFDRV_StoreFreeCountToFSINFO(PF_VOLUME* p_vol); + +s32 VFiPFDRV_lerase(PF_VOLUME* p_vol, u32 sector, u32 num_sectors); + +#endif // PF_DRIVER_H diff --git a/libs/RVL_SDK/include/revolution/vf/pf_fat.h b/libs/RVL_SDK/include/revolution/vf/pf_fat.h index f76ea28fb..074785bcb 100644 --- a/libs/RVL_SDK/include/revolution/vf/pf_fat.h +++ b/libs/RVL_SDK/include/revolution/vf/pf_fat.h @@ -5,10 +5,16 @@ s32 VFiPFFAT_ReadFATSector(PF_VOLUME* p_vol, PF_CACHE_PAGE** pp_page, u32 cluster); -s32 VFiPFFAT_ReadFATEntryPage(PF_VOLUME* p_vol, u32 cluster, u32* p_value, PF_CACHE_PAGE** pp_page); - s32 VFiPFFAT_UpdateFATEntry(PF_VOLUME* p_vol, PF_CACHE_PAGE* p_page); s32 VFiPFFAT_ClearClusterLink(PF_FFD* p_ffd, u32 chain_index); +s32 VFiPFFAT_WriteFATEntryPage(PF_VOLUME* p_vol, u32 cluster, u32 value, PF_CACHE_PAGE** p_page); + +s32 VFiPFFAT_RefreshFSINFO(PF_VOLUME* p_vol); + +s32 VFiPFFAT_FreeChain(PF_FFD* p_ffd, u32 start_cluster, u32 chain_index, u32 size); + +s32 VFiPFFAT_GetNumberOfCluster(PF_FFD* p_ffd, u32 chain_index, u32 may_allocate, u32*); + #endif // PF_FAT_H diff --git a/libs/RVL_SDK/include/revolution/vf/pf_fat12.h b/libs/RVL_SDK/include/revolution/vf/pf_fat12.h index 0fbf9b395..e2e02d4aa 100644 --- a/libs/RVL_SDK/include/revolution/vf/pf_fat12.h +++ b/libs/RVL_SDK/include/revolution/vf/pf_fat12.h @@ -3,7 +3,7 @@ #include "revolution/vf/vf_struct.h" -s32 VFiPFFAT12_READFATEntry(PF_VOLUME* p_vol, u16 cluster, u32* p_value); +s32 VFiPFFAT12_ReadFATEntry(PF_VOLUME* p_vol, u16 cluster, u32* p_value); s32 VFiPFFAT12_ReadFATEntryPage(PF_VOLUME* p_vol, u16 cluster, u32* p_value, PF_CACHE_PAGE** pp_page); s32 VFiPFFAT12_WriteFATEntry(PF_VOLUME* p_vol, u16 cluster, u16 value); s32 VFiPFFAT12_WriteFATEntryPage(PF_VOLUME* p_vol, u16 cluster, u16 value, PF_CACHE_PAGE** pp_page); diff --git a/libs/RVL_SDK/include/revolution/vf/pf_fat16.h b/libs/RVL_SDK/include/revolution/vf/pf_fat16.h index ded3f9b42..ee031ed72 100644 --- a/libs/RVL_SDK/include/revolution/vf/pf_fat16.h +++ b/libs/RVL_SDK/include/revolution/vf/pf_fat16.h @@ -3,6 +3,10 @@ #include "revolution/vf/vf_struct.h" +s32 VFiPFFAT16_ReadFATEntry(PF_VOLUME* p_vol, u32 cluster, u32* p_value); + +s32 VFiPFFAT16_ReadFATEntryPage(PF_VOLUME* p_vol, u32 cluster, u32* p_value, PF_CACHE_PAGE** pp_page); + s32 VFiPFFAT16_WriteFATEntry(PF_VOLUME* p_vol, u32 cluster, u32 value); #endif // PF_FAT16_H diff --git a/libs/RVL_SDK/include/revolution/vf/pf_fat32.h b/libs/RVL_SDK/include/revolution/vf/pf_fat32.h index c53c88198..bfb742047 100644 --- a/libs/RVL_SDK/include/revolution/vf/pf_fat32.h +++ b/libs/RVL_SDK/include/revolution/vf/pf_fat32.h @@ -3,6 +3,10 @@ #include "revolution/vf/vf_struct.h" +s32 VFiPFFAT32_ReadFATEntry(PF_VOLUME* p_vol, u32 cluster, u32* p_value); + +s32 VFiPFFAT32_ReadFATEntryPage(PF_VOLUME* p_vol, u32 cluster, u32* p_value, PF_CACHE_PAGE** pp_page); + s32 VFiPFFAT32_WriteFATEntry(PF_VOLUME* p_vol, u32 cluster, u32 value); #endif // PF_FAT32_H diff --git a/libs/RVL_SDK/include/revolution/vf/pf_sector.h b/libs/RVL_SDK/include/revolution/vf/pf_sector.h index 696cca31f..911d78311 100644 --- a/libs/RVL_SDK/include/revolution/vf/pf_sector.h +++ b/libs/RVL_SDK/include/revolution/vf/pf_sector.h @@ -7,4 +7,6 @@ s32 VFiPFSEC_ReadFAT(PF_VOLUME* p_vol, u8* p_buf, u32 sector, u16 offset, u16 si s32 VFiPFSEC_WriteFAT(PF_VOLUME* p_vol, const u8* p_buf, u32 sector, u16 offset, u16 size); +s32 VFiPFSEC_WriteDataSector(PF_VOLUME* p_vol, const u8* p_buf, u32 sector, u32 size, u32* p_success_size, u32 is_direct, u32 set_sig); + #endif // PF_SECTOR_H diff --git a/libs/RVL_SDK/include/revolution/vf/vf_struct.h b/libs/RVL_SDK/include/revolution/vf/vf_struct.h index 66f665081..f923dfe03 100644 --- a/libs/RVL_SDK/include/revolution/vf/vf_struct.h +++ b/libs/RVL_SDK/include/revolution/vf/vf_struct.h @@ -70,11 +70,11 @@ typedef struct PF_DIR_ENT { unsigned short entry_offset; // offset 0x23C, size 0x2 } PF_DIR_ENT; -struct PF_FAT_HINT { +typedef struct PF_FAT_HINT { // total size: 0x8 unsigned long chain_index; // offset 0x0, size 0x4 unsigned long cluster; // offset 0x4, size 0x4 -}; +} PF_FAT_HINT; struct PF_CLUSTER_LINK { // total size: 0x14 diff --git a/src/RVL_SDK/vf/pf_fat.c b/src/RVL_SDK/vf/pf_fat.c index af8ebfe31..d2bbe44a2 100644 --- a/src/RVL_SDK/vf/pf_fat.c +++ b/src/RVL_SDK/vf/pf_fat.c @@ -1,26 +1,63 @@ #include "revolution/vf/pf_fat.h" +#include "revolution/types.h" #include "revolution/vf/pf_cache.h" +#include "revolution/vf/pf_clib.h" +#include "revolution/vf/pf_driver.h" #include "revolution/vf/pf_fat12.h" #include "revolution/vf/pf_fat16.h" #include "revolution/vf/pf_fat32.h" +#include "revolution/vf/pf_sector.h" static struct { - unsigned long bad; - unsigned long eoc1; - unsigned long eoc2; - unsigned long fat0_mask; - unsigned long fat1; + u32 bad; + u32 eoc1; + u32 eoc2; + u32 fat0_mask; + u32 fat1; } fat_special_values[3] = { {0xFF7, 0xFF8, 0xFFF, 0xF00, 0xFFF}, // FAT12 {0xFFF7, 0xFFF8, 0xFFFF, 0xFF00, 0xFFFF}, // FAT16 {0xFFFFFF7, 0xFFFFFF8, 0xFFFFFFF, 0xFFFFF00, 0xFFFFFFF} // FAT32 }; +static s32 VFiPFFAT_ReadFATEntry(PF_VOLUME* p_vol, u32 cluster, u32* p_value) { + u32 fat_type; + + fat_type = p_vol->bpb.fat_type; + if (fat_type == FAT_16) + return VFiPFFAT16_ReadFATEntry(p_vol, cluster, p_value); + if (fat_type >= FAT_16) { + if (fat_type < (FAT_32 | FAT_16)) + return VFiPFFAT32_ReadFATEntry(p_vol, cluster, p_value); + } else if (fat_type >= FAT_12) { + return VFiPFFAT12_ReadFATEntry(p_vol, cluster, p_value); + } + *p_value = -1; + return 15; +} + +static s32 VFiPFFAT_ReadFATEntryPage(PF_VOLUME* p_vol, u32 cluster, u32* p_value, PF_CACHE_PAGE** p_page) { + u32 fat_type; // r0 + + fat_type = p_vol->bpb.fat_type; + if (fat_type == FAT_16) + return VFiPFFAT16_ReadFATEntryPage(p_vol, cluster, p_value, p_page); + if (fat_type >= FAT_16) { + if (fat_type >= (FAT_32 | FAT_16)) + return 15; + return VFiPFFAT32_ReadFATEntryPage(p_vol, cluster, p_value, p_page); + } else { + if (fat_type < FAT_12) + return 15; + return VFiPFFAT12_ReadFATEntryPage(p_vol, cluster, p_value, p_page); + } +} + s32 VFiPFFAT_ReadFATSector(PF_VOLUME* p_vol, PF_CACHE_PAGE** pp_page, u32 cluster) { int fat_type; - unsigned int offset; - unsigned int sector; - unsigned int current_fat; + u32 offset; + u32 sector; + u32 current_fat; int err; int v10; @@ -65,17 +102,17 @@ s32 VFiPFFAT_ReadFATSector(PF_VOLUME* p_vol, PF_CACHE_PAGE** pp_page, u32 cluste return 0; } -s32 VFiPFFAT_SearchForNumFreeClusters(PF_VOLUME* p_vol, unsigned int start_cluster, unsigned int end_cluster, unsigned int num_cluster, - unsigned int* p_start_free_cluster, unsigned int* p_last_free_cluster) { - unsigned int v7; - unsigned int v8; - unsigned int success_num; - unsigned int save_start_cluster; - unsigned int v13; - unsigned int upper_bound_cluster; +s32 VFiPFFAT_SearchForNumFreeClusters(PF_VOLUME* p_vol, u32 start_cluster, u32 end_cluster, u32 num_cluster, u32* p_start_free_cluster, + u32* p_last_free_cluster) { + u32 v7; + u32 v8; + u32 success_num; + u32 save_start_cluster; + u32 v13; + u32 upper_bound_cluster; int result; PF_CACHE_PAGE* p_page; - unsigned int temp_start_cluster; + u32 temp_start_cluster; int search_flg; u32 fat_entry[14]; @@ -138,7 +175,7 @@ s32 VFiPFFAT_SearchForNumFreeClusters(PF_VOLUME* p_vol, unsigned int start_clust return result; } -s32 VFiPFFAT_UpdateClusterLink(PF_FFD* p_ffd, unsigned int cluster, unsigned int chain_index) { +s32 VFiPFFAT_UpdateClusterLink(PF_FFD* p_ffd, u32 cluster, u32 chain_index) { if (p_ffd->cluster_link.max_count > p_ffd->cluster_link.position && p_ffd->cluster_link.max_count) { if (chain_index == p_ffd->cluster_link.position * (p_ffd->cluster_link.interval + 1)) { p_ffd->cluster_link.interval_offset = 0; @@ -151,12 +188,12 @@ s32 VFiPFFAT_UpdateClusterLink(PF_FFD* p_ffd, unsigned int cluster, unsigned int return 0; } -s32 VFiPFFAT_FindClusterLink(PF_FFD* p_ffd, unsigned int chain_index, unsigned int* p_cluster, unsigned int* is_found) { +s32 VFiPFFAT_FindClusterLink(PF_FFD* p_ffd, u32 chain_index, u32* p_cluster, u32* is_found) { int result; - unsigned int position; - unsigned int offset; - unsigned int current_cluster; - unsigned int i; + u32 position; + u32 offset; + u32 current_cluster; + u32 i; PF_CACHE_PAGE* p_page; u32 next_cluster; @@ -194,11 +231,11 @@ s32 VFiPFFAT_FindClusterLink(PF_FFD* p_ffd, unsigned int chain_index, unsigned i return 0; } -s32 VFiPFFAT_FindClusterLinkPage(PF_FFD* p_ffd, unsigned int chain_index, u32* p_cluster, u32* is_found, PF_CACHE_PAGE* p_page) { +s32 VFiPFFAT_FindClusterLinkPage(PF_FFD* p_ffd, u32 chain_index, u32* p_cluster, u32* is_found, PF_CACHE_PAGE* p_page) { int result; - unsigned int position; + u32 position; u32 current_cluster; - unsigned int i; + u32 i; PF_CACHE_PAGE* v12; u32 next_cluster; @@ -259,8 +296,7 @@ static s32 VFiPFFAT_WriteFATEntry(PF_VOLUME* p_vol, u32 cluster, u32 value) { } } -s32 VFiPFFAT_ReadClusterPage(PF_FFD* p_ffd, unsigned int cluster, unsigned int chain_index, u32* next_cluster, u32* chk_clstlnk, - PF_CACHE_PAGE** p_page) { +s32 VFiPFFAT_ReadClusterPage(PF_FFD* p_ffd, u32 cluster, u32 chain_index, u32* next_cluster, u32* chk_clstlnk, PF_CACHE_PAGE** p_page) { int err; *next_cluster = -1; @@ -287,7 +323,7 @@ s32 VFiPFFAT_ReadClusterPage(PF_FFD* p_ffd, unsigned int cluster, unsigned int c } s32 VFiPFFAT_ClearClusterLink(PF_FFD* p_ffd, u32 chain_index) { - unsigned int v2; + u32 v2; v2 = chain_index / (p_ffd->cluster_link.interval + 1); if (p_ffd->cluster_link.max_count >= v2) { @@ -302,10 +338,10 @@ s32 VFiPFFAT_ClearClusterLink(PF_FFD* p_ffd, u32 chain_index) { return 0; } -s32 VFiPFFAT_WriteCluster(PF_FFD* p_ffd, unsigned int cluster, unsigned int chain_index, unsigned int next_cluster, unsigned int use_clstlnk) { +s32 VFiPFFAT_WriteCluster(PF_FFD* p_ffd, u32 cluster, u32 chain_index, u32 next_cluster, u32 use_clstlnk) { int err; - unsigned int v10; - unsigned int access_cluster; + u32 v10; + u32 access_cluster; v10 = use_clstlnk; err = VFiPFFAT_WriteFATEntry(p_ffd->p_vol, cluster, next_cluster); @@ -329,3 +365,1037 @@ s32 VFiPFFAT_WriteCluster(PF_FFD* p_ffd, unsigned int cluster, unsigned int chai } return err; } + +s32 VFiPFFAT_WriteClusterPage(PF_FFD* p_ffd, u32 cluster, u32 chain_index, u32 next_cluster, u32 use_clstlnk, PF_CACHE_PAGE** p_page) { + int err; + u32 v12; + u32 v13; + + v12 = use_clstlnk; + err = VFiPFFAT_WriteFATEntryPage(p_ffd->p_vol, cluster, next_cluster, p_page); + if (!err) { + if (!p_ffd->cluster_link.buffer || !v12) + return 0; + if (!next_cluster) { + VFiPFFAT_ClearClusterLink(p_ffd, chain_index); + return 0; + } + if (cluster == fat_special_values[p_ffd->p_vol->bpb.fat_type].eoc2) + return 0; + err = VFiPFFAT_FindClusterLinkPage(p_ffd, chain_index, &v13, &v12, *p_page); + if (!err) { + if (v12) + return 0; + err = VFiPFFAT_UpdateClusterLink(p_ffd, cluster, chain_index); + if (!err) + return 0; + } + } + return err; +} +s32 VFiPFFAT_DoAllocateChain(PF_FFD* p_ffd, u32 chain_len, u32 chain_index, u32* p_chain_start, u32* p_last_allocated) { + PF_VOLUME* p_vol; + int result; + u32 i; + PF_CACHE_PAGE* v12; + u32 last_allocated_cluster; + u32 first_allocated_cluster; + u32 fat_type; + u32 eoc2; + + p_vol = p_ffd->p_vol; + fat_type = p_vol->bpb.fat_type; + eoc2 = fat_special_values[fat_type].eoc2; + *p_chain_start = -1; + *p_last_allocated = -1; + last_allocated_cluster = -1; + result = + VFiPFFAT_SearchForNumFreeClusters(p_vol, p_vol->last_free_cluster, 0xFFFFFFFF, chain_len, &first_allocated_cluster, &last_allocated_cluster); + if (!result) { + if (first_allocated_cluster == -1) + return 0; + result = VFiPFFAT_ReadFATSector(p_vol, &v12, first_allocated_cluster); + if (!result) { + v12->option = 0; + for (i = first_allocated_cluster; i < last_allocated_cluster; ++i) { + result = VFiPFFAT_WriteClusterPage(p_ffd, i, chain_index, i + 1, 1u, &v12); + if (result) + return result; + if ((p_vol->fsi_flag & 4) != 0 && p_vol->num_free_clusters != -1 && p_vol->num_free_clusters && + (p_vol->bpb.fat_type != FAT_32 || last_allocated_cluster != p_vol->bpb.root_dir_cluster)) { + --p_vol->num_free_clusters; + } + if (*p_chain_start == -1) + *p_chain_start = i; + *p_last_allocated = i; + ++chain_index; + } + if (last_allocated_cluster != -1) { + result = VFiPFFAT_WriteClusterPage(p_ffd, last_allocated_cluster, chain_index, eoc2, 1u, &v12); + if (result) + return result; + if (*p_chain_start == -1) + *p_chain_start = i; + *p_last_allocated = i; + if (p_vol->num_free_clusters != -1 && p_vol->num_free_clusters && + (p_vol->bpb.fat_type != FAT_32 || last_allocated_cluster != p_vol->bpb.root_dir_cluster)) { + --p_vol->num_free_clusters; + } + } + p_vol->last_free_cluster = last_allocated_cluster + 1; + p_ffd->last_cluster.num_last_cluster = last_allocated_cluster; + p_ffd->last_cluster.max_chain_index = chain_index; + *p_last_allocated = last_allocated_cluster; + result = VFiPFFAT_UpdateFATEntry(p_vol, v12); + if (!result) { + if (p_vol->bpb.fat_type == FAT_32 && (p_vol->fsi_flag & 2) != 0) { + if (VFiPFFAT_RefreshFSINFO(p_vol)) { + p_vol->num_free_clusters = -1; + p_vol->fsi_flag &= ~4u; + } + } + return 0; + } + } + } + return result; +} + +static s32 VFiPFFAT_AllocateChain(PF_FFD* p_ffd, u32 chain_len, u32 chain_index, u32* p_chain_start, u32* p_last_allocated) { + int err; + + err = VFiPFFAT_DoAllocateChain(p_ffd, chain_len, chain_index, p_chain_start, p_last_allocated); + if (!err) + return 0; + if (*p_chain_start != -1) + VFiPFFAT_FreeChain(p_ffd, *p_chain_start, chain_index, -1); + *p_chain_start = -1; + *p_last_allocated = -1; + return err; +} + +int VFiPFFAT_GetClusterInChain(PF_FFD* p_ffd, u32 chain_index, u32 mode, u32 num_cluster, u32* locate_start, u32* locate_end) { + u32* p_chain_start; + u32 trace_cnt; + u32 search_index; + u32 current_cluster; + int result; + int err; + int v16; + PF_CACHE_PAGE* p_page; + u32 check_use; + u32 chain_start; + u32 append_cnt; + u32 next_cluster; + u32 eoc1; + u32 bad; + + p_page = 0; + bad = fat_special_values[p_ffd->p_vol->bpb.fat_type].bad; + eoc1 = fat_special_values[p_ffd->p_vol->bpb.fat_type].eoc1; + *locate_end = -1; + *locate_start = -1; + if (p_ffd->p_hint->chain_index && p_ffd->p_hint->chain_index <= chain_index) { + chain_start = p_ffd->p_hint->cluster; + p_chain_start = &chain_start; + trace_cnt = chain_index - p_ffd->p_hint->chain_index; + search_index = p_ffd->p_hint->chain_index + 1; + } else { + p_chain_start = p_ffd->p_start_cluster; + trace_cnt = chain_index; + search_index = 1; + } + if (p_ffd->last_access.chain_index && p_ffd->last_access.chain_index <= chain_index && p_ffd->last_access.chain_index > search_index - 1) { + chain_start = p_ffd->last_access.cluster; + p_chain_start = &chain_start; + trace_cnt = chain_index - p_ffd->last_access.chain_index; + search_index = p_ffd->last_access.chain_index + 1; + } + current_cluster = *p_chain_start; + next_cluster = *p_chain_start; + if (mode == 2) { + if (trace_cnt && num_cluster) + trace_cnt = num_cluster + trace_cnt - 1; + else + trace_cnt = num_cluster; + append_cnt = trace_cnt; + if (p_ffd->last_cluster.num_last_cluster) { + trace_cnt = 0; + append_cnt = p_ffd->last_cluster.max_chain_index + num_cluster - chain_index; + current_cluster = p_ffd->last_cluster.num_last_cluster; + next_cluster = fat_special_values[p_ffd->p_vol->bpb.fat_type].eoc2; + search_index = p_ffd->last_cluster.max_chain_index + 1; + } + } else { + if (mode == 1 && !current_cluster) + ++trace_cnt; + append_cnt = trace_cnt; + } + if (trace_cnt) { + result = VFiPFFAT_ReadFATSector(p_ffd->p_vol, &p_page, current_cluster); + if (result) + return result; + p_page->option = 0; + check_use = 1; + while (1) { + v16 = trace_cnt-- == 0; + if (v16 || current_cluster >= bad) + break; + if (current_cluster) { + err = VFiPFFAT_ReadClusterPage(p_ffd, current_cluster, search_index, &next_cluster, &check_use, &p_page); + if (err && next_cluster != -1) + return err; + } else { + next_cluster = fat_special_values[p_ffd->p_vol->bpb.fat_type].eoc2; + --search_index; + } + if ((next_cluster < 2 || next_cluster >= p_ffd->p_vol->bpb.num_clusters + 2) && next_cluster < eoc1) + return 14; + if (mode && next_cluster >= eoc1) + break; + current_cluster = next_cluster; + ++search_index; + } + append_cnt = trace_cnt; + } + if (mode && next_cluster >= eoc1) { + *locate_start = 0; + result = VFiPFFAT_AllocateChain(p_ffd, ++append_cnt, search_index, locate_start, &next_cluster); + if (result) + return result; + if (next_cluster == -1) + return 6; + if (*p_chain_start) { + result = VFiPFFAT_WriteCluster(p_ffd, current_cluster, search_index - 1, *locate_start, 1u); + if (result) + return result; + } else { + *p_chain_start = *locate_start; + } + current_cluster = next_cluster; + } + *locate_end = current_cluster; + return 0; +} + +s32 VFiPFFAT_GetClusterContinuousSectorInChain(PF_FFD* p_ffd, u32 initial_cluster, u32 chain_index, u32 size, u32* p_num_sector) { + PF_VOLUME* p_vol; + u32 cluster; + int err; + u32 next_cluster; + u32 check_use; + PF_CACHE_PAGE* p_page; + + p_vol = p_ffd->p_vol; + next_cluster = -1; + cluster = initial_cluster; + check_use = 1; + err = VFiPFFAT_ReadFATSector(p_vol, &p_page, initial_cluster); + if (err) { + return err; + } + + while (next_cluster) { + err = VFiPFFAT_ReadClusterPage(p_ffd, cluster, chain_index, &next_cluster, &check_use, &p_page); + if (err) + return err; + if (cluster + 1 != next_cluster) { + if (next_cluster == fat_special_values[p_vol->bpb.fat_type].eoc2) { + p_ffd->last_cluster.num_last_cluster = cluster; + p_ffd->last_cluster.max_chain_index = chain_index - 1; + } + break; + } + ++p_ffd->p_hint->chain_index; + p_ffd->p_hint->cluster = next_cluster; + *p_num_sector += p_vol->bpb.sectors_per_cluster; + if (*p_num_sector << p_vol->bpb.log2_bytes_per_sector >= size) + break; + cluster = next_cluster; + ++chain_index; + } + return 0; +} + +s32 VFiPFFAT_GetClusterAllocatedInChain(PF_FFD* p_ffd, u32 initial_cluster, u32 chain_index, u32 size, u32* p_num_clusters) { + PF_VOLUME* p_vol; + u32 cluster; + u32 v10; + int err; + u32 next_cluster; + u32 check_use; + + PF_CACHE_PAGE* p_page; + + p_vol = p_ffd->p_vol; + next_cluster = -1; + cluster = initial_cluster; + check_use = 1; + v10 = 0; + err = VFiPFFAT_ReadFATSector(p_vol, &p_page, initial_cluster); + if (err) { + return err; + } + + while (next_cluster) { + v10 += p_vol->bpb.bytes_per_sector << p_vol->bpb.log2_sectors_per_cluster; + ++*p_num_clusters; + if (v10 >= size) + break; + err = VFiPFFAT_ReadClusterPage(p_ffd, cluster, chain_index, &next_cluster, &check_use, &p_page); + if (err) + return err; + if (next_cluster == fat_special_values[p_vol->bpb.fat_type].eoc2) { + p_ffd->last_cluster.num_last_cluster = cluster; + p_ffd->last_cluster.max_chain_index = chain_index - 1; + break; + } + cluster = next_cluster; + ++chain_index; + } + + return 0; +} + +s32 VFiPFFAT_GetClusterSpecified(PF_FFD* p_ffd, u32 chain_index, u32 may_allocate, u32* p_cluster) { + PF_VOLUME* p_vol; + PF_FAT_HINT* p_hint; + s32 err; + u32 is_found; + + p_vol = p_ffd->p_vol; + p_hint = p_ffd->p_hint; + + if (!*p_ffd->p_start_cluster && !may_allocate) { + *p_cluster = -1; + return 0; + } + + if (*p_ffd->p_start_cluster == 1) { + if (p_vol->bpb.fat_type <= FAT_16) { + *p_cluster = -1; + return 0; + } + *p_ffd->p_start_cluster = p_vol->bpb.root_dir_cluster; + } + + if (p_ffd->cluster_link.buffer && !may_allocate) { + err = VFiPFFAT_FindClusterLink(p_ffd, chain_index, p_cluster, &is_found); + if (err) + return err; + + if (is_found) { + p_hint->chain_index = chain_index; + p_hint->cluster = *p_cluster; + return 0; + } + } + + err = VFiPFFAT_GetNumberOfCluster(p_ffd, chain_index, may_allocate, p_cluster); + if (!err && *p_cluster != -1) { + p_hint->chain_index = chain_index; + p_hint->cluster = *p_cluster; + } + + return err; +} + +s32 VFiPFFAT_GetNumberOfCluster(PF_FFD* p_ffd, u32 chain_index, u32 may_allocate, u32* p_cluster) { + int err; + u32 locate_start; + u32 locate_end; + + *p_cluster = -1; + err = VFiPFFAT_GetClusterInChain(p_ffd, chain_index, may_allocate != 0, 0, &locate_start, &locate_end); + if (err) { + return err; + } + + if (locate_end >= 2 && locate_end < p_ffd->p_vol->bpb.num_clusters + 2) { + *p_cluster = locate_end; + } + + return 0; +} + +static s32 VFiPFFAT_GetNumberOfAllocatedCluster(PF_FFD* p_ffd, u32 chain_index, u32 num_cluster, u32* p_cluster, u32* p_num_cluster) { + int err; + u32 locate_start; + u32 locate_end; + + *p_cluster = -1; + err = VFiPFFAT_GetClusterInChain(p_ffd, chain_index, 2u, num_cluster, &locate_start, &locate_end); + if (err) { + return err; + } + + *p_num_cluster = locate_end - locate_start + 1; + if (locate_start >= 2 && locate_start < p_ffd->p_vol->bpb.num_clusters + 2) { + *p_cluster = locate_start; + } + + return 0; +} + +static s32 VFiPFFAT_GetClusterAllocated(PF_FFD* p_ffd, u32 chain_index, u32 num_cluster, u32* p_cluster, u32* p_num_cluster) { + PF_VOLUME* p_vol; + PF_FAT_HINT* p_hint; + int err; + + p_vol = p_ffd->p_vol; + p_hint = p_ffd->p_hint; + if (*p_ffd->p_start_cluster == 1) { + if (p_vol->bpb.fat_type <= FAT_16) { + *p_cluster = -1; + return 0; + } + *p_ffd->p_start_cluster = p_vol->bpb.root_dir_cluster; + } + err = VFiPFFAT_GetNumberOfAllocatedCluster(p_ffd, chain_index, num_cluster, p_cluster, p_num_cluster); + if (err) { + return err; + } + + if (*p_cluster != -1) { + p_hint->chain_index = chain_index; + p_hint->cluster = *p_cluster; + } + return 0; +} + +static s32 VFiPFFAT_GetSectorInRootDirRegion(PF_VOLUME* p_vol, u32 sector_offset, u32* p_sector) { + if (p_vol->bpb.fat_type >= FAT_32) + return 12; + if (sector_offset < p_vol->bpb.num_root_dir_sectors) + *p_sector = p_vol->bpb.first_root_dir_sector + sector_offset; + else + *p_sector = -1; + return 0; +} + +s32 VFiPFFAT_GetSector(PF_FFD* p_ffd, u32 file_sector_index, u32 mode, u32 size, u32* p_sector, u32* p_num_sector) { + PF_VOLUME* p_vol; + int err; + int v11; + u32 v12; + u32 v13; + int v14; + u32 num_divide; + u32 cluster; + u32 chain_index; + u32 fat_type; + + v12 = 0; + p_vol = p_ffd->p_vol; + fat_type = p_vol->bpb.fat_type; + if (*p_ffd->p_start_cluster == 1 && fat_type <= 1) { + err = VFiPFFAT_GetSectorInRootDirRegion(p_vol, file_sector_index, p_sector); + if (!err) + return 0; + } else { + chain_index = file_sector_index >> p_vol->bpb.log2_sectors_per_cluster; + if (mode == 2) { + num_divide = size >> p_vol->bpb.log2_bytes_per_sector; + v11 = (size & (p_vol->bpb.bytes_per_sector - 1)) != 0; + v14 = v11; + v13 = (num_divide + v11) >> p_vol->bpb.log2_sectors_per_cluster; + v13 += ((p_vol->bpb.sectors_per_cluster - 1) & (num_divide + v11)) != 0; + err = VFiPFFAT_GetClusterAllocated(p_ffd, chain_index, v13, &cluster, &v12); + if (err) + return err; + *p_num_sector = v12 << p_vol->bpb.log2_sectors_per_cluster; + } else { + err = VFiPFFAT_GetClusterSpecified(p_ffd, chain_index, mode, &cluster); + if (err) + return err; + *p_num_sector = 1 << p_vol->bpb.log2_sectors_per_cluster; + } + if (cluster == -1) + *p_sector = -1; + else + *p_sector = (file_sector_index & (p_vol->bpb.sectors_per_cluster - 1)) + p_vol->bpb.first_data_sector + + ((cluster - 2) << p_vol->bpb.log2_sectors_per_cluster); + return 0; + } + return err; +} + +s32 VFiPFFAT_UpdateFATEntry(PF_VOLUME* p_vol, PF_CACHE_PAGE* p_page) { + int err; + + err = 0; + if ((p_page->stat & 2) == 2) { + err = VFiPFCACHE_WriteFATPage(p_vol, p_page); + } + + return err; +} + +s32 VFiPFFAT_UpdateAlternateFATEntry(PF_VOLUME* p_vol, u8* p_buf, u32 sector, u32 size) { + u32 offset; + int err; + int err2; + u32 num_success; + u32 fat_num; + u32 fat_no; + + err = 0; + offset = sector - p_vol->bpb.num_reserved_sectors; + if (offset / p_vol->bpb.sectors_per_FAT) { + fat_no = offset % p_vol->bpb.sectors_per_FAT; + fat_num = 0; + } else { + fat_no = sector + p_vol->bpb.sectors_per_FAT; + fat_num = 1; + } + while (fat_num < p_vol->bpb.num_active_FATs) { + err2 = VFiPFDRV_lwrite(p_vol, p_buf, fat_no, size, &num_success); + if (err2 && !err) { + err = err2; + } + if (num_success != size) { + err = 17; + } + ++fat_num; + fat_no += p_vol->bpb.sectors_per_FAT; + } + return err; +} + +s32 VFiPFFAT_GetSectorSpecified(PF_FFD* p_ffd, u32 file_sector_index, u32 may_allocate, u32* p_sector) { + int err; + u32 num_sector; + + if (!p_ffd) + return 10; + if (!p_ffd->p_hint) + return 10; + if (p_ffd->p_vol->drv_char < 65 || p_ffd->p_vol->drv_char > 90) + return 35; + if (file_sector_index >= (0xFFFFFFFF >> p_ffd->p_vol->bpb.log2_bytes_per_sector) + 1) + return 37; + + err = VFiPFFAT_GetSector(p_ffd, file_sector_index, may_allocate != 0, 0, p_sector, &num_sector); + if (err) { + return err; + } + + return 0; +} + +s32 VFiPFFAT_GetSectorAllocated(PF_FFD* p_ffd, u32 file_sector_index, u32 size, u32* p_sector, u32* p_num_sector) { + int err; + + if (!p_ffd) + return 10; + if (!p_ffd->p_hint) + return 10; + if (p_ffd->p_vol->drv_char < 65 || p_ffd->p_vol->drv_char > 90) + return 35; + if (file_sector_index >= (0xFFFFFFFF >> p_ffd->p_vol->bpb.log2_bytes_per_sector) + 1) + return 37; + err = VFiPFFAT_GetSector(p_ffd, file_sector_index, 2u, size, p_sector, p_num_sector); + if (!err) + return 0; + return err; +} + +s32 VFiPFFAT_GetContinuousSector(PF_FFD* p_ffd, u32 file_sector_index, u32 size, u32* p_sector, u32* p_num_sector) { + u32 cluster; + s32 err; + PF_VOLUME* p_vol; + + cluster = -1; + if (!p_ffd) + return 10; + if (!p_ffd->p_hint) + return 10; + if (p_ffd->p_vol->drv_char < 65 || p_ffd->p_vol->drv_char > 90) + return 35; + if (file_sector_index >= (0xFFFFFFFF >> p_ffd->p_vol->bpb.log2_bytes_per_sector) + 1) + return 37; + p_vol = p_ffd->p_vol; + if (*p_sector == -1) { + err = VFiPFFAT_GetSectorSpecified(p_ffd, file_sector_index, 0, p_sector); + if (err) + goto error; + if (*p_sector != -1) + cluster = ((*p_sector - p_vol->bpb.first_data_sector) >> p_vol->bpb.log2_sectors_per_cluster) + 2; + } else { + cluster = ((*p_sector - p_vol->bpb.first_data_sector) >> p_vol->bpb.log2_sectors_per_cluster) + 2; + } + if (*p_sector == -1) + *p_num_sector = 0; + else + *p_num_sector = p_vol->bpb.first_data_sector + ((cluster - 1) << p_vol->bpb.log2_sectors_per_cluster) - *p_sector; + if (*p_sector == -1) + return 0; + if (*p_num_sector << p_vol->bpb.log2_bytes_per_sector >= size) + return 0; + err = VFiPFFAT_GetClusterContinuousSectorInChain(p_ffd, cluster, (file_sector_index >> p_vol->bpb.log2_sectors_per_cluster) + 1, size, + p_num_sector); + if (!err) + return 0; + +error: + return err; +} + +s32 VFiPFFAT_CountAllocatedClusters(PF_FFD* p_ffd, u32 size, u32* p_num_alloc_clusters) { + u32 total_size; + int err; + u32 cluster; + u32 chain_index; + + total_size = size; + *p_num_alloc_clusters = 0; + if (!p_ffd) + return 10; + if (!p_ffd->p_hint) + return 10; + if (p_ffd->p_vol->drv_char < 65 || p_ffd->p_vol->drv_char > 90) + return 35; + if (*p_ffd->p_start_cluster < 2) + return 0; + if (p_ffd->last_cluster.num_last_cluster) { + *p_num_alloc_clusters = p_ffd->last_cluster.max_chain_index + 1; + return 0; + } + if (p_ffd->p_hint->cluster) { + if (size <= (p_ffd->p_hint->chain_index + 1) << (p_ffd->p_vol->bpb.log2_bytes_per_sector + p_ffd->p_vol->bpb.log2_sectors_per_cluster)) { + *p_num_alloc_clusters = p_ffd->p_hint->chain_index + 1; + return 0; + } + *p_num_alloc_clusters = p_ffd->p_hint->chain_index; + cluster = p_ffd->p_hint->cluster; + chain_index = p_ffd->p_hint->chain_index + 1; + total_size = size - (p_ffd->p_hint->chain_index << (p_ffd->p_vol->bpb.log2_bytes_per_sector + p_ffd->p_vol->bpb.log2_sectors_per_cluster)); + } else { + cluster = *p_ffd->p_start_cluster; + chain_index = 1; + } + err = VFiPFFAT_GetClusterAllocatedInChain(p_ffd, cluster, chain_index, total_size, p_num_alloc_clusters); + if (err) { + return err; + } + return 0; +} + +int VFiPFFAT_CountFreeClusters(PF_VOLUME* p_vol, u32* p_num_free_clusters) { + int err; + u32 free_cluster; + PF_CACHE_PAGE* p_page; + u32 next_cluster; + + if (!p_vol) + return 10; + if (p_vol->bpb.fat_type > FAT_32) + return 15; + if ((p_vol->fsi_flag & 4) != 0 && p_vol->num_free_clusters != -1) { + *p_num_free_clusters = p_vol->num_free_clusters; + return 0; + } + *p_num_free_clusters = -1; + free_cluster = 2; + if ((p_vol->fsi_flag & 1) != 0 && p_vol->bpb.fat_type == FAT_32) { + err = VFiPFDRV_GetFSINFOInformation(p_vol); + if (err) + return err; + *p_num_free_clusters = p_vol->num_free_clusters; + } + if (*p_num_free_clusters == -1) { + err = VFiPFFAT_ReadFATSector(p_vol, &p_page, 2u); + if (err) + return err; + p_page->option = 0; + *p_num_free_clusters = 0; + while (free_cluster >= 2 && free_cluster < p_vol->bpb.num_clusters + 2) { + err = VFiPFFAT_ReadFATEntryPage(p_vol, free_cluster, &next_cluster, &p_page); + if (err) + return err; + if (!next_cluster) + ++*p_num_free_clusters; + ++free_cluster; + } + p_vol->num_free_clusters = *p_num_free_clusters; + if (p_vol->bpb.fat_type == FAT_32 && (p_vol->fsi_flag & 2) != 0) { + if (VFiPFFAT_RefreshFSINFO(p_vol)) { + p_vol->num_free_clusters = -1; + p_vol->fsi_flag &= ~4u; + } + } + } + p_vol->fsi_flag |= 4u; + return 0; +} + +s32 VFiPFFAT_RefreshFSINFO(PF_VOLUME* p_vol) { + int err; + + err = 0; + if (p_vol->bpb.fat_type != FAT_32) + return 12; + if ((p_vol->fsi_flag & 2) == 0) + return 36; + if ((p_vol->fsi_flag & 4) != 0) + return VFiPFDRV_StoreFreeCountToFSINFO(p_vol); + return err; +} + +s32 VFiPFFAT_FreeChain(PF_FFD* p_ffd, u32 start_cluster, u32 chain_index, u32 size) { + u32 v5; + PF_VOLUME* p_vol; + int err; + int v10; + int save_num_clusters; + u32 save_start_cluster; + u32 sector; + PF_CACHE_PAGE* p_page; + u32 clst_size; + u32 file_size; + u32 next_cluster; + u32 eoc1; + + v5 = start_cluster; + p_vol = p_ffd->p_vol; + if (!p_vol) + return 10; + if ((start_cluster < 2 || start_cluster >= p_vol->bpb.num_clusters + 2) && start_cluster) + return 14; + if (!start_cluster) + return 0; + eoc1 = fat_special_values[p_vol->bpb.fat_type].eoc1; + if (!size) + return 0; + file_size = size; + clst_size = p_vol->bpb.bytes_per_sector << p_vol->bpb.log2_sectors_per_cluster; + err = VFiPFFAT_ReadFATSector(p_vol, &p_page, start_cluster); + if (!err) { + p_page->option = 1; + next_cluster = v5; + save_start_cluster = v5; + save_num_clusters = 1; + while (v5 < eoc1 && (!size || file_size)) { + sector = p_page->sector; + err = VFiPFFAT_ReadFATEntryPage(p_vol, v5, &next_cluster, &p_page); + if (err) + return err; + if (!next_cluster) { + err = VFiPFFAT_UpdateFATEntry(p_vol, p_page); + if (!err) + return 0; + return err; + } + if (sector != p_page->sector) { + err = VFiPFFAT_ReadFATSector(p_vol, &p_page, v5); + if (err) + return err; + } + if (chain_index == -1) + v10 = VFiPFFAT_WriteFATEntryPage(p_vol, v5, 0, &p_page); + else + v10 = VFiPFFAT_WriteClusterPage(p_ffd, v5, chain_index++, 0, 1u, &p_page); + if (v10) + return v10; + if ((p_vol->flags & 0x40) != 0) { + if (next_cluster == v5 + 1) { + ++save_num_clusters; + } else { + err = VFiPFDRV_lerase(p_vol, p_vol->bpb.first_data_sector + ((save_start_cluster - 2) << p_vol->bpb.log2_sectors_per_cluster), + save_num_clusters << p_vol->bpb.log2_sectors_per_cluster); + if (err) + return err; + save_start_cluster = next_cluster; + save_num_clusters = 1; + } + } + if (size && file_size) { + if (file_size > clst_size) + file_size -= clst_size; + else + file_size = 0; + } + if (p_vol->num_free_clusters != -1) + ++p_vol->num_free_clusters; + v5 = next_cluster; + } + err = VFiPFFAT_UpdateFATEntry(p_vol, p_page); + if (!err) { + if (p_vol->bpb.fat_type == FAT_32 && (p_vol->fsi_flag & 2) != 0) { + if (VFiPFFAT_RefreshFSINFO(p_vol)) { + p_vol->num_free_clusters = -1; + p_vol->fsi_flag &= ~4u; + } + } + return 0; + } + } + return err; +} + +s32 VFiPFFAT_GetBeforeChain(struct PF_VOLUME* p_vol, u32 start_cluster, u32 lActive, u32* p_cluster) { + u32 v5; + int err; + u32 eoc1; + PF_CACHE_PAGE* p_page; + u32 next_cluster; + + v5 = start_cluster; + if (p_vol) { + if (start_cluster >= 2 && start_cluster < p_vol->bpb.num_clusters + 2) { + eoc1 = fat_special_values[p_vol->bpb.fat_type].eoc1; + *p_cluster = -1; + err = VFiPFFAT_ReadFATSector(p_vol, &p_page, start_cluster); + if (!err) { + p_page->option = 0; + while (v5 < eoc1) { + err = VFiPFFAT_ReadFATEntryPage(p_vol, v5, &next_cluster, &p_page); + if (err) + return err; + if (lActive == next_cluster) { + *p_cluster = v5; + return 0; + } + if ((--v5 < 2 || v5 >= p_vol->bpb.num_clusters + 2) && v5 < eoc1) { + *p_cluster = lActive; + return 0; + } + } + return 13; + } + } else { + *p_cluster = -1; + return 10; + } + } else { + *p_cluster = -1; + return 10; + } + return err; +} + +s32 VFiPFFAT_GetBeforeSector(u32* p_befor_sector, PF_VOLUME* p_vol, u32 current_sector) { + u32 v5; + int err; + u32 next_cluster; + + v5 = current_sector; + err = 0; + if (!p_befor_sector || !p_vol) + return 10; + if (current_sector < p_vol->bpb.first_root_dir_sector) + return 10; + if (p_vol->bpb.fat_type == FAT_32 || current_sector >= p_vol->bpb.first_data_sector) { + if (((p_vol->bpb.sectors_per_cluster - 1) & (current_sector - p_vol->bpb.first_data_sector)) != 0) { + v5 = current_sector - 1; + } else { + err = + VFiPFFAT_GetBeforeChain(p_vol, ((current_sector - p_vol->bpb.first_data_sector) >> p_vol->bpb.log2_sectors_per_cluster) + 2, + ((current_sector - p_vol->bpb.first_data_sector) >> p_vol->bpb.log2_sectors_per_cluster) + 2, &next_cluster); + if (!err) { + if (next_cluster == -1) + v5 = -1; + else + v5 = ((next_cluster - 2) << p_vol->bpb.log2_sectors_per_cluster) + p_vol->bpb.sectors_per_cluster + p_vol->bpb.first_data_sector - + 1; + } + } + } else { + v5 = current_sector - 1; + if (current_sector - 1 < p_vol->bpb.first_root_dir_sector) + err = 34; + } + if (err) + *p_befor_sector = -1; + else + *p_befor_sector = v5; + return err; +} + +s32 VFiPFFAT_InitFATRegion(PF_VOLUME* p_vol) { + int err; + u32 num_cache_buff; + u32 size; + u32 root_dir_sector; + u32 sector; + u32 success_size; + PF_CACHE_PAGE* p_page; + + if (!p_vol) + return 10; + if (p_vol->bpb.fat_type > FAT_32) + return 15; + err = VFiPFCACHE_AllocateDataPage(p_vol, 0xFFFFFFFF, &p_page); + if (!err) { + num_cache_buff = p_vol->cache.data_buff_size; + size = num_cache_buff << p_vol->bpb.log2_bytes_per_sector; + root_dir_sector = p_vol->bpb.first_root_dir_sector; + VFipf_memset(p_page->buffer, 0, size); + for (sector = p_vol->bpb.num_reserved_sectors; sector < root_dir_sector; sector += num_cache_buff) { + if (sector + num_cache_buff > root_dir_sector) { + num_cache_buff = root_dir_sector - sector; + size = (root_dir_sector - sector) << p_vol->bpb.log2_bytes_per_sector; + } + if (VFiPFSEC_WriteDataSector(p_vol, p_page->buffer, sector, size, &success_size, 1u, 0)) { + sector = root_dir_sector; + } else if (success_size != size) { + sector = root_dir_sector; + } + } + VFiPFCACHE_FreeDataPage(p_vol, p_page); + err = VFiPFFAT_WriteFATEntry(p_vol, 0, p_vol->bpb.media | fat_special_values[p_vol->bpb.fat_type].fat0_mask); + if (!err) { + err = VFiPFFAT_WriteFATEntry(p_vol, 1u, fat_special_values[p_vol->bpb.fat_type].fat0_mask); + if (!err) { + err = VFiPFCACHE_FlushFATCache(p_vol); + if (!err) + return 0; + } + } + } + return err; +} + +s32 VFiPFFAT_MakeRootDir(PF_VOLUME* p_vol) { + int err; + + err = VFiPFFAT_WriteFATEntry(p_vol, p_vol->bpb.root_dir_cluster, fat_special_values[p_vol->bpb.fat_type].eoc2); + if (!err) { + err = VFiPFCACHE_FlushFATCache(p_vol); + if (!err) + return 0; + } + return err; +} + +s32 VFiPFFAT_TraceClustersChain(PF_FFD* p_ffd, u32 start_clst, u32 size, u32* p_target_clst, u32* p_next_clst) { + u32 v6; + int err; + PF_VOLUME* p_vol; + u32 clst_cnt; + u32 chain_index; + u32 cnt; + PF_CACHE_PAGE* p_page; + u32 check_use; + u32 clst_size; + u32 save_cluster; + u32 next_cluster; + + v6 = start_clst; + save_cluster = start_clst; + *p_target_clst = 0; + *p_next_clst = 0; + if (!p_ffd) + return 10; + if (!p_ffd->p_hint) + return 10; + if (p_ffd->p_vol->drv_char < 65 || p_ffd->p_vol->drv_char > 90) + return 35; + if (!p_ffd->p_vol) + return 10; + if (*p_ffd->p_start_cluster < 2) + return 0; + if (start_clst < 2) + return 0; + if (!size) + return 0; + p_vol = p_ffd->p_vol; + if (size == -1 && p_ffd->last_cluster.num_last_cluster) { + *p_target_clst = p_ffd->last_cluster.num_last_cluster; + *p_next_clst = fat_special_values[p_vol->bpb.fat_type].eoc2; + return 0; + } else { + clst_size = p_vol->bpb.bytes_per_sector << p_vol->bpb.log2_sectors_per_cluster; + clst_cnt = size / clst_size; + if (size % clst_size) + ++clst_cnt; + if (*p_ffd->p_start_cluster == start_clst) + chain_index = 1; + else + chain_index = p_ffd->p_hint->chain_index + 1; + next_cluster = -1; + check_use = 1; + err = VFiPFFAT_ReadFATSector(p_vol, &p_page, start_clst); + if (!err) { + for (cnt = 0; cnt < clst_cnt; ++cnt) { + err = VFiPFFAT_ReadClusterPage(p_ffd, v6, chain_index, &next_cluster, &check_use, &p_page); + if (err) + return err; + save_cluster = v6; + if (next_cluster == fat_special_values[p_vol->bpb.fat_type].eoc2) { + p_ffd->last_cluster.num_last_cluster = v6; + p_ffd->last_cluster.max_chain_index = chain_index - 1; + break; + } + v6 = next_cluster; + ++chain_index; + } + p_ffd->p_hint->chain_index = chain_index - 1; + *p_target_clst = save_cluster; + *p_next_clst = next_cluster; + return 0; + } + } + return err; +} + +s32 VFiPFFAT_ReadValueToSpecifiedCluster(PF_VOLUME* p_vol, u32 cluster, u32* value) { + int err; + + err = VFiPFFAT_ReadFATEntry(p_vol, cluster, value); + if (err) + return err; + + return 0; +} + +void VFiPFFAT_InitHint(PF_FAT_HINT* p_hint) { + p_hint->chain_index = 0; + p_hint->cluster = 0; +} + +void VFiPFFAT_SetHint(PF_FFD* p_ffd, PF_FAT_HINT* p_hint) { + p_ffd->p_hint = p_hint; +} + +s32 VFiPFFAT_ResetFFD(PF_FFD* p_ffd, u32* p_start_cluster) { + if (!p_ffd) + return 10; + if (!p_start_cluster) + return 10; + p_ffd->p_start_cluster = p_start_cluster; + if (p_ffd->p_hint) + VFiPFFAT_InitHint(p_ffd->p_hint); + p_ffd->last_access.cluster = 0; + p_ffd->last_access.chain_index = 0; + p_ffd->last_cluster.num_last_cluster = 0; + p_ffd->last_cluster.max_chain_index = 0; + p_ffd->cluster_link.buffer = 0; + return 0; +} + +s32 VFiPFFAT_InitFFD(PF_FFD* p_ffd, PF_FAT_HINT* p_hint, PF_VOLUME* p_vol, u32* p_start_cluster) { + if (!p_ffd) + return 10; + if (!p_start_cluster) + return 10; + p_ffd->p_hint = p_hint; + p_ffd->p_vol = p_vol; + VFiPFFAT_ResetFFD(p_ffd, p_start_cluster); + return 0; +} + +s32 VFiPFFAT_FinalizeFFD(PF_FFD* p_ffd) { + if (!p_ffd) + return 10; + p_ffd->cluster_link.buffer = 0; + return 0; +} + +void VFiPFFAT_SetLastAccess(PF_FFD* p_ffd, PF_FAT_HINT* last_access) { + p_ffd->last_access = *last_access; +} + +u32 VFiPFFAT_GetValueOfEOC2(PF_VOLUME* p_vol) { + return fat_special_values[p_vol->bpb.fat_type].eoc2; +}