15#define WRITE_MODE_APPEND_EXISTING 0
16#define WRITE_MODE_CREATE_OR_REPLACE 1
18#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
19#define le32toh(x) __builtin_bswap32(x)
29static SPINLOCK fat32_read_fat_lock = { 0 };
30static SPINLOCK fat32_write_fat_lock = { 0 };
31static void* fat_cache_buf = NULL;
33static uint32_t fat_cache_sector = UINT32_MAX;
35#define MAX_LFN_ENTRIES 20
36#define MAX_LFN_LEN 260
41#define FAT32_READ_ERROR 0xFFFFFFFFu
47static MTSTATUS read_sector(uint32_t lba,
void* buf) {
49 size_t NumberOfBytes = fs.bytes_per_sector;
50 if (!NumberOfBytes) NumberOfBytes = 512;
52 if (NumberOfBytes % 512 != 0) {
57 return disk->read_sector(disk, lba, buf, NumberOfBytes);
61static MTSTATUS write_sector(uint32_t lba,
const void* buf) {
63 size_t NumberOfBytes = fs.bytes_per_sector;
64 if (!NumberOfBytes) NumberOfBytes = 512;
66 if (NumberOfBytes % 512 != 0) {
71 return disk->write_sector(disk, lba, buf, NumberOfBytes);
75static uint8_t lfn_checksum(
const uint8_t short_name[11]) {
77 for (
int i = 0; i < 11; i++) {
78 sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + short_name[i];
84static inline int toupper(
int c) {
85 if (c >=
'a' && c <=
'z') {
86 return c - (
'a' -
'A');
92static bool cmp_name(
const char* str_1,
const char* str_2) {
94 for (
int i = 0; i < 11; i++) { t[i] = str_1[i]; }
95 for (
int i = 0; i < 11; i++) {
96 if (toupper(t[i]) != toupper(str_2[i])) {
105static void format_short_name(
const char* input,
char out[11]) {
107 for (
int i = 0; i < 11; ++i) out[i] =
' ';
110 const unsigned char* p = (
const unsigned char*)input;
111 while (*p && *p !=
'.' && ni < 8) {
112 out[ni++] = (char)toupper(*p++);
118 while (*p && ei < 3) {
119 out[8 + ei++] = (char)toupper(*p++);
132 if (!cur || remaining == 0)
return NULL;
137 uint32_t lfn_count = 0;
141 while (i < remaining && ((uint8_t)cur[i].name[0] != 0x00) && (cur[i].attr ==
ATTR_LONG_NAME)) {
147 if (i >= remaining)
return NULL;
149 if ((uint8_t)short_entry->name[0] == 0x00 || (uint8_t)short_entry->name[0] == 0xE5) {
155 if (lfn_count == 0) {
157 const unsigned char* s = (
const unsigned char*)short_entry->name;
161 for (
int n = 0; n < 8; ++n) {
162 if (s[n] ==
' ')
break;
163 if (pos < (
int)
MAX_LFN_LEN - 1) out_name[pos++] = s[n];
167 bool has_ext =
false;
168 for (
int n = 8; n < 11; ++n)
if (s[n] !=
' ') { has_ext =
true;
break; }
170 if (pos < (
int)
MAX_LFN_LEN - 1) out_name[pos++] =
'.';
171 for (
int n = 8; n < 11; ++n) {
172 if (s[n] ==
' ')
break;
173 if (pos < (
int)
MAX_LFN_LEN - 1) out_name[pos++] = s[n];
177 out_name[pos] =
'\0';
183 uint8_t cs = lfn_checksum((uint8_t*)short_entry->name);
184 for (uint32_t j = 0; j < lfn_count; ++j) {
185 uint8_t entry_checksum = *((uint8_t*)lfn_list[j] + 13);
186 if (entry_checksum != cs)
return NULL;
191 for (
int j = (
int)lfn_count - 1; j >= 0; --j) {
192 uint8_t* ebytes = (uint8_t*)lfn_list[j];
195 uint16_t* name1 = (uint16_t*)(ebytes + 1);
196 for (
int c = 0; c < 5; ++c) {
197 uint16_t ch = name1[c];
198 if (ch == 0x0000) { out_name[pos] =
'\0';
goto done; }
202 if (ch <= 0x7F) out_name[pos++] = (char)ch;
else out_name[pos++] =
'?';
206 uint16_t* name2 = (uint16_t*)(ebytes + 14);
207 for (
int c = 0; c < 6; ++c) {
208 uint16_t ch = name2[c];
209 if (ch == 0x0000) { out_name[pos] =
'\0';
goto done; }
213 if (ch <= 0x7F) out_name[pos++] = (char)ch;
else out_name[pos++] =
'?';
217 uint16_t* name3 = (uint16_t*)(ebytes + 28);
218 for (
int c = 0; c < 2; ++c) {
219 uint16_t ch = name3[c];
220 if (ch == 0x0000) { out_name[pos] =
'\0';
goto done; }
224 if (ch <= 0x7F) out_name[pos++] = (char)ch;
else out_name[pos++] =
'?';
229 out_name[pos] =
'\0';
231 *out_consumed = (uint32_t)lfn_count + 1;
235static inline uint32_t fat32_total_clusters(
void) {
236 return (bpb.total_sectors_32 - fs.first_data_sector) / fs.sectors_per_cluster;
240static uint32_t fat32_read_fat(uint32_t cluster) {
255 if (!fat_cache_buf) {
257 if (!fat_cache_buf) {
258 gop_printf(0xFFFF0000,
"fat32_read_fat: couldn't alloc cache buf\n");
267 uint32_t fat_offset = cluster * 4;
268 uint32_t fat_sector = fs.fat_start + (fat_offset / fs.bytes_per_sector);
269 uint32_t ent_offset = fat_offset % fs.bytes_per_sector;
270 uint32_t bps = fs.bytes_per_sector;
273 if (fat_cache_sector != fat_sector) {
274 MTSTATUS st = read_sector(fat_sector, fat_cache_buf);
276 gop_printf(0xFFFF0000,
"fat32_read_fat: read_sector fail for sector %u\n", fat_sector);
283 fat_cache_sector = fat_sector;
289 if (ent_offset <= bps - 4) {
291 kmemcpy(&raw, (uint8_t*)fat_cache_buf + ent_offset,
sizeof(raw));
293 val = raw & 0x0FFFFFFF;
300 gop_printf(0xFFFF0000,
"fat32_read_fat: couldn't alloc secondary cache buf\n");
311 gop_printf(0xFFFF0000,
"fat32_read_fat: read_sector fail for next sector %u\n", fat_sector + 1);
320 size_t first = bps - ent_offset;
321 kmemcpy(tmp, (uint8_t*)fat_cache_buf + ent_offset, first);
323 kmemcpy(&raw, tmp,
sizeof(raw));
325 val = raw & 0x0FFFFFFF;
329 if (val == cluster) {
331 gop_printf(0xFFFF0000,
"FAT suspicious: cluster=%u -> raw=0x%08x (ent_off=%u, fat_sector=%u, total=%u)\n",
332 cluster, raw, ent_offset, fat_sector, fat32_total_clusters());
345static inline uint32_t first_sector_of_cluster(uint32_t cluster) {
346 return fs.first_data_sector + (cluster - 2) * fs.sectors_per_cluster;
350static bool fat32_write_fat(uint32_t cluster, uint32_t value) {
353 uint32_t fat_offset = cluster * 4;
354 uint32_t sec_index = fat_offset / fs.bytes_per_sector;
355 uint32_t ent_offset = fat_offset % fs.bytes_per_sector;
356 uint32_t bps = fs.bytes_per_sector;
357 if (bps == 0) {
gop_printf(0xFFFF0000,
"fat32_write_fat: bps==0!\n");
MsReleaseSpinlock(&fat32_write_fat_lock, oldIrql);
return false; }
364 gop_printf(0x00FF00FF,
"fat32_write_fat: alloc buf1=%p bps=%u ent_off=%u sec=%u\n", buf1, bps, ent_offset, sec_index);
367 bool spans = (ent_offset > bps - 4);
378 for (uint32_t fat_i = 0; fat_i < bpb.num_fats; ++fat_i) {
379 uint32_t current_fat_base = fs.fat_start + (fat_i * fs.sectors_per_fat);
380 uint32_t sector1_lba = current_fat_base + sec_index;
381 uint32_t sector2_lba = sector1_lba + 1;
391 uint8_t value_bytes[4];
392 kmemcpy(value_bytes, &value, 4);
394 size_t first_part_size = bps - ent_offset;
395 size_t second_part_size = 4 - first_part_size;
397 kmemcpy((uint8_t*)buf1 + ent_offset, value_bytes, first_part_size);
398 kmemcpy(buf2, value_bytes + first_part_size, second_part_size);
401 if (
MT_FAILURE(write_sector(sector1_lba, buf1)) ||
MT_FAILURE(write_sector(sector2_lba, buf2))) {
408 if (
MT_FAILURE(read_sector(sector1_lba, buf1))) { ok =
false;
break; }
412 kmemcpy(&raw_le, (uint8_t*)buf1 + ent_offset,
sizeof(raw_le));
413 uint32_t raw =
le32toh(raw_le);
416 raw = (raw & 0xF0000000) | (value & 0x0FFFFFFF);
419 uint32_t new_le =
le32toh(raw);
420 kmemcpy((uint8_t*)buf1 + ent_offset, &new_le,
sizeof(new_le));
422 if (
MT_FAILURE(write_sector(sector1_lba, buf1))) { ok =
false;
break; }
436 return ((uint32_t)entry->fst_clus_hi << 16) | entry->fst_clus_lo;
440static bool fat32_free_cluster_chain(uint32_t start_cluster) {
441 if (start_cluster < 2 || start_cluster >=
FAT32_EOC_MIN)
return false;
443 uint32_t cur = start_cluster;
445 uint32_t next = fat32_read_fat(cur);
446 if (next == cur || next == 0) {
447 gop_printf(0xFFFF0000,
"Detected FAT self-loop/zero at %u -> %u | %s\n", cur, next, __func__);
453 if (next == cur)
break;
459static uint32_t fat32_find_free_cluster(
void) {
464 uint32_t total_clusters = fat32_total_clusters();
466 for (uint32_t i = 2; i < total_clusters; i++) {
467 retval = fat32_read_fat(i);
483static bool zero_cluster(uint32_t cluster) {
486 if (!buf)
return false;
487 kmemset(buf, 0, fs.bytes_per_sector);
489 uint32_t sector = first_sector_of_cluster(cluster);
490 for (uint32_t i = 0; i < fs.sectors_per_cluster; i++) {
491 status = write_sector(sector + i, buf);
503static bool cmp_short_name(
const char* dir_name,
const char short_name[11]) {
504 for (
int i = 0; i < 11; ++i) {
505 if ((
unsigned char)dir_name[i] != (
unsigned char)short_name[i])
return false;
511static inline bool ci_equal(
const char* a,
const char* b) {
514 if (la != lb)
return false;
515 for (
size_t i = 0; i < la; ++i) {
516 if ((
char)toupper((
int)a[i]) != (
char)toupper((
int)b[i]))
return false;
522static uint32_t fat32_create_lfn_entries(
FAT32_LFN_ENTRY* entry_buffer,
const char* long_name, uint8_t sfn_checksum) {
523 uint32_t len =
kstrlen(long_name);
524 uint32_t num_lfn_entries = (len + 12) / 13;
525 uint32_t char_idx = 0;
527 for (
int i = (
int)num_lfn_entries - 1; i >= 0; --i) {
533 uint8_t seq = (uint8_t)(num_lfn_entries - i);
534 if (i == (
int)num_lfn_entries - 1)
544 for (
int k = 0; k < 13; ++k) {
545 uint16_t uch = 0xFFFF;
547 uch = (uint8_t)long_name[char_idx];
548 else if (char_idx == len)
563 return num_lfn_entries;
574static bool fat32_find_entry(
const char* path,
FAT32_DIR_ENTRY* out_entry, uint32_t* out_parent_cluster) {
576 kstrncpy(path_copy, path,
sizeof(path_copy));
578 uint32_t current_cluster = fs.root_cluster;
579 uint32_t parent_cluster_of_last_found = fs.root_cluster;
581 if (
kstrcmp(path_copy,
"/") == 0 || path_copy[0] ==
'\0') {
585 out_entry->fst_clus_lo = (uint16_t)(fs.root_cluster & 0xFFFF);
586 out_entry->fst_clus_hi = (uint16_t)(fs.root_cluster >> 16);
588 if (out_parent_cluster) *out_parent_cluster = fs.root_cluster;
594 bool any_token_found =
false;
596 char* save_ptr = NULL;
597 char* token =
kstrtok_r(path_copy,
"/", &save_ptr);
599 while (token != NULL) {
600 bool found_this_token =
false;
601 parent_cluster_of_last_found = current_cluster;
604 if (!sector_buf)
return false;
606 uint32_t search_cluster = current_cluster;
608 uint32_t sector = first_sector_of_cluster(search_cluster);
609 for (uint32_t i = 0; i < fs.sectors_per_cluster; i++) {
610 MTSTATUS status = read_sector(sector + i, sector_buf);
616 for (uint32_t j = 0; j < num_entries; ) {
623 uint32_t consumed = 0;
624 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], num_entries - j, lfn_buf, &consumed);
628 if (ci_equal(lfn_buf, token)) {
630 found_this_token =
true;
631 current_cluster = (sfn->fst_clus_hi << 16) | sfn->fst_clus_lo;
632 goto token_search_done;
635 j += (consumed > 0) ? consumed : 1;
639 search_cluster = fat32_read_fat(search_cluster);
645 if (!found_this_token) {
648 any_token_found =
true;
656 if (any_token_found) {
658 if (out_parent_cluster) *out_parent_cluster = parent_cluster_of_last_found;
665static bool fat32_extend_directory(uint32_t dir_cluster) {
666 uint32_t new_cluster = fat32_find_free_cluster();
667 if (new_cluster == 0)
return false;
670 if (!zero_cluster(new_cluster)) {
678 uint32_t current = dir_cluster;
684 return fat32_write_fat(current, new_cluster);
687static bool fat32_find_free_dir_slots(uint32_t dir_cluster, uint32_t count, uint32_t* out_sector, uint32_t* out_entry_index) {
688 uint32_t current_cluster = dir_cluster;
690 if (!sector_buf)
return false;
694 uint32_t sector_lba = first_sector_of_cluster(current_cluster);
695 for (uint32_t i = 0; i < fs.sectors_per_cluster; i++) {
696 status = read_sector(sector_lba + i, sector_buf);
703 uint32_t consecutive_free = 0;
705 for (uint32_t j = 0; j < num_entries; j++) {
706 uint8_t first_byte = (uint8_t)entries[j].name[0];
708 if (consecutive_free == 0) {
710 *out_sector = sector_lba + i;
711 *out_entry_index = j;
714 if (consecutive_free == count) {
720 consecutive_free = 0;
725 uint32_t next_cluster = fat32_read_fat(current_cluster);
728 if (fat32_extend_directory(dir_cluster)) {
729 return fat32_find_free_dir_slots(dir_cluster, count, out_sector, out_entry_index);
735 current_cluster = next_cluster;
742#define BPB_SECTOR_START 2048
754 kmemcpy(&bpb, buf,
sizeof(bpb));
757 fs.bytes_per_sector = bpb.bytes_per_sector;
758 fs.sectors_per_cluster = bpb.sectors_per_cluster;
759 fs.reserved_sector_count = bpb.reserved_sector_count;
760 fs.sectors_per_fat = bpb.fat_size_32;
761 fs.root_cluster = bpb.root_cluster;
763 fs.first_data_sector = fs.fat_start + bpb.num_fats * fs.sectors_per_fat;
770 uint32_t cluster = fs.root_cluster;
777 uint32_t lfn_accum = 0;
780 uint32_t sector = first_sector_of_cluster(cluster);
781 for (uint32_t i = 0; i < fs.sectors_per_cluster; ++i) {
782 status = read_sector(sector + i, buf);
788 uint32_t entries = fs.bytes_per_sector /
sizeof(*dir);
790 for (uint32_t j = 0; j < entries; ++j, ++dir) {
791 uint8_t first = (uint8_t)dir->name[0];
820 uint32_t consumed = 0;
827 real = read_lfn(temp_entries, lfn_accum + 1, bufferLfn, &consumed);
834 uint32_t remaining = entries - j;
835 real = read_lfn(&dir[0], remaining, bufferLfn, &consumed);
841 gop_printf(0xFF00FFFF,
"Found: %s\n", bufferLfn);
846 for (
int k = 0; k < 11; ++k) fallback[k] = dir->name[k];
848 gop_printf(0xFF00FFFF,
"Found (raw): %s\n", fallback);
855 cluster = fat32_read_fat(cluster);
860static bool is_filename_in_dir(
const char* filename) {
861 if (!filename)
return false;
864 if (*filename ==
'/')
return true;
871static uint32_t extract_dir_cluster(
const char* filename) {
873 if (!filename || filename[0] ==
'\0')
return fs.root_cluster;
877 kstrncpy(path_copy, filename,
sizeof(path_copy));
880 int len = (int)
kstrlen(path_copy);
881 while (len > 1 && path_copy[len - 1] ==
'/') {
882 path_copy[len - 1] =
'\0';
888 for (
int i = len - 1; i >= 0; --i) {
889 if (path_copy[i] ==
'/') { last_slash = i;
break; }
893 if (last_slash == -1) {
894 return fs.root_cluster;
899 if (last_slash == 0) {
905 for (
int i = 0; i < last_slash; ++i) parent[i] = path_copy[i];
906 parent[last_slash] =
'\0';
911 if (!fat32_find_entry(parent, &parent_entry, NULL))
return 0;
916 uint32_t cluster = ((uint32_t)parent_entry.fst_clus_hi << 16) | parent_entry.fst_clus_lo;
917 if (cluster == 0) cluster = fs.root_cluster;
928 uint32_t cluster = 0;
930 if (is_filename_in_dir(filename)) {
931 cluster = extract_dir_cluster(filename);
938 cluster = fs.root_cluster;
942 uint32_t sector = first_sector_of_cluster(cluster);
943 for (uint32_t i = 0; i < fs.sectors_per_cluster; ++i) {
944 status = read_sector(sector + i, sblk);
952 uint32_t entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
954 for (uint32_t j = 0; j < entries_per_sector; ) {
968 uint32_t consumed_entries = 0;
969 FAT32_DIR_ENTRY* sfn_entry = read_lfn(current_entry, entries_per_sector - j, lfn_buf, &consumed_entries);
973 if (
kstrcmp(filename, lfn_buf) == 0) {
977 char shortname_formatted[11];
978 format_short_name(filename, shortname_formatted);
979 if (cmp_short_name(sfn_entry->name, shortname_formatted)) {
983 j += consumed_entries;
988 uint32_t file_size = sfn_entry->file_size;
990 *file_size_out = file_size;
1001 uint32_t file_cluster = (uint32_t)((sfn_entry->fst_clus_hi << 16) | sfn_entry->fst_clus_lo);
1002 uint32_t remaining_bytes = file_size;
1003 uint8_t* dst = (uint8_t*)file_buffer;
1005 while (file_cluster < FAT32_EOC_MIN && remaining_bytes > 0) {
1006 uint32_t current_sector = first_sector_of_cluster(file_cluster);
1007 for (uint32_t sc = 0; sc < fs.sectors_per_cluster && remaining_bytes > 0; ++sc) {
1008 status = read_sector(current_sector + sc, sblk);
1016 uint32_t bytes_to_copy = fs.bytes_per_sector;
1017 if (bytes_to_copy > remaining_bytes) {
1018 bytes_to_copy = remaining_bytes;
1021 kmemcpy(dst, sblk, bytes_to_copy);
1022 dst += bytes_to_copy;
1023 remaining_bytes -= bytes_to_copy;
1025 file_cluster = fat32_read_fat(file_cluster);
1030 *buffer_out = file_buffer;
1039 cluster = fat32_read_fat(cluster);
1049 if (fat32_find_entry(path, NULL, NULL)) {
1051 gop_printf(0xFFFF0000,
"Error: Path '%s' already exists.\n", path);
1057 char path_copy[260];
1058 kstrncpy(path_copy, path,
sizeof(path_copy));
1060 char* new_dir_name = NULL;
1061 char* parent_path =
"/";
1065 while (len > 1 && path_copy[len - 1] ==
'/') {
1066 path_copy[len - 1] =
'\0';
1071 int last_slash = -1;
1072 for (
int i = 0; path_copy[i] !=
'\0'; i++) {
1073 if (path_copy[i] ==
'/') last_slash = i;
1077 if (last_slash != -1) {
1078 new_dir_name = &path_copy[last_slash + 1];
1079 if (last_slash > 0) {
1080 path_copy[last_slash] =
'\0';
1081 parent_path = path_copy;
1087 new_dir_name = path_copy;
1093 uint32_t parent_cluster;
1094 if (!fat32_find_entry(parent_path, &parent_entry, NULL)) {
1096 gop_printf(0xFFFF0000,
"Error: Parent path '%s' not found.\n", parent_path);
1102 gop_printf(0xFFFF0000,
"Error: Parent path is not a directory. PATH: %s\n", parent_path);
1106 parent_cluster = (parent_entry.fst_clus_hi << 16) | parent_entry.fst_clus_lo;
1109 uint32_t new_cluster = fat32_find_free_cluster();
1113 zero_cluster(new_cluster);
1118 kmemset(sector_buf, 0, fs.bytes_per_sector);
1121 kmemcpy(dot_entries[0].name,
". ", 11);
1123 dot_entries[0].fst_clus_lo = (uint16_t)new_cluster;
1124 dot_entries[0].fst_clus_hi = (uint16_t)(new_cluster >> 16);
1126 kmemcpy(dot_entries[1].name,
".. ", 11);
1128 dot_entries[1].fst_clus_lo = (uint16_t)parent_cluster;
1129 dot_entries[1].fst_clus_hi = (uint16_t)(parent_cluster >> 16);
1131 write_sector(first_sector_of_cluster(new_cluster), sector_buf);
1136 format_short_name(new_dir_name, sfn);
1139 int name_len =
kstrlen(new_dir_name);
1141 if (name_len > 11) need_lfn = 1;
1143 for (
int i = 0; i < name_len; i++) {
1144 char c = new_dir_name[i];
1145 if (c >=
'a' && c <=
'z') { need_lfn = 1;
break; }
1149 uint32_t entry_sector = 0, entry_index = 0;
1153 uint8_t checksum = lfn_checksum((uint8_t*)sfn);
1154 uint32_t num_lfn_entries = (name_len + 12) / 13;
1155 uint32_t total_slots = num_lfn_entries + 1;
1157 if (!fat32_find_free_dir_slots(parent_cluster, total_slots, &entry_sector, &entry_index)) {
1166 if (!temp_entries) {
1175 fat32_create_lfn_entries(temp_entries, new_dir_name, checksum);
1180 kmemcpy(sfn_entry->name, sfn, 11);
1182 sfn_entry->fst_clus_lo = (uint16_t)new_cluster;
1183 sfn_entry->fst_clus_hi = (uint16_t)(new_cluster >> 16);
1186 const int entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
1187 uint32_t cur_sector = entry_sector;
1188 int cur_index = (int)entry_index;
1189 uint32_t remaining = total_slots;
1190 uint32_t temp_idx = 0;
1192 while (remaining > 0) {
1193 status = read_sector(cur_sector, sector_buf);
1202 int can = entries_per_sector - cur_index;
1203 int to_write = (remaining < (uint32_t)can) ? remaining : (uint32_t)can;
1205 for (
int j = 0; j < to_write; j++) {
1211 status = write_sector(cur_sector, sector_buf);
1219 remaining -= to_write;
1220 temp_idx += to_write;
1233 if (!fat32_find_free_dir_slots(parent_cluster, 1, &entry_sector, &entry_index)) {
1241 status = read_sector(entry_sector, sector_buf);
1246 kmemcpy(new_entry->name, sfn, 11);
1248 new_entry->fst_clus_lo = (uint16_t)new_cluster;
1249 new_entry->fst_clus_hi = (uint16_t)(new_cluster >> 16);
1251 status = write_sector(entry_sector, sector_buf);
1259static TIME_ENTRY convertFat32ToRealtime(uint16_t fat32Time, uint16_t fat32Date) {
1264 fat32_decode_date(fat32Date, &y, &mon, &day);
1265 fat32_decode_time(fat32Time, &
h, &m, &s);
1281 uint32_t first_cluster = 0;
1284 char parent_path_buf[260];
1285 char filename_buf[260];
1286 int last_slash = -1;
1287 for (
int len = 0; path[len] !=
'\0'; len++) {
1288 if (path[len] ==
'/') {
1293 if (last_slash == -1) {
1295 kstrcpy(parent_path_buf,
"/");
1296 kstrncpy(filename_buf, path,
sizeof(filename_buf) - 1);
1297 filename_buf[
sizeof(filename_buf) - 1] =
'\0';
1301 kstrncpy(filename_buf, &path[last_slash + 1],
sizeof(filename_buf) - 1);
1302 filename_buf[
sizeof(filename_buf) - 1] =
'\0';
1303 if (last_slash == 0) {
1305 kstrcpy(parent_path_buf,
"/");
1309 size_t parent_len = last_slash;
1310 if (parent_len >=
sizeof(parent_path_buf)) {
1311 parent_len =
sizeof(parent_path_buf) - 1;
1313 kmemcpy(parent_path_buf, path, parent_len);
1314 parent_path_buf[parent_len] =
'\0';
1318 char* filename = filename_buf;
1319 char* parent_path = parent_path_buf;
1323 if (!fat32_find_entry(parent_path, &parent_entry, NULL) || !(parent_entry.attr &
ATTR_DIRECTORY)) {
1326 uint32_t parent_cluster = (parent_entry.fst_clus_hi << 16) | parent_entry.fst_clus_lo;
1329 bool exists = fat32_find_entry(path, &existing_entry, NULL);
1332 uint32_t located_sector = 0;
1333 uint32_t located_index = 0;
1334 uint32_t located_consumed = 0;
1335 bool located =
false;
1339 uint32_t cluster = parent_cluster;
1341 uint32_t sector_lba = first_sector_of_cluster(cluster);
1342 for (uint32_t s = 0; s < fs.sectors_per_cluster; ++s) {
1343 status = read_sector(sector_lba + s, buf);
1346 uint32_t entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
1348 for (uint32_t j = 0; j < entries_per_sector; ) {
1349 uint8_t first = (uint8_t)entries[j].name[0];
1354 uint32_t consumed = 0;
1355 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], entries_per_sector - j, lfn_buf, &consumed);
1357 if (ci_equal(lfn_buf, filename)) {
1358 located_sector = sector_lba + s;
1360 located_consumed = consumed;
1372 cluster = fat32_read_fat(cluster);
1379 if (exists) first_cluster = (existing_entry.fst_clus_hi << 16) | existing_entry.fst_clus_lo;
1382 if (exists && first_cluster >= 2) {
1383 if (!fat32_free_cluster_chain(first_cluster)) {
1392 uint32_t cluster_size = fs.sectors_per_cluster * fs.bytes_per_sector;
1393 uint32_t clusters_needed = 0;
1394 uint32_t last_cluster = 0;
1395 uint32_t append_offset = 0;
1398 uint32_t cur = first_cluster;
1399 if (existing_entry.file_size > 0) {
1401 uint32_t next = fat32_read_fat(cur);
1405 append_offset = existing_entry.file_size % cluster_size;
1410 uint32_t bytes_fit = cluster_size - append_offset;
1411 if (size > bytes_fit) {
1412 clusters_needed = (size - bytes_fit + cluster_size - 1) / cluster_size;
1416 clusters_needed = (size + cluster_size - 1) / cluster_size;
1419 uint32_t first_new = 0;
1420 uint32_t prev_cluster = 0;
1421 for (uint32_t i = 0; i < clusters_needed; ++i) {
1422 uint32_t nc = fat32_find_free_cluster();
1424 if (first_new) fat32_free_cluster_chain(first_new);
1428 if (first_new == 0) first_new = nc;
1429 if (prev_cluster != 0) fat32_write_fat(prev_cluster, nc);
1432 if (prev_cluster != 0) fat32_write_fat(prev_cluster,
FAT32_EOC_MAX);
1435 if (last_cluster == 0) {
1436 first_cluster = first_new;
1439 fat32_write_fat(last_cluster, first_new);
1443 if (first_new != 0) first_cluster = first_new;
1448 if (first_new) fat32_free_cluster_chain(first_new);
1452 const uint8_t* src = (
const uint8_t*)data;
1453 uint32_t bytes_left = size;
1457 uint32_t sector_lba = first_sector_of_cluster(write_cluster);
1458 uint32_t start_offset_in_cluster = (write_cluster == last_cluster && append_offset > 0) ? append_offset : 0;
1460 for (uint32_t s = start_offset_in_cluster / fs.bytes_per_sector; s < fs.sectors_per_cluster && bytes_left > 0; ++s) {
1461 uint32_t off_in_sector = (s == start_offset_in_cluster / fs.bytes_per_sector) ? start_offset_in_cluster % fs.bytes_per_sector : 0;
1462 uint32_t to_write = fs.bytes_per_sector - off_in_sector;
1463 if (to_write > bytes_left) to_write = bytes_left;
1465 if (off_in_sector > 0 || to_write < fs.bytes_per_sector) {
1466 read_sector(sector_lba + s, sector_buf);
1468 kmemcpy((uint8_t*)sector_buf + off_in_sector, src, to_write);
1469 write_sector(sector_lba + s, sector_buf);
1472 bytes_left -= to_write;
1475 write_cluster = fat32_read_fat(write_cluster);
1482 format_short_name(filename, sfn);
1483 uint8_t checksum = lfn_checksum((uint8_t*)sfn);
1485 uint32_t lfn_count = (
kstrlen(filename) + 12) / 13;
1486 uint32_t total_entries = lfn_count + 1;
1490 if (first_cluster) fat32_free_cluster_chain(first_cluster);
1495 fat32_create_lfn_entries(entry_buf, filename, checksum);
1499 kmemcpy(sfn_entry->name, sfn, 11);
1500 sfn_entry->attr = 0;
1501 uint32_t final_size = size;
1503 sfn_entry->file_size = final_size;
1504 sfn_entry->fst_clus_lo = (uint16_t)first_cluster;
1505 sfn_entry->fst_clus_hi = (uint16_t)(first_cluster >> 16);
1510 if (exists && located) {
1515 status = read_sector(located_sector, delete_buf);
1518 for (uint32_t k = 0; k < located_consumed; ++k) {
1519 if ((located_index + k) < (fs.bytes_per_sector / 32)) {
1523 write_sector(located_sector, delete_buf);
1529 uint32_t entry_sector, entry_index;
1530 if (!fat32_find_free_dir_slots(parent_cluster, total_entries, &entry_sector, &entry_index)) {
1532 if (first_cluster) fat32_free_cluster_chain(first_cluster);
1541 uint32_t current_sector = entry_sector;
1542 uint32_t current_index_in_sector = entry_index;
1543 uint32_t entries_remaining = total_entries;
1544 uint8_t* source_entry = (uint8_t*)entry_buf;
1545 const uint32_t entries_per_sector = fs.bytes_per_sector / 32;
1547 while (entries_remaining > 0) {
1548 status = read_sector(current_sector, write_buf);
1555 uint32_t space_in_sector = entries_per_sector - current_index_in_sector;
1556 uint32_t entries_to_write = (entries_remaining < space_in_sector) ? entries_remaining : space_in_sector;
1558 kmemcpy((uint8_t*)write_buf + current_index_in_sector * 32, source_entry, entries_to_write * 32);
1560 status = write_sector(current_sector, write_buf);
1567 entries_remaining -= entries_to_write;
1568 source_entry += entries_to_write * 32;
1571 current_index_in_sector = 0;
1583 if (!fat32_find_entry(path, &dir_entry, NULL) || !(dir_entry.attr &
ATTR_DIRECTORY)) {
1584 gop_printf(0xFFFF0000,
"Error: Directory not found or path is not a directory: %s\n", path);
1588 uint32_t cluster = (uint32_t)((dir_entry.fst_clus_hi << 16) | dir_entry.fst_clus_lo);
1590 cluster = fs.root_cluster;
1596 if (max_len > 0) listings[0] =
'\0';
1600 uint32_t sector = first_sector_of_cluster(cluster);
1601 bool end_of_dir =
false;
1603 for (uint32_t i = 0; i < fs.sectors_per_cluster; ++i) {
1604 status = read_sector(sector + i, buf);
1608 uint32_t entries = fs.bytes_per_sector /
sizeof(*dir);
1610 for (uint32_t j = 0; j < entries; ) {
1619 (current_entry->name[0] ==
'.' && (current_entry->name[1] ==
'\0' || current_entry->name[1] ==
'.'))) {
1625 uint32_t consumed = 0;
1626 FAT32_DIR_ENTRY* sfn_entry = read_lfn(current_entry, entries - j, lfn_name, &consumed);
1630 ksnprintf(line_buf,
sizeof(line_buf),
"<DIR> %s\n", lfn_name);
1633 ksnprintf(line_buf,
sizeof(line_buf),
"%s (%u bytes)\n", lfn_name, sfn_entry->file_size);
1636 size_t avail = (used < max_len) ? (max_len - used) : 0;
1639 ksnprintf(listings + used, avail,
"%s", line_buf);
1649 if (end_of_dir)
break;
1652 if (end_of_dir)
break;
1654 cluster = fat32_read_fat(cluster);
1666 uint32_t parent_cluster = 0;
1667 fat32_find_entry(path, &entry, &parent_cluster);
1669 uint32_t dir_cluster = get_dir_cluster(&entry);
1670 if (dir_cluster == 0)
return false;
1673 if (!buf)
return false;
1675 uint32_t cluster = dir_cluster;
1678 uint32_t sector_lba = first_sector_of_cluster(cluster);
1679 for (uint32_t s = 0; s < fs.sectors_per_cluster; ++s) {
1680 status = read_sector(sector_lba + s, buf);
1684 uint32_t entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
1686 for (uint32_t j = 0; j < entries_per_sector; ) {
1687 uint8_t first = (uint8_t)entries[j].name[0];
1694 uint32_t consumed = 0;
1695 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], entries_per_sector - j, lfn_buf, &consumed);
1696 if (!sfn) { j++;
continue; }
1699 if ((
unsigned char)sfn->name[0] ==
'.') {
1709 cluster = fat32_read_fat(cluster);
1719static bool mark_entry_and_lfns_deleted(
const char* path, uint32_t parent_cluster) {
1721 char path_copy[260];
1722 kstrncpy(path_copy, path,
sizeof(path_copy));
1723 int len = (int)
kstrlen(path_copy);
1725 while (len > 1 && path_copy[len - 1] ==
'/') { path_copy[--len] =
'\0'; }
1727 int last_slash = -1;
1728 for (
int i = len - 1; i >= 0; --i) {
1729 if (path_copy[i] ==
'/') { last_slash = i;
break; }
1732 const char* filename = (last_slash == -1) ? path_copy : &path_copy[last_slash + 1];
1735 char sfn_formatted[11];
1736 format_short_name(filename, sfn_formatted);
1739 if (!buf)
return false;
1741 uint32_t cluster = parent_cluster;
1744 uint32_t sector_lba = first_sector_of_cluster(cluster);
1745 for (uint32_t s = 0; s < fs.sectors_per_cluster; ++s) {
1746 status = read_sector(sector_lba + s, buf);
1750 uint32_t entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
1752 for (uint32_t j = 0; j < entries_per_sector; ) {
1753 uint8_t first = (uint8_t)entries[j].name[0];
1759 uint32_t consumed = 0;
1760 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], entries_per_sector - j, lfn_buf, &consumed);
1767 if (
kstrcmp(lfn_buf, filename) == 0) {
1772 if (!match && ci_equal(lfn_buf, filename)) {
1777 if (!match && cmp_short_name(sfn->name, sfn_formatted)) {
1783 for (uint32_t k = 0; k < consumed; ++k) {
1788 bool ok = write_sector(sector_lba + s, buf);
1802 cluster = fat32_read_fat(cluster);
1814static bool fat32_rm_rf_dir(uint32_t dir_cluster) {
1816 if (dir_cluster == 0 || dir_cluster == fs.root_cluster)
return false;
1819 if (!buf)
return false;
1821 uint32_t cluster = dir_cluster;
1825 uint32_t sector_lba = first_sector_of_cluster(cluster);
1827 for (uint32_t s = 0; s < fs.sectors_per_cluster; ++s) {
1828 status = read_sector(sector_lba + s, buf);
1832 uint32_t entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
1834 for (uint32_t j = 0; j < entries_per_sector; ) {
1835 uint8_t first = (uint8_t)entries[j].name[0];
1842 goto free_and_return;
1850 uint32_t consumed = 0;
1851 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], entries_per_sector - j, lfn_name, &consumed);
1860 if ((
unsigned char)sfn->name[0] ==
'.') {
1867 uint32_t child_cluster = get_dir_cluster(sfn);
1868 if (child_cluster != 0 && child_cluster != 1 && child_cluster != dir_cluster) {
1870 if (!fat32_rm_rf_dir(child_cluster)) {
1878 for (uint32_t k = 0; k < consumed; ++k) {
1882 status = write_sector(sector_lba + s, buf);
1890 uint32_t file_cluster = get_dir_cluster(sfn);
1891 if (file_cluster >= 2) {
1892 if (!fat32_free_cluster_chain(file_cluster)) {
1898 for (uint32_t k = 0; k < consumed; ++k) {
1902 status = write_sector(sector_lba + s, buf);
1910 cluster = fat32_read_fat(cluster);
1915 if (!fat32_free_cluster_chain(dir_cluster)) {
1926 uint32_t parent_cluster;
1932 uint32_t dir_cluster = get_dir_cluster(&entry);
1933 if (dir_cluster == 0) dir_cluster = fs.root_cluster;
1948 uint8_t attr = entry->attr;
1958 uint32_t parent_cluster;
1959 if (!fat32_find_entry(path, &entry, &parent_cluster)) {
1964 if (!is_file(&entry)) {
1969 uint32_t file_cluster = get_dir_cluster(&entry);
1973 if (!fat32_free_cluster_chain(file_cluster)) {
1979 if (!mark_entry_and_lfns_deleted(path, parent_cluster)) {
FORCEINLINE int32_t InterlockedCompareExchange32(volatile int32_t *target, int32_t value, int32_t comparand)
FORCEINLINE int32_t InterlockedExchange32(volatile int32_t *target, int32_t value)
BLOCK_DEVICE * get_block_device(int index)
struct _BLOCK_DEVICE BLOCK_DEVICE
struct _GOP_PARAMS GOP_PARAMS
#define WRITE_MODE_APPEND_EXISTING
MTSTATUS fat32_init(int disk_index)
MTSTATUS fat32_create_directory(const char *path)
Creates a new directory (/testdir/ or /testdir are both allowed to create 'testdir' inside of 'root')
#define WRITE_MODE_CREATE_OR_REPLACE
MTSTATUS fat32_list_directory(const char *path, char *listings, size_t max_len)
Lists the directory given.
MTSTATUS fat32_delete_directory(const char *path)
This function deletes the directory given to the function from the system.
MTSTATUS fat32_read_file(const char *filename, uint32_t *file_size_out, void **buffer_out)
A FAT32 Function that reads the file requested into a dynamically allocated buffer.
MTSTATUS fat32_write_file(const char *path, const void *data, uint32_t size, uint32_t mode)
Creates a new file and writes data to it.
MTSTATUS fat32_delete_file(const char *path)
This function deletes the file given to the function from the system.
void fat32_list_root(void)
bool fat32_directory_is_empty(const char *path)
This function returns if the directory given to the function is empty (e.g, has only '....
volatile int32_t fat32_called_from_scanner
#define DELETED_DIR_ENTRY
struct _FAT32_FSINFO FAT32_FSINFO
#define FAT32_FREE_CLUSTER
size_t kstrlen(const char *str)
void gop_printf(uint32_t color, const char *fmt,...)
int ksnprintf(char *buf, size_t bufsize, const char *fmt,...)
char * kstrtok_r(char *str, const char *delim, char **save_ptr)
char * kstrcpy(char *dst, const char *src)
char * kstrncpy(char *dst, const char *src, size_t n)
int kstrcmp(const char *s1, const char *s2)
struct _ACPI_SDT_HEADER h
FORCEINLINE void * kmemcpy(void *dest, const void *src, size_t len)
FORCEINLINE void * kmemset(void *dest, int64_t val, uint64_t len)
struct _SPINLOCK SPINLOCK
#define MT_FAT32_DIRECTORY_NOT_FOUND
#define MT_GENERAL_FAILURE
#define MT_FAT32_PARENT_PATH_NOT_FOUND
#define MT_FAT32_CLUSTERS_FULL
#define MT_FAT32_DIRECTORY_ALREADY_EXISTS
#define MT_FAILURE(Status)
#define MT_FAT32_INVALID_WRITE_MODE
#define MT_FAT32_INVALID_FILENAME
#define MT_FAT32_CLUSTER_NOT_FOUND
#define MT_FAT32_FILE_NOT_FOUND
#define MT_FAT32_PARENT_PATH_NOT_DIR
#define MT_FAT32_INVALID_CLUSTER
#define MT_SUCCEEDED(Status)
Macros to test status.
#define MT_FAT32_DIR_FULL
void MmFreePool(IN void *buf)
void * MmAllocatePoolWithTag(IN enum _POOL_TYPE PoolType, IN size_t NumberOfBytes, IN uint32_t Tag)
void MsAcquireSpinlock(IN PSPINLOCK lock, IN PIRQL OldIrql)
void MsReleaseSpinlock(IN PSPINLOCK lock, IN IRQL OldIrql)