| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* GATE PROJECT LICENSE: | ||
| 2 | +----------------------------------------------------------------------------+ | ||
| 3 | | Copyright(c) 2018-2025, Stefan Meislinger | | ||
| 4 | | All rights reserved. | | ||
| 5 | | | | ||
| 6 | | Redistribution and use in source and binary forms, with or without | | ||
| 7 | | modification, are permitted provided that the following conditions are met:| | ||
| 8 | | | | ||
| 9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
| 10 | | this list of conditions and the following disclaimer. | | ||
| 11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
| 12 | | notice, this list of conditions and the following disclaimer in the | | ||
| 13 | | documentation and/or other materials provided with the distribution. | | ||
| 14 | | | | ||
| 15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
| 16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
| 17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
| 18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
| 19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
| 20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
| 21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
| 22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
| 23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
| 24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
| 25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
| 26 | +----------------------------------------------------------------------------+ | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include "gate/tech/filesystems.h" | ||
| 30 | #include "gate/results.h" | ||
| 31 | |||
| 32 | ✗ | gate_result_t gate_filesystem_read_bootsector(gate_controlstream_t* blockstream, gate_filesystem_fat_bootsect_t* bootsect) | |
| 33 | { | ||
| 34 | gate_result_t ret; | ||
| 35 | char buffer[512]; | ||
| 36 | ✗ | gate_size_t received = 0; | |
| 37 | |||
| 38 | do | ||
| 39 | { | ||
| 40 | ✗ | ret = gate_stream_seek(blockstream, 0, GATE_STREAM_SEEK_BEGIN, NULL); | |
| 41 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
| 42 | |||
| 43 | ✗ | ret = gate_stream_read(blockstream, buffer, 512, &received); | |
| 44 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
| 45 | |||
| 46 | ✗ | gate_mem_copy(bootsect, &buffer[0], 512); | |
| 47 | } while (0); | ||
| 48 | |||
| 49 | ✗ | return ret; | |
| 50 | } | ||
| 51 | |||
| 52 | ✗ | static unsigned get_total_clusters(gate_filesystem_fat_bootsect_t const* bootsect) | |
| 53 | { | ||
| 54 | ✗ | return (unsigned)bootsect->bpb.total_sectors / (unsigned)bootsect->bpb.sectors_per_cluster; | |
| 55 | } | ||
| 56 | |||
| 57 | ✗ | static unsigned get_first_root_dir_sector(gate_filesystem_fat_bootsect_t const* bootsect) | |
| 58 | { | ||
| 59 | ✗ | return (unsigned)bootsect->bpb.reserved_sectors + (unsigned)bootsect->bpb.sectors_per_fat * (unsigned)bootsect->bpb.number_of_fats; | |
| 60 | } | ||
| 61 | |||
| 62 | ✗ | static unsigned get_root_dir_sectors(gate_filesystem_fat_bootsect_t const* bootsect) | |
| 63 | { | ||
| 64 | ✗ | return (bootsect->bpb.root_entries * 32 + (unsigned)bootsect->bpb.bytes_per_sector - 1) | |
| 65 | ✗ | / (unsigned)bootsect->bpb.bytes_per_sector; | |
| 66 | } | ||
| 67 | |||
| 68 | ✗ | static unsigned get_total_data_sectors(gate_filesystem_fat_bootsect_t const* bootsect) | |
| 69 | { | ||
| 70 | ✗ | unsigned const first_root_dir_sector = get_first_root_dir_sector(bootsect); | |
| 71 | ✗ | unsigned const root_dir_sectors = get_root_dir_sectors(bootsect); | |
| 72 | ✗ | return (unsigned)bootsect->bpb.total_sectors - first_root_dir_sector - root_dir_sectors; | |
| 73 | } | ||
| 74 | |||
| 75 | ✗ | static unsigned get_total_data_clusters(gate_filesystem_fat_bootsect_t const* bootsect) | |
| 76 | { | ||
| 77 | ✗ | return get_total_data_sectors(bootsect) / (unsigned)bootsect->bpb.sectors_per_cluster; | |
| 78 | } | ||
| 79 | |||
| 80 | ✗ | static unsigned get_root_dir_sectors_count(gate_filesystem_fat_bootsect_t const* bootsect) | |
| 81 | { | ||
| 82 | ✗ | unsigned const sector_size = bootsect->bpb.bytes_per_sector; | |
| 83 | ✗ | return (bootsect->bpb.root_entries * 32 + sector_size - 1) / sector_size; | |
| 84 | } | ||
| 85 | |||
| 86 | ✗ | static unsigned get_data_cluster_sector(gate_filesystem_fat_bootsect_t const* bootsect, unsigned cluster_num) | |
| 87 | { | ||
| 88 | /* notice: our cluster_num starts with "0" (FAT clusters start with "2") */ | ||
| 89 | ✗ | unsigned const root_dir_sectors = get_root_dir_sectors_count(bootsect); | |
| 90 | ✗ | unsigned const first_data_cluster_sector = get_first_root_dir_sector(bootsect) + root_dir_sectors; | |
| 91 | ✗ | return first_data_cluster_sector + cluster_num * (unsigned)bootsect->bpb.sectors_per_cluster; | |
| 92 | } | ||
| 93 | |||
| 94 | ✗ | static unsigned get_fat_type(gate_filesystem_fat_bootsect_t const* bootsect) | |
| 95 | { | ||
| 96 | ✗ | gate_size_t total_clusters = bootsect->bpb.total_sectors / bootsect->bpb.sectors_per_cluster; | |
| 97 | |||
| 98 | ✗ | if (total_clusters < 4085) | |
| 99 | { | ||
| 100 | ✗ | return 12; | |
| 101 | } | ||
| 102 | ✗ | else if (total_clusters < 65525) | |
| 103 | { | ||
| 104 | ✗ | return 16; | |
| 105 | } | ||
| 106 | else | ||
| 107 | { | ||
| 108 | ✗ | return 32; | |
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | ✗ | static gate_result_t read_sector(gate_controlstream_t* blockstream, gate_filesystem_fat_bootsect_t const* bootsect, unsigned sector, char* out_buffer) | |
| 113 | { | ||
| 114 | ✗ | const gate_size_t sector_length = bootsect->bpb.bytes_per_sector; | |
| 115 | ✗ | const gate_int64_t pos = (gate_int64_t)sector * (gate_int64_t)sector_length; | |
| 116 | gate_size_t length_returned; | ||
| 117 | ✗ | gate_result_t result = gate_stream_seek(blockstream, pos, GATE_STREAM_SEEK_BEGIN, NULL); | |
| 118 | ✗ | if (GATE_SUCCEEDED(result)) | |
| 119 | { | ||
| 120 | ✗ | result = gate_stream_read_block((gate_stream_t*)blockstream, out_buffer, sector_length, &length_returned); | |
| 121 | } | ||
| 122 | ✗ | return result; | |
| 123 | } | ||
| 124 | |||
| 125 | ✗ | gate_result_t gate_filesystem_read_fat_entries(gate_controlstream_t* blockstream, gate_filesystem_fat_bootsect_t const* bootsect, | |
| 126 | gate_uint16_t* fat_entries, gate_size_t fat_entries_capacity, gate_size_t* fat_entries_count) | ||
| 127 | { | ||
| 128 | ✗ | const unsigned fat_type = get_fat_type(bootsect); | |
| 129 | ✗ | const unsigned fat_start = bootsect->bpb.reserved_sectors; | |
| 130 | ✗ | const unsigned sector_len = bootsect->bpb.bytes_per_sector; | |
| 131 | char local_buffer[512 * 3]; | ||
| 132 | ✗ | char* buffer = &local_buffer[0]; | |
| 133 | ✗ | const gate_size_t buffer_required_len = (gate_size_t)sector_len * 3u; | |
| 134 | ✗ | gate_size_t entry_counter = 0; | |
| 135 | ✗ | gate_result_t ret = GATE_RESULT_FAILED;; | |
| 136 | |||
| 137 | |||
| 138 | ✗ | if (sizeof(local_buffer) > buffer_required_len) | |
| 139 | { | ||
| 140 | ✗ | buffer = gate_mem_alloc(buffer_required_len); | |
| 141 | ✗ | if (buffer == NULL) | |
| 142 | { | ||
| 143 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | ✗ | if (!fat_entries_count) | |
| 148 | { | ||
| 149 | ✗ | fat_entries_count = &entry_counter; | |
| 150 | } | ||
| 151 | |||
| 152 | ✗ | switch (fat_type) | |
| 153 | { | ||
| 154 | ✗ | case 12: | |
| 155 | { | ||
| 156 | unsigned ndx; | ||
| 157 | ✗ | for (ndx = 0; (ndx < bootsect->bpb.sectors_per_fat) && (fat_entries_capacity > 0); ndx += 3) | |
| 158 | { | ||
| 159 | unsigned pos; | ||
| 160 | ✗ | ret = read_sector(blockstream, bootsect, fat_start + ndx, &buffer[0]); | |
| 161 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
| 162 | ✗ | ret = read_sector(blockstream, bootsect, fat_start + ndx + 1, &buffer[sector_len]); | |
| 163 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
| 164 | ✗ | ret = read_sector(blockstream, bootsect, fat_start + ndx + 2, &buffer[sector_len * 2]); | |
| 165 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
| 166 | |||
| 167 | ✗ | for (pos = 0; (pos < 3 * sector_len) && (fat_entries_capacity > 0); pos += 3) | |
| 168 | { | ||
| 169 | ✗ | *fat_entries = (gate_uint16_t)buffer[pos] | ((gate_uint16_t)buffer[pos + 1] << 8); | |
| 170 | ✗ | ++fat_entries; | |
| 171 | ✗ | ++(*fat_entries_count); | |
| 172 | ✗ | if (0 == --fat_entries_capacity) | |
| 173 | { | ||
| 174 | ✗ | break; | |
| 175 | } | ||
| 176 | |||
| 177 | ✗ | *fat_entries = (((gate_uint16_t)buffer[pos + 1] >> 4) & 0x0f) | ((gate_uint16_t)buffer[pos + 2] << 4); | |
| 178 | ✗ | ++fat_entries; | |
| 179 | ✗ | ++(*fat_entries_count); | |
| 180 | ✗ | --fat_entries_capacity; | |
| 181 | } | ||
| 182 | } | ||
| 183 | ✗ | break; | |
| 184 | } | ||
| 185 | ✗ | case 16: | |
| 186 | case 32: | ||
| 187 | default: | ||
| 188 | { | ||
| 189 | ✗ | ret = GATE_RESULT_NOTSUPPORTED; | |
| 190 | ✗ | break; | |
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | ✗ | if (buffer && (buffer != &local_buffer[0])) | |
| 195 | { | ||
| 196 | ✗ | gate_mem_dealloc(buffer); | |
| 197 | } | ||
| 198 | ✗ | return ret; | |
| 199 | } | ||
| 200 | |||
| 201 | ✗ | gate_result_t gate_filesystem_read_next_fat_entry( | |
| 202 | gate_controlstream_t* blockstream, gate_filesystem_fat_bootsect_t const* bootsect, gate_uint32_t fat_entry, gate_uint32_t* next_fat_entry) | ||
| 203 | { | ||
| 204 | ✗ | const unsigned fat_type = get_fat_type(bootsect); | |
| 205 | ✗ | const unsigned fat_start = bootsect->bpb.reserved_sectors; | |
| 206 | ✗ | const unsigned sector_len = bootsect->bpb.bytes_per_sector; | |
| 207 | unsigned char local_buffer[512 * 2]; | ||
| 208 | ✗ | unsigned char* buffer = &local_buffer[0]; | |
| 209 | ✗ | const gate_size_t buffer_required_len = (gate_size_t)sector_len * 2u; | |
| 210 | ✗ | gate_result_t ret = GATE_RESULT_FAILED; | |
| 211 | |||
| 212 | ✗ | if (sizeof(local_buffer) > buffer_required_len) | |
| 213 | { | ||
| 214 | ✗ | buffer = (unsigned char*)gate_mem_alloc(buffer_required_len); | |
| 215 | ✗ | if (buffer == NULL) | |
| 216 | { | ||
| 217 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | ✗ | switch (fat_type) | |
| 222 | { | ||
| 223 | ✗ | case 12: | |
| 224 | { | ||
| 225 | unsigned next_cluster; | ||
| 226 | ✗ | unsigned cluster_pos = fat_entry; | |
| 227 | ✗ | unsigned fat_offset = (cluster_pos / 2) * 3; | |
| 228 | ✗ | unsigned sector_num = fat_offset / sector_len; | |
| 229 | ✗ | unsigned sector_offset = fat_offset % sector_len; | |
| 230 | |||
| 231 | ✗ | ret = read_sector(blockstream, bootsect, fat_start + sector_num, (char*)&buffer[0]); | |
| 232 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
| 233 | ✗ | if (sector_offset >= sector_len - 2) | |
| 234 | { | ||
| 235 | /* fat entry is on the boundary to the next sector */ | ||
| 236 | ✗ | ret = read_sector(blockstream, bootsect, fat_start + sector_num, (char*)&buffer[sector_len]); | |
| 237 | ✗ | GATE_BREAK_IF_FAILED(ret); | |
| 238 | } | ||
| 239 | |||
| 240 | ✗ | if ((cluster_pos & 1) == 0) | |
| 241 | { | ||
| 242 | ✗ | next_cluster = (gate_uint16_t)buffer[sector_offset] | (((gate_uint16_t)buffer[sector_offset + 1] & 0x0f) << 8); | |
| 243 | } | ||
| 244 | else | ||
| 245 | { | ||
| 246 | ✗ | next_cluster = (((gate_uint16_t)buffer[sector_offset + 1] >> 4) & 0x0f) | ((gate_uint16_t)buffer[sector_offset + 2] << 4); | |
| 247 | } | ||
| 248 | |||
| 249 | ✗ | if (next_cluster >= 0xff8) | |
| 250 | { | ||
| 251 | ✗ | ret = GATE_RESULT_ENDOFSTREAM; | |
| 252 | ✗ | *next_fat_entry = 0; | |
| 253 | } | ||
| 254 | ✗ | else if (next_cluster == 0xff7) | |
| 255 | { | ||
| 256 | ✗ | ret = GATE_RESULT_INVALIDCONTENT; | |
| 257 | } | ||
| 258 | else | ||
| 259 | { | ||
| 260 | ✗ | *next_fat_entry = next_cluster; | |
| 261 | ✗ | ret = GATE_RESULT_OK; | |
| 262 | } | ||
| 263 | ✗ | break; | |
| 264 | } | ||
| 265 | ✗ | case 16: | |
| 266 | case 32: | ||
| 267 | default: | ||
| 268 | { | ||
| 269 | ✗ | ret = GATE_RESULT_NOTSUPPORTED; | |
| 270 | ✗ | break; | |
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | ✗ | if (buffer && (buffer != &local_buffer[0])) | |
| 275 | { | ||
| 276 | ✗ | gate_mem_dealloc(buffer); | |
| 277 | } | ||
| 278 | ✗ | return ret; | |
| 279 | } | ||
| 280 | |||
| 281 | |||
| 282 | |||
| 283 | ✗ | gate_result_t gate_filesystem_read_fat_cluster(gate_controlstream_t* blockstream, gate_filesystem_fat_bootsect_t const* bootsect, | |
| 284 | gate_uint32_t cluster, char* buffer, gate_size_t buffer_capacity, gate_size_t* buffer_filled) | ||
| 285 | { | ||
| 286 | ✗ | unsigned fat_type = get_fat_type(bootsect); | |
| 287 | |||
| 288 | ✗ | switch (fat_type) | |
| 289 | { | ||
| 290 | ✗ | case 12: | |
| 291 | { | ||
| 292 | unsigned total_clusters; | ||
| 293 | unsigned sector_num; | ||
| 294 | unsigned byte_count; | ||
| 295 | gate_int64_t stream_offset; | ||
| 296 | gate_result_t result; | ||
| 297 | |||
| 298 | ✗ | if (cluster < 2) | |
| 299 | { | ||
| 300 | /* first FAT clusters has cluster-id 2 */ | ||
| 301 | ✗ | return GATE_RESULT_INVALIDARG; | |
| 302 | } | ||
| 303 | ✗ | cluster -= 2; | |
| 304 | ✗ | total_clusters = get_total_data_clusters(bootsect); | |
| 305 | ✗ | if (cluster >= total_clusters) | |
| 306 | { | ||
| 307 | ✗ | return GATE_RESULT_OUTOFBOUNDS; | |
| 308 | } | ||
| 309 | ✗ | sector_num = get_data_cluster_sector(bootsect, (unsigned)cluster); | |
| 310 | ✗ | stream_offset = (gate_int64_t)sector_num * (gate_int64_t)bootsect->bpb.bytes_per_sector; | |
| 311 | ✗ | byte_count = (unsigned)bootsect->bpb.sectors_per_cluster * (unsigned)bootsect->bpb.bytes_per_sector; | |
| 312 | ✗ | if (buffer_capacity > byte_count) | |
| 313 | { | ||
| 314 | ✗ | buffer_capacity = byte_count; | |
| 315 | } | ||
| 316 | ✗ | result = gate_stream_seek(blockstream, stream_offset, GATE_STREAM_SEEK_BEGIN, NULL); | |
| 317 | ✗ | GATE_RETURN_IF_FAILED(result); | |
| 318 | ✗ | return gate_stream_read_block((gate_stream_t*)blockstream, buffer, buffer_capacity, buffer_filled); | |
| 319 | } | ||
| 320 | ✗ | case 16: | |
| 321 | case 32: | ||
| 322 | default: | ||
| 323 | ✗ | return GATE_RESULT_NOTSUPPORTED; | |
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 327 | ✗ | static gate_result_t read_fat_dir(gate_controlstream_t* blockstream, gate_filesystem_fat_bootsect_t const* bootsect, | |
| 328 | unsigned start_sector, unsigned sectors_count, gate_filesystem_fat_direntry_callback_t callback, void* user_param) | ||
| 329 | { | ||
| 330 | ✗ | const unsigned sectorlen = bootsect->bpb.bytes_per_sector; | |
| 331 | ✗ | const unsigned sectorentries = sectorlen / 32; | |
| 332 | |||
| 333 | ✗ | gate_result_t result = GATE_RESULT_OK; | |
| 334 | unsigned ndx; | ||
| 335 | |||
| 336 | ✗ | for (ndx = 0; ndx != sectors_count; ++ndx) | |
| 337 | { | ||
| 338 | gate_filesystem_fat_direntry_t const* ptr_direntry; | ||
| 339 | unsigned ent; | ||
| 340 | char buffer[4096]; | ||
| 341 | ✗ | result = read_sector(blockstream, bootsect, start_sector + ndx, buffer); | |
| 342 | ✗ | GATE_RETURN_IF_FAILED(result); | |
| 343 | ✗ | ptr_direntry = (gate_filesystem_fat_direntry_t const*)buffer; | |
| 344 | |||
| 345 | ✗ | for (ent = 0; ent != sectorentries; ++ent, ++ptr_direntry) | |
| 346 | { | ||
| 347 | ✗ | switch ((unsigned char)ptr_direntry->filename[0]) | |
| 348 | { | ||
| 349 | ✗ | case 0: | |
| 350 | /* end of directory reached */ | ||
| 351 | ✗ | return GATE_RESULT_OK; | |
| 352 | ✗ | case 0xe5: | |
| 353 | /* unused_entry, skip */ | ||
| 354 | ✗ | continue; | |
| 355 | ✗ | default: | |
| 356 | ✗ | if (ptr_direntry->attributes == 0x0f) | |
| 357 | { | ||
| 358 | /* long filename, skip */ | ||
| 359 | ✗ | continue; | |
| 360 | } | ||
| 361 | |||
| 362 | /* standard entry: */ | ||
| 363 | ✗ | if (!callback(ptr_direntry, user_param)) | |
| 364 | { | ||
| 365 | /* canceled by callback */ | ||
| 366 | ✗ | return GATE_RESULT_CANCELED; | |
| 367 | } | ||
| 368 | ✗ | break; | |
| 369 | } | ||
| 370 | } | ||
| 371 | } | ||
| 372 | ✗ | return result; | |
| 373 | } | ||
| 374 | |||
| 375 | ✗ | gate_result_t gate_filesystem_read_fat_directory(gate_controlstream_t* blockstream, gate_filesystem_fat_bootsect_t const* bootsect, | |
| 376 | gate_string_t const* subdir, gate_filesystem_fat_direntry_callback_t callback, void* user_param) | ||
| 377 | { | ||
| 378 | ✗ | const unsigned root_sector = get_first_root_dir_sector(bootsect); | |
| 379 | ✗ | const unsigned root_sectors_count = get_root_dir_sectors(bootsect); | |
| 380 | |||
| 381 | ✗ | gate_result_t ret = read_fat_dir(blockstream, bootsect, root_sector, root_sectors_count, callback, user_param); | |
| 382 | ✗ | if (ret == GATE_RESULT_CANCELED) | |
| 383 | { | ||
| 384 | ✗ | ret = GATE_RESULT_OK; | |
| 385 | } | ||
| 386 | ✗ | return ret; | |
| 387 | } | ||
| 388 | |||
| 389 | struct find_fat_file_param | ||
| 390 | { | ||
| 391 | char filename[8]; | ||
| 392 | char fileext[3]; | ||
| 393 | gate_filesystem_fat_direntry_t matched_entry; | ||
| 394 | }; | ||
| 395 | |||
| 396 | ✗ | static gate_bool_t find_fat_file_cb(gate_filesystem_fat_direntry_t const* entry, void* user_param) | |
| 397 | { | ||
| 398 | ✗ | struct find_fat_file_param* param = (struct find_fat_file_param*)user_param; | |
| 399 | ✗ | if ((0 == gate_mem_compare(entry->filename, param->filename, 8)) | |
| 400 | ✗ | && (0 == gate_mem_compare(entry->extension, param->fileext, 3))) | |
| 401 | { | ||
| 402 | ✗ | gate_mem_copy(¶m->matched_entry, entry, sizeof(gate_filesystem_fat_direntry_t)); | |
| 403 | ✗ | return false; | |
| 404 | } | ||
| 405 | ✗ | return true; | |
| 406 | } | ||
| 407 | |||
| 408 | |||
| 409 | ✗ | gate_result_t gate_filesystem_find_fat_file(gate_controlstream_t* blockstream, gate_filesystem_fat_bootsect_t const* bootsect, | |
| 410 | gate_string_t const* path, gate_filesystem_fat_direntry_t* ptr_found_entry) | ||
| 411 | { | ||
| 412 | gate_result_t ret; | ||
| 413 | gate_size_t pos; | ||
| 414 | ✗ | gate_size_t len = gate_string_length(path); | |
| 415 | struct find_fat_file_param param; | ||
| 416 | |||
| 417 | ✗ | gate_mem_clear(¶m, sizeof(param)); | |
| 418 | ✗ | gate_mem_fill(¶m.filename[0], ' ', sizeof(param.filename)); | |
| 419 | ✗ | gate_mem_fill(¶m.fileext[0], ' ', sizeof(param.fileext)); | |
| 420 | ✗ | pos = gate_string_char_pos_last(path, '.'); | |
| 421 | ✗ | if (pos == GATE_STR_NPOS) | |
| 422 | { | ||
| 423 | ✗ | pos = len > 8 ? 8 : len; | |
| 424 | ✗ | gate_mem_copy(param.filename, gate_string_ptr(path, 0), pos); | |
| 425 | } | ||
| 426 | else | ||
| 427 | { | ||
| 428 | ✗ | gate_mem_copy(param.filename, gate_string_ptr(path, 0), pos > 8 ? 8 : pos); | |
| 429 | ✗ | if (len - pos - 1 >= 3) | |
| 430 | { | ||
| 431 | ✗ | gate_mem_copy(param.fileext, gate_string_ptr(path, pos + 1), 3); | |
| 432 | } | ||
| 433 | else | ||
| 434 | { | ||
| 435 | ✗ | gate_mem_copy(param.fileext, gate_string_ptr(path, pos + 1), len - pos - 1); | |
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | ✗ | ret = gate_filesystem_read_fat_directory(blockstream, bootsect, NULL, &find_fat_file_cb, ¶m); | |
| 440 | ✗ | if (GATE_SUCCEEDED(ret)) | |
| 441 | { | ||
| 442 | ✗ | if (param.matched_entry.filename[0] != 0) | |
| 443 | { | ||
| 444 | ✗ | gate_mem_copy(ptr_found_entry, ¶m.matched_entry, sizeof(gate_filesystem_fat_direntry_t)); | |
| 445 | } | ||
| 446 | else | ||
| 447 | { | ||
| 448 | ✗ | ret = GATE_RESULT_NOMATCH; | |
| 449 | } | ||
| 450 | } | ||
| 451 | ✗ | return ret; | |
| 452 | } | ||
| 453 |