b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | /* |
| 2 | * initfs.c |
| 3 | * |
| 4 | * TFFS_mount TFFS_mkfs implementation. |
| 5 | * implementation file. |
| 6 | * |
| 7 | * Copyright (C) knightray@gmail.com |
| 8 | * |
| 9 | * SPDX-License-Identifier: GPL-2.0+ |
| 10 | */ |
| 11 | #include "initfs.h" |
| 12 | #include "debug.h" |
| 13 | #include "tffs.h" |
| 14 | #include "hai.h" |
| 15 | #include "fat.h" |
| 16 | #include "dir.h" |
| 17 | |
| 18 | #ifndef DBG_INITFS |
| 19 | #undef DBG |
| 20 | #define DBG nulldbg |
| 21 | #endif |
| 22 | |
| 23 | int32 |
| 24 | TFFS_mount( |
| 25 | IN byte * dev, |
| 26 | OUT tffs_handle_t * phtffs) |
| 27 | { |
| 28 | int32 ret; |
| 29 | tffs_t * tffs; |
| 30 | boot_sector_t * pbs = NULL; |
| 31 | tdev_handle_t hdev; |
| 32 | tdir_t * proot_dir = NULL; |
| 33 | tdir_t * pcur_dir = NULL; |
| 34 | uint32 rootdir_clus; |
| 35 | tfat_t * pfat = NULL; |
| 36 | tcache_t * pcache = NULL; |
| 37 | |
| 38 | if (!dev || !phtffs) |
| 39 | return ERR_TFFS_INVALID_PARAM; |
| 40 | |
| 41 | ret = TFFS_OK; |
| 42 | tffs = (tffs_t *)Malloc(sizeof(tffs_t)); |
| 43 | Memset(tffs, 0, sizeof(tffs_t)); |
| 44 | pbs = (boot_sector_t *)Malloc(sizeof(boot_sector_t)); |
| 45 | Memset(pbs, 0, sizeof(boot_sector_t)); |
| 46 | |
| 47 | /* Marvell fixed: sizeof(boot_sector_t) is actualy 514 but only |
| 48 | due to sub-struct size alignment to 32-bit. |
| 49 | This only affects bs_sig offset, and it is unused |
| 50 | ASSERT(sizeof(boot_sector_t) == 512); |
| 51 | */ |
| 52 | |
| 53 | hdev = HAI_initdevice(dev, 512); |
| 54 | if (hdev == NULL) { |
| 55 | ret = ERR_TFFS_DEVICE_FAIL; |
| 56 | goto _release; |
| 57 | } |
| 58 | tffs->hdev = hdev; |
| 59 | |
| 60 | if (HAI_readsector(hdev, 0, (ubyte *)pbs) != HAI_OK) { |
| 61 | ret = ERR_TFFS_DEVICE_FAIL; |
| 62 | goto _release; |
| 63 | } |
| 64 | |
| 65 | if (!_validate_bs(pbs)) { |
| 66 | ret = ERR_TFFS_BAD_BOOTSECTOR; |
| 67 | goto _release; |
| 68 | } |
| 69 | |
| 70 | tffs->pbs = pbs; |
| 71 | |
| 72 | _parse_boot_sector(pbs, tffs); |
| 73 | DBG("tffs->fat_type:%d\n", tffs->fat_type); |
| 74 | DBG("tffs->sec_fat:%d\n", tffs->sec_fat); |
| 75 | DBG("tffs->sec_root_dir:%d\n", tffs->sec_root_dir); |
| 76 | DBG("tffs->sec_first_data:%d\n", tffs->sec_first_data); |
| 77 | |
| 78 | /* Marvell fixed */ |
| 79 | #ifdef TFFS_FAT_CACHE |
| 80 | if ((pcache = cache_init(hdev, TFFS_FAT_CACHE, tffs->pbs->byts_per_sec)) == NULL) { |
| 81 | WARN("TFFS: cache is disable.\n"); |
| 82 | pcache = cache_init(hdev, 0, tffs->pbs->byts_per_sec); |
| 83 | } |
| 84 | tffs->pfatcache = pcache; |
| 85 | #endif |
| 86 | if ((pfat = fat_init(tffs)) == NULL) { |
| 87 | ret = ERR_TFFS_BAD_FAT; |
| 88 | goto _release; |
| 89 | } |
| 90 | tffs->pfat = pfat; |
| 91 | |
| 92 | /* Marvell fixed: TFFS_FILE_CACHE instead of 32 hard-coded */ |
| 93 | if ((pcache = cache_init(hdev, TFFS_FILE_CACHE, tffs->pbs->byts_per_sec)) == NULL) { |
| 94 | WARN("TFFS: cache is disable.\n"); |
| 95 | pcache = cache_init(hdev, 0, tffs->pbs->byts_per_sec); |
| 96 | } |
| 97 | tffs->pcache = pcache; |
| 98 | |
| 99 | rootdir_clus = tffs->fat_type == FT_FAT32 ? tffs->pbs->bh32.root_clus : ROOT_DIR_CLUS_FAT16; |
| 100 | |
| 101 | if (dir_init_by_clus(tffs, rootdir_clus, &proot_dir) != DIR_OK || |
| 102 | dir_init_by_clus(tffs, rootdir_clus, &pcur_dir) != DIR_OK) { |
| 103 | ret = ERR_TFFS_DEVICE_FAIL; |
| 104 | goto _release; |
| 105 | } |
| 106 | |
| 107 | tffs->root_dir = proot_dir; |
| 108 | tffs->cur_dir = pcur_dir; |
| 109 | |
| 110 | *phtffs = (tffs_handle_t)tffs; |
| 111 | INFO("tiny fat file system mount OK.\n"); |
| 112 | |
| 113 | return ret; |
| 114 | |
| 115 | _release: |
| 116 | if (pfat) |
| 117 | fat_destroy(pfat); |
| 118 | if (proot_dir) |
| 119 | dir_destroy(proot_dir); |
| 120 | if (pcur_dir) |
| 121 | dir_destroy(pcur_dir); |
| 122 | if (HAI_closedevice(tffs->hdev) != HAI_OK) |
| 123 | ret = ERR_TFFS_DEVICE_FAIL; |
| 124 | Free(pbs); |
| 125 | Free(tffs); |
| 126 | |
| 127 | return ret; |
| 128 | } |
| 129 | |
| 130 | int32 |
| 131 | TFFS_fs_flush( |
| 132 | IN tffs_handle_t htffs) |
| 133 | { |
| 134 | tffs_t * ptffs; |
| 135 | int32 ret; |
| 136 | |
| 137 | if (!htffs) |
| 138 | return ERR_TFFS_INVALID_PARAM; |
| 139 | |
| 140 | ptffs = (tffs_t *)htffs; |
| 141 | ret = TFFS_OK; |
| 142 | |
| 143 | if (ptffs->pfat) |
| 144 | fat_flush(ptffs->pfat); |
| 145 | if (ptffs->pcache) |
| 146 | ret = cache_flush(ptffs->pcache); |
| 147 | #ifdef TFFS_FAT_CACHE |
| 148 | if (ptffs->pfatcache) |
| 149 | ret = cache_flush(ptffs->pfatcache); |
| 150 | #endif |
| 151 | return ret; |
| 152 | } |
| 153 | |
| 154 | int32 |
| 155 | TFFS_umount( |
| 156 | IN tffs_handle_t htffs) |
| 157 | { |
| 158 | tffs_t * ptffs; |
| 159 | int32 ret; |
| 160 | |
| 161 | if (!htffs) |
| 162 | return ERR_TFFS_INVALID_PARAM; |
| 163 | |
| 164 | ptffs = (tffs_t *)htffs; |
| 165 | ret = TFFS_OK; |
| 166 | |
| 167 | if (ptffs->pbs) |
| 168 | Free(ptffs->pbs); |
| 169 | |
| 170 | if (ptffs->pfat) |
| 171 | fat_destroy(ptffs->pfat); |
| 172 | |
| 173 | if (ptffs->root_dir) |
| 174 | dir_destroy(ptffs->root_dir); |
| 175 | |
| 176 | if (ptffs->cur_dir) |
| 177 | dir_destroy(ptffs->cur_dir); |
| 178 | |
| 179 | if (ptffs->pcache) |
| 180 | ret = cache_destroy(ptffs->pcache); |
| 181 | /* Marvell fixed */ |
| 182 | #ifdef TFFS_FAT_CACHE |
| 183 | if (ptffs->pfatcache) |
| 184 | ret = cache_destroy(ptffs->pfatcache); |
| 185 | #endif |
| 186 | if (ret > 0 && (HAI_closedevice(ptffs->hdev) != HAI_OK)) |
| 187 | ret = ERR_TFFS_DEVICE_FAIL; |
| 188 | |
| 189 | Free(ptffs); |
| 190 | |
| 191 | return ret; |
| 192 | } |
| 193 | |
| 194 | int32 |
| 195 | _validate_bs( |
| 196 | IN boot_sector_t * pbs) |
| 197 | { |
| 198 | INFO("=================Boot sector====================\n"); |
| 199 | INFO("oem_name: %s\n", pbs->oem_name); |
| 200 | INFO("byts_per_sec: %d\n", pbs->byts_per_sec); |
| 201 | INFO("resvd_sec_cnt: %d\n", pbs->resvd_sec_cnt); |
| 202 | INFO("sec_per_clus: %d\n", pbs->sec_per_clus); |
| 203 | INFO("num_fats: %d\n", pbs->num_fats); |
| 204 | INFO("================================================\n"); |
| 205 | /* Marvell fixed: check basic parameters are sane */ |
| 206 | if ((pbs->byts_per_sec == 0) || (pbs->sec_per_clus == 0) || |
| 207 | (pbs->num_fats < 1) || (pbs->num_fats > 2)) |
| 208 | return FALSE; |
| 209 | return TRUE; |
| 210 | } |
| 211 | |
| 212 | void |
| 213 | _parse_boot_sector( |
| 214 | IN boot_sector_t * pbs, |
| 215 | OUT tffs_t * tffs) |
| 216 | { |
| 217 | uint32 totsec; |
| 218 | uint32 count_of_clusters; |
| 219 | uint32 datasec; |
| 220 | |
| 221 | tffs->root_dir_sectors = ((pbs->root_ent_cnt * 32) + (pbs->byts_per_sec - 1)) / pbs->byts_per_sec; |
| 222 | |
| 223 | if (pbs->fatsz16 != 0) { |
| 224 | tffs->fatsz = pbs->fatsz16; |
| 225 | } |
| 226 | else { |
| 227 | tffs->fatsz = pbs->bh32.fatsz32; |
| 228 | } |
| 229 | |
| 230 | if (pbs->tot_sec16 != 0) { |
| 231 | totsec = pbs->tot_sec16; |
| 232 | } |
| 233 | else { |
| 234 | totsec = pbs->tot_sec32; |
| 235 | } |
| 236 | |
| 237 | datasec = totsec - (pbs->resvd_sec_cnt + (pbs->num_fats * tffs->fatsz) + tffs->root_dir_sectors); |
| 238 | count_of_clusters = datasec / pbs->sec_per_clus; |
| 239 | tffs->total_clusters = count_of_clusters; |
| 240 | |
| 241 | DBG("count_of_clusters = %d\n", count_of_clusters); |
| 242 | |
| 243 | //FIXME. I should find another to determine the fat type. |
| 244 | if (count_of_clusters < 4085) { |
| 245 | tffs->fat_type = FT_FAT12; |
| 246 | } |
| 247 | else if (count_of_clusters < 65525 && pbs->fatsz16 != 0){ |
| 248 | tffs->fat_type = FT_FAT16; |
| 249 | } |
| 250 | else { |
| 251 | tffs->fat_type = FT_FAT32; |
| 252 | } |
| 253 | |
| 254 | tffs->sec_fat = pbs->resvd_sec_cnt; |
| 255 | tffs->sec_root_dir = tffs->sec_fat + pbs->num_fats * tffs->fatsz; |
| 256 | tffs->sec_first_data = tffs->sec_root_dir + tffs->root_dir_sectors; |
| 257 | /* Marvell fixed */ |
| 258 | tffs->num_fats = pbs->num_fats; |
| 259 | } |
| 260 | |