17#define WRITE_MODE_APPEND_EXISTING 0
18#define WRITE_MODE_CREATE_OR_REPLACE 1
20#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
21#define le32toh(x) __builtin_bswap32(x)
31static SPINLOCK fat32_read_fat_lock = { 0 };
32static SPINLOCK fat32_write_fat_lock = { 0 };
33static void* fat_cache_buf = NULL;
35static uint32_t fat_cache_sector = UINT32_MAX;
37#define MAX_LFN_ENTRIES 20
38#define MAX_LFN_LEN 260
43#define FAT32_READ_ERROR 0xFFFFFFFFu
49static MTSTATUS read_sector(uint32_t lba,
void* buf) {
51 size_t NumberOfBytes = fs.bytes_per_sector;
52 if (!NumberOfBytes) NumberOfBytes = 512;
54 if (NumberOfBytes % 512 != 0) {
59 return disk->read_sector(disk, lba, buf, NumberOfBytes);
63static MTSTATUS write_sector(uint32_t lba,
const void* buf) {
65 size_t NumberOfBytes = fs.bytes_per_sector;
66 if (!NumberOfBytes) NumberOfBytes = 512;
68 if (NumberOfBytes % 512 != 0) {
73 return disk->write_sector(disk, lba, buf, NumberOfBytes);
77static uint8_t lfn_checksum(
const uint8_t short_name[11]) {
79 for (
int i = 0; i < 11; i++) {
80 sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + short_name[i];
86static inline int toupper(
int c) {
87 if (c >=
'a' && c <=
'z') {
88 return c - (
'a' -
'A');
94static bool cmp_name(
const char* str_1,
const char* str_2) {
96 for (
int i = 0; i < 11; i++) { t[i] = str_1[i]; }
97 for (
int i = 0; i < 11; i++) {
98 if (toupper(t[i]) != toupper(str_2[i])) {
107static void format_short_name(
const char* input,
char out[11]) {
109 for (
int i = 0; i < 11; ++i) out[i] =
' ';
112 const unsigned char* p = (
const unsigned char*)input;
113 while (*p && *p !=
'.' && ni < 8) {
114 out[ni++] = (char)toupper(*p++);
120 while (*p && ei < 3) {
121 out[8 + ei++] = (char)toupper(*p++);
134 if (!cur || remaining == 0)
return NULL;
139 uint32_t lfn_count = 0;
143 while (i < remaining && ((uint8_t)cur[i].name[0] != 0x00) && (cur[i].attr ==
ATTR_LONG_NAME)) {
149 if (i >= remaining)
return NULL;
151 if ((uint8_t)short_entry->name[0] == 0x00 || (uint8_t)short_entry->name[0] == 0xE5) {
157 if (lfn_count == 0) {
159 const unsigned char* s = (
const unsigned char*)short_entry->name;
163 for (
int n = 0; n < 8; ++n) {
164 if (s[n] ==
' ')
break;
165 if (pos < (
int)
MAX_LFN_LEN - 1) out_name[pos++] = s[n];
169 bool has_ext =
false;
170 for (
int n = 8; n < 11; ++n)
if (s[n] !=
' ') { has_ext =
true;
break; }
172 if (pos < (
int)
MAX_LFN_LEN - 1) out_name[pos++] =
'.';
173 for (
int n = 8; n < 11; ++n) {
174 if (s[n] ==
' ')
break;
175 if (pos < (
int)
MAX_LFN_LEN - 1) out_name[pos++] = s[n];
179 out_name[pos] =
'\0';
185 uint8_t cs = lfn_checksum((uint8_t*)short_entry->name);
186 for (uint32_t j = 0; j < lfn_count; ++j) {
187 uint8_t entry_checksum = *((uint8_t*)lfn_list[j] + 13);
188 if (entry_checksum != cs)
return NULL;
193 for (
int j = (
int)lfn_count - 1; j >= 0; --j) {
194 uint8_t* ebytes = (uint8_t*)lfn_list[j];
197 uint16_t* name1 = (uint16_t*)(ebytes + 1);
198 for (
int c = 0; c < 5; ++c) {
199 uint16_t ch = name1[c];
200 if (ch == 0x0000) { out_name[pos] =
'\0';
goto done; }
204 if (ch <= 0x7F) out_name[pos++] = (char)ch;
else out_name[pos++] =
'?';
208 uint16_t* name2 = (uint16_t*)(ebytes + 14);
209 for (
int c = 0; c < 6; ++c) {
210 uint16_t ch = name2[c];
211 if (ch == 0x0000) { out_name[pos] =
'\0';
goto done; }
215 if (ch <= 0x7F) out_name[pos++] = (char)ch;
else out_name[pos++] =
'?';
219 uint16_t* name3 = (uint16_t*)(ebytes + 28);
220 for (
int c = 0; c < 2; ++c) {
221 uint16_t ch = name3[c];
222 if (ch == 0x0000) { out_name[pos] =
'\0';
goto done; }
226 if (ch <= 0x7F) out_name[pos++] = (char)ch;
else out_name[pos++] =
'?';
231 out_name[pos] =
'\0';
233 *out_consumed = (uint32_t)lfn_count + 1;
237static inline uint32_t fat32_total_clusters(
void) {
238 return (bpb.total_sectors_32 - fs.first_data_sector) / fs.sectors_per_cluster;
242static uint32_t fat32_read_fat(uint32_t cluster) {
257 if (!fat_cache_buf) {
259 if (!fat_cache_buf) {
260 gop_printf(0xFFFF0000,
"fat32_read_fat: couldn't alloc cache buf\n");
269 uint32_t fat_offset = cluster * 4;
270 uint32_t fat_sector = fs.fat_start + (fat_offset / fs.bytes_per_sector);
271 uint32_t ent_offset = fat_offset % fs.bytes_per_sector;
272 uint32_t bps = fs.bytes_per_sector;
275 if (fat_cache_sector != fat_sector) {
276 MTSTATUS st = read_sector(fat_sector, fat_cache_buf);
278 gop_printf(0xFFFF0000,
"fat32_read_fat: read_sector fail for sector %u\n", fat_sector);
285 fat_cache_sector = fat_sector;
291 if (ent_offset <= bps - 4) {
293 kmemcpy(&raw, (uint8_t*)fat_cache_buf + ent_offset,
sizeof(raw));
295 val = raw & 0x0FFFFFFF;
302 gop_printf(0xFFFF0000,
"fat32_read_fat: couldn't alloc secondary cache buf\n");
313 gop_printf(0xFFFF0000,
"fat32_read_fat: read_sector fail for next sector %u\n", fat_sector + 1);
322 size_t first = bps - ent_offset;
323 kmemcpy(tmp, (uint8_t*)fat_cache_buf + ent_offset, first);
325 kmemcpy(&raw, tmp,
sizeof(raw));
327 val = raw & 0x0FFFFFFF;
331 if (val == cluster) {
333 gop_printf(0xFFFF0000,
"FAT suspicious: cluster=%u -> raw=0x%08x (ent_off=%u, fat_sector=%u, total=%u)\n",
334 cluster, raw, ent_offset, fat_sector, fat32_total_clusters());
347static inline uint32_t first_sector_of_cluster(uint32_t cluster) {
348 return fs.first_data_sector + (cluster - 2) * fs.sectors_per_cluster;
352static bool fat32_write_fat(uint32_t cluster, uint32_t value) {
355 uint32_t fat_offset = cluster * 4;
356 uint32_t sec_index = fat_offset / fs.bytes_per_sector;
357 uint32_t ent_offset = fat_offset % fs.bytes_per_sector;
358 uint32_t bps = fs.bytes_per_sector;
359 if (bps == 0) {
gop_printf(0xFFFF0000,
"fat32_write_fat: bps==0!\n");
MsReleaseSpinlock(&fat32_write_fat_lock, oldIrql);
return false; }
366 gop_printf(0x00FF00FF,
"fat32_write_fat: alloc buf1=%p bps=%u ent_off=%u sec=%u\n", buf1, bps, ent_offset, sec_index);
369 bool spans = (ent_offset > bps - 4);
380 for (uint32_t fat_i = 0; fat_i < bpb.num_fats; ++fat_i) {
381 uint32_t current_fat_base = fs.fat_start + (fat_i * fs.sectors_per_fat);
382 uint32_t sector1_lba = current_fat_base + sec_index;
383 uint32_t sector2_lba = sector1_lba + 1;
393 uint8_t value_bytes[4];
394 kmemcpy(value_bytes, &value, 4);
396 size_t first_part_size = bps - ent_offset;
397 size_t second_part_size = 4 - first_part_size;
399 kmemcpy((uint8_t*)buf1 + ent_offset, value_bytes, first_part_size);
400 kmemcpy(buf2, value_bytes + first_part_size, second_part_size);
403 if (
MT_FAILURE(write_sector(sector1_lba, buf1)) ||
MT_FAILURE(write_sector(sector2_lba, buf2))) {
410 if (
MT_FAILURE(read_sector(sector1_lba, buf1))) { ok =
false;
break; }
414 kmemcpy(&raw_le, (uint8_t*)buf1 + ent_offset,
sizeof(raw_le));
415 uint32_t raw =
le32toh(raw_le);
418 raw = (raw & 0xF0000000) | (value & 0x0FFFFFFF);
421 uint32_t new_le =
le32toh(raw);
422 kmemcpy((uint8_t*)buf1 + ent_offset, &new_le,
sizeof(new_le));
424 if (
MT_FAILURE(write_sector(sector1_lba, buf1))) { ok =
false;
break; }
438 return ((uint32_t)entry->fst_clus_hi << 16) | entry->fst_clus_lo;
442static bool fat32_free_cluster_chain(uint32_t start_cluster) {
443 if (start_cluster < 2 || start_cluster >=
FAT32_EOC_MIN)
return false;
445 uint32_t cur = start_cluster;
447 uint32_t next = fat32_read_fat(cur);
448 if (next == cur || next == 0) {
449 gop_printf(0xFFFF0000,
"Detected FAT self-loop/zero at %u -> %u | %s\n", cur, next, __func__);
455 if (next == cur)
break;
461static uint32_t fat32_find_free_cluster(
void) {
466 uint32_t total_clusters = fat32_total_clusters();
468 for (uint32_t i = 2; i < total_clusters; i++) {
469 retval = fat32_read_fat(i);
485static bool zero_cluster(uint32_t cluster) {
488 if (!buf)
return false;
489 kmemset(buf, 0, fs.bytes_per_sector);
491 uint32_t sector = first_sector_of_cluster(cluster);
492 for (uint32_t i = 0; i < fs.sectors_per_cluster; i++) {
493 status = write_sector(sector + i, buf);
505static bool cmp_short_name(
const char* dir_name,
const char short_name[11]) {
506 for (
int i = 0; i < 11; ++i) {
507 if ((
unsigned char)dir_name[i] != (
unsigned char)short_name[i])
return false;
513static inline bool ci_equal(
const char* a,
const char* b) {
516 if (la != lb)
return false;
517 for (
size_t i = 0; i < la; ++i) {
518 if ((
char)toupper((
int)a[i]) != (
char)toupper((
int)b[i]))
return false;
524static uint32_t fat32_create_lfn_entries(
FAT32_LFN_ENTRY* entry_buffer,
const char* long_name, uint8_t sfn_checksum) {
525 uint32_t len =
kstrlen(long_name);
526 uint32_t num_lfn_entries = (len + 12) / 13;
527 uint32_t char_idx = 0;
529 for (
int i = (
int)num_lfn_entries - 1; i >= 0; --i) {
535 uint8_t seq = (uint8_t)(num_lfn_entries - i);
536 if (i == (
int)num_lfn_entries - 1)
546 for (
int k = 0; k < 13; ++k) {
547 uint16_t uch = 0xFFFF;
549 uch = (uint8_t)long_name[char_idx];
550 else if (char_idx == len)
565 return num_lfn_entries;
576static bool fat32_find_entry(
const char* path,
FAT32_DIR_ENTRY* out_entry, uint32_t* out_parent_cluster) {
578 kstrncpy(path_copy, path,
sizeof(path_copy));
580 uint32_t current_cluster = fs.root_cluster;
581 uint32_t parent_cluster_of_last_found = fs.root_cluster;
583 if (
kstrcmp(path_copy,
"/") == 0 || path_copy[0] ==
'\0') {
587 out_entry->fst_clus_lo = (uint16_t)(fs.root_cluster & 0xFFFF);
588 out_entry->fst_clus_hi = (uint16_t)(fs.root_cluster >> 16);
590 if (out_parent_cluster) *out_parent_cluster = fs.root_cluster;
596 bool any_token_found =
false;
598 char* save_ptr = NULL;
599 char* token =
kstrtok_r(path_copy,
"/", &save_ptr);
602 if (!sector_buf)
return false;
604 while (token != NULL) {
605 bool found_this_token =
false;
606 parent_cluster_of_last_found = current_cluster;
608 uint32_t search_cluster = current_cluster;
610 uint32_t sector = first_sector_of_cluster(search_cluster);
611 for (uint32_t i = 0; i < fs.sectors_per_cluster; i++) {
612 MTSTATUS status = read_sector(sector + i, sector_buf);
618 for (uint32_t j = 0; j < num_entries; ) {
625 uint32_t consumed = 0;
626 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], num_entries - j, lfn_buf, &consumed);
630 if (ci_equal(lfn_buf, token)) {
632 found_this_token =
true;
633 current_cluster = (sfn->fst_clus_hi << 16) | sfn->fst_clus_lo;
634 goto token_search_done;
637 j += (consumed > 0) ? consumed : 1;
641 search_cluster = fat32_read_fat(search_cluster);
647 if (!found_this_token) {
650 any_token_found =
true;
658 if (any_token_found) {
660 if (out_parent_cluster) *out_parent_cluster = parent_cluster_of_last_found;
667static bool fat32_extend_directory(uint32_t dir_cluster) {
668 uint32_t new_cluster = fat32_find_free_cluster();
669 if (new_cluster == 0)
return false;
672 if (!zero_cluster(new_cluster)) {
680 uint32_t current = dir_cluster;
686 return fat32_write_fat(current, new_cluster);
689static bool fat32_find_free_dir_slots(uint32_t dir_cluster, uint32_t count, uint32_t* out_sector, uint32_t* out_entry_index) {
690 uint32_t current_cluster = dir_cluster;
692 if (!sector_buf)
return false;
696 uint32_t sector_lba = first_sector_of_cluster(current_cluster);
697 for (uint32_t i = 0; i < fs.sectors_per_cluster; i++) {
698 status = read_sector(sector_lba + i, sector_buf);
705 uint32_t consecutive_free = 0;
707 for (uint32_t j = 0; j < num_entries; j++) {
708 uint8_t first_byte = (uint8_t)entries[j].name[0];
710 if (consecutive_free == 0) {
712 *out_sector = sector_lba + i;
713 *out_entry_index = j;
716 if (consecutive_free == count) {
722 consecutive_free = 0;
727 uint32_t next_cluster = fat32_read_fat(current_cluster);
730 if (fat32_extend_directory(dir_cluster)) {
731 return fat32_find_free_dir_slots(dir_cluster, count, out_sector, out_entry_index);
737 current_cluster = next_cluster;
744static MTSTATUS fat32_update_file_entry(
const char* path, uint32_t start_cluster, uint32_t new_size,
bool update_cluster,
bool update_size) {
746 kstrncpy(path_copy, path,
sizeof(path_copy));
750 uint32_t current_cluster = fs.root_cluster;
751 char* save_ptr = NULL;
752 char* token =
kstrtok_r(path_copy,
"/", &save_ptr);
755 uint32_t buf_size = fs.bytes_per_sector * 2;
759 while (token != NULL) {
760 char* next_token =
kstrtok_r(NULL,
"/", &save_ptr);
761 bool is_target_file = (next_token == NULL);
762 bool found_component =
false;
763 uint32_t search_cluster = current_cluster;
766 uint32_t sector_lba = first_sector_of_cluster(search_cluster);
768 for (uint32_t i = 0; i < fs.sectors_per_cluster; i++) {
770 MTSTATUS st = read_sector(sector_lba + i, big_buf);
774 if (i < fs.sectors_per_cluster - 1) {
775 read_sector(sector_lba + i + 1, (uint8_t*)big_buf + fs.bytes_per_sector);
778 kmemset((uint8_t*)big_buf + fs.bytes_per_sector, 0, fs.bytes_per_sector);
782 uint32_t num_entries_to_scan = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
785 for (uint32_t j = 0; j < num_entries_to_scan; ) {
790 uint32_t consumed = 0;
791 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], total_entries_in_buf - j, lfn_buf, &consumed);
794 if (ci_equal(lfn_buf, token)) {
795 if (is_target_file) {
799 if (update_cluster) {
800 sfn->fst_clus_hi = (uint16_t)((start_cluster >> 16) & 0xFFFF);
801 sfn->fst_clus_lo = (uint16_t)(start_cluster & 0xFFFF);
806 sfn->file_size = new_size;
810 uintptr_t offset = (uintptr_t)sfn - (uintptr_t)big_buf;
811 uint32_t target_sector = sector_lba + i;
812 void* write_source = big_buf;
814 if (offset >= fs.bytes_per_sector) {
815 target_sector = sector_lba + i + 1;
816 write_source = (uint8_t*)big_buf + fs.bytes_per_sector;
819 MTSTATUS wr_st = write_sector(target_sector, write_source);
824 current_cluster = ((uint32_t)sfn->fst_clus_hi << 16) | sfn->fst_clus_lo;
825 found_component =
true;
830 j += (consumed > 0) ? consumed : 1;
833 search_cluster = fat32_read_fat(search_cluster);
837 if (!found_component) {
850#define BPB_SECTOR_START 2048
862 kmemcpy(&bpb, buf,
sizeof(bpb));
865 fs.bytes_per_sector = bpb.bytes_per_sector;
866 fs.sectors_per_cluster = bpb.sectors_per_cluster;
867 fs.reserved_sector_count = bpb.reserved_sector_count;
868 fs.sectors_per_fat = bpb.fat_size_32;
869 fs.root_cluster = bpb.root_cluster;
871 fs.first_data_sector = fs.fat_start + bpb.num_fats * fs.sectors_per_fat;
878 uint32_t cluster = fs.root_cluster;
885 uint32_t lfn_accum = 0;
888 uint32_t sector = first_sector_of_cluster(cluster);
889 for (uint32_t i = 0; i < fs.sectors_per_cluster; ++i) {
890 status = read_sector(sector + i, buf);
896 uint32_t entries = fs.bytes_per_sector /
sizeof(*dir);
898 for (uint32_t j = 0; j < entries; ++j, ++dir) {
899 uint8_t first = (uint8_t)dir->name[0];
928 uint32_t consumed = 0;
935 real = read_lfn(temp_entries, lfn_accum + 1, bufferLfn, &consumed);
942 uint32_t remaining = entries - j;
943 real = read_lfn(&dir[0], remaining, bufferLfn, &consumed);
949 gop_printf(0xFF00FFFF,
"Found: %s\n", bufferLfn);
954 for (
int k = 0; k < 11; ++k) fallback[k] = dir->name[k];
956 gop_printf(0xFF00FFFF,
"Found (raw): %s\n", fallback);
963 cluster = fat32_read_fat(cluster);
968static bool is_filename_in_dir(
const char* filename) {
969 if (!filename)
return false;
972 if (*filename ==
'/')
return true;
979static uint32_t extract_dir_cluster(
const char* filename) {
981 if (!filename || filename[0] ==
'\0')
return fs.root_cluster;
985 kstrncpy(path_copy, filename,
sizeof(path_copy));
988 int len = (int)
kstrlen(path_copy);
989 while (len > 1 && path_copy[len - 1] ==
'/') {
990 path_copy[len - 1] =
'\0';
996 for (
int i = len - 1; i >= 0; --i) {
997 if (path_copy[i] ==
'/') { last_slash = i;
break; }
1001 if (last_slash == -1) {
1002 return fs.root_cluster;
1007 if (last_slash == 0) {
1013 for (
int i = 0; i < last_slash; ++i) parent[i] = path_copy[i];
1014 parent[last_slash] =
'\0';
1019 if (!fat32_find_entry(parent, &parent_entry, NULL))
return 0;
1024 uint32_t cluster = ((uint32_t)parent_entry.fst_clus_hi << 16) | parent_entry.fst_clus_lo;
1025 if (cluster == 0) cluster = fs.root_cluster;
1031 IN uint64_t FileOffset,
1033 IN size_t BufferSize,
1037 if (BytesRead) *BytesRead = 0;
1040 uint32_t bytes_per_sector = fs.bytes_per_sector;
1041 uint32_t sectors_per_cluster = fs.sectors_per_cluster;
1042 uint32_t cluster_size = bytes_per_sector * sectors_per_cluster;
1045 uint32_t current_cluster = (uint32_t)(uintptr_t)FileObject->FsContext;
1046 uint32_t clusters_to_skip = FileOffset / cluster_size;
1048 for (uint32_t i = 0; i < clusters_to_skip; i++) {
1049 current_cluster = fat32_read_fat(current_cluster);
1056 FileObject->CurrentOffset = FileOffset;
1061 if (!IntermediateBuffer) {
1065 size_t total_bytes_read = 0;
1066 size_t bytes_left = BufferSize;
1067 uint32_t current_file_offset = FileOffset;
1068 uint8_t* current_buffer_ptr = (uint8_t*)Buffer;
1071 while (bytes_left > 0) {
1073 uint32_t offset_in_cluster = current_file_offset % cluster_size;
1074 uint32_t sector_index_in_cluster = offset_in_cluster / bytes_per_sector;
1076 uint32_t lba = fs.first_data_sector + ((current_cluster - 2) * sectors_per_cluster) + sector_index_in_cluster;
1079 uint32_t offset_in_sector = current_file_offset % bytes_per_sector;
1080 uint32_t bytes_available_in_sector = bytes_per_sector - offset_in_sector;
1083 size_t bytes_to_copy = (bytes_left < bytes_available_in_sector) ? bytes_left : bytes_available_in_sector;
1086 bool direct_read = (offset_in_sector == 0) && (bytes_left >= bytes_per_sector);
1088 void* target_buf = direct_read ? current_buffer_ptr : IntermediateBuffer;
1090 status = read_sector(lba, target_buf);
1099 kmemcpy(current_buffer_ptr, (uint8_t*)IntermediateBuffer + offset_in_sector, bytes_to_copy);
1103 total_bytes_read += bytes_to_copy;
1104 bytes_left -= bytes_to_copy;
1105 current_buffer_ptr += bytes_to_copy;
1106 current_file_offset += bytes_to_copy;
1110 if (bytes_left > 0 && (current_file_offset % cluster_size) == 0) {
1111 current_cluster = fat32_read_fat(current_cluster);
1123 if (IntermediateBuffer) {
1128 *BytesRead = total_bytes_read;
1138 if (fat32_find_entry(path, NULL, NULL)) {
1140 gop_printf(0xFFFF0000,
"Error: Path '%s' already exists.\n", path);
1146 char path_copy[260];
1147 kstrncpy(path_copy, path,
sizeof(path_copy));
1149 char* new_dir_name = NULL;
1150 char* parent_path =
"/";
1154 while (len > 1 && path_copy[len - 1] ==
'/') {
1155 path_copy[len - 1] =
'\0';
1160 int last_slash = -1;
1161 for (
int i = 0; path_copy[i] !=
'\0'; i++) {
1162 if (path_copy[i] ==
'/') last_slash = i;
1166 if (last_slash != -1) {
1167 new_dir_name = &path_copy[last_slash + 1];
1168 if (last_slash > 0) {
1169 path_copy[last_slash] =
'\0';
1170 parent_path = path_copy;
1176 new_dir_name = path_copy;
1182 uint32_t parent_cluster;
1183 if (!fat32_find_entry(parent_path, &parent_entry, NULL)) {
1185 gop_printf(0xFFFF0000,
"Error: Parent path '%s' not found.\n", parent_path);
1191 gop_printf(0xFFFF0000,
"Error: Parent path is not a directory. PATH: %s\n", parent_path);
1195 parent_cluster = (parent_entry.fst_clus_hi << 16) | parent_entry.fst_clus_lo;
1198 uint32_t new_cluster = fat32_find_free_cluster();
1202 zero_cluster(new_cluster);
1207 kmemset(sector_buf, 0, fs.bytes_per_sector);
1210 kmemcpy(dot_entries[0].name,
". ", 11);
1212 dot_entries[0].fst_clus_lo = (uint16_t)new_cluster;
1213 dot_entries[0].fst_clus_hi = (uint16_t)(new_cluster >> 16);
1215 kmemcpy(dot_entries[1].name,
".. ", 11);
1217 dot_entries[1].fst_clus_lo = (uint16_t)parent_cluster;
1218 dot_entries[1].fst_clus_hi = (uint16_t)(parent_cluster >> 16);
1220 write_sector(first_sector_of_cluster(new_cluster), sector_buf);
1225 format_short_name(new_dir_name, sfn);
1228 int name_len =
kstrlen(new_dir_name);
1230 if (name_len > 11) need_lfn = 1;
1232 for (
int i = 0; i < name_len; i++) {
1233 char c = new_dir_name[i];
1234 if (c >=
'a' && c <=
'z') { need_lfn = 1;
break; }
1238 uint32_t entry_sector = 0, entry_index = 0;
1242 uint8_t checksum = lfn_checksum((uint8_t*)sfn);
1243 uint32_t num_lfn_entries = (name_len + 12) / 13;
1244 uint32_t total_slots = num_lfn_entries + 1;
1246 if (!fat32_find_free_dir_slots(parent_cluster, total_slots, &entry_sector, &entry_index)) {
1255 if (!temp_entries) {
1264 fat32_create_lfn_entries(temp_entries, new_dir_name, checksum);
1269 kmemcpy(sfn_entry->name, sfn, 11);
1271 sfn_entry->fst_clus_lo = (uint16_t)new_cluster;
1272 sfn_entry->fst_clus_hi = (uint16_t)(new_cluster >> 16);
1275 const int entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
1276 uint32_t cur_sector = entry_sector;
1277 int cur_index = (int)entry_index;
1278 uint32_t remaining = total_slots;
1279 uint32_t temp_idx = 0;
1281 while (remaining > 0) {
1282 status = read_sector(cur_sector, sector_buf);
1291 int can = entries_per_sector - cur_index;
1292 int to_write = (remaining < (uint32_t)can) ? remaining : (uint32_t)can;
1294 for (
int j = 0; j < to_write; j++) {
1300 status = write_sector(cur_sector, sector_buf);
1308 remaining -= to_write;
1309 temp_idx += to_write;
1322 if (!fat32_find_free_dir_slots(parent_cluster, 1, &entry_sector, &entry_index)) {
1330 status = read_sector(entry_sector, sector_buf);
1335 kmemcpy(new_entry->name, sfn, 11);
1337 new_entry->fst_clus_lo = (uint16_t)new_cluster;
1338 new_entry->fst_clus_hi = (uint16_t)(new_cluster >> 16);
1340 status = write_sector(entry_sector, sector_buf);
1348static TIME_ENTRY convertFat32ToRealtime(uint16_t fat32Time, uint16_t fat32Date) {
1353 fat32_decode_date(fat32Date, &y, &mon, &day);
1354 fat32_decode_time(fat32Time, &
h, &m, &s);
1366 IN uint64_t FileOffset,
1368 IN size_t BufferSize,
1372 if (BytesWritten) *BytesWritten = 0;
1375 uint32_t bytes_per_sector = fs.bytes_per_sector;
1376 uint32_t sectors_per_cluster = fs.sectors_per_cluster;
1377 uint32_t cluster_size = bytes_per_sector * sectors_per_cluster;
1381 if (FileObject->FsContext == 0) {
1383 uint32_t first_cluster = fat32_find_free_cluster();
1384 if (first_cluster == 0) {
1392 zero_cluster(first_cluster);
1395 MTSTATUS update_st = fat32_update_file_entry(FileObject->FileName, first_cluster, 0,
true,
false);
1404 FileObject->FsContext = (
void*)(uintptr_t)first_cluster;
1408 uint32_t current_cluster = (uint32_t)(uintptr_t)FileObject->FsContext;
1409 uint32_t clusters_to_skip = FileOffset / cluster_size;
1411 for (uint32_t i = 0; i < clusters_to_skip; i++) {
1412 current_cluster = fat32_read_fat(current_cluster);
1422 if (!IntermediateBuffer) {
1426 size_t total_bytes_written = 0;
1427 size_t bytes_left = BufferSize;
1428 uint32_t current_file_offset = FileOffset;
1429 const uint8_t* src_buffer_ptr = (
const uint8_t*)Buffer;
1432 while (bytes_left > 0) {
1434 uint32_t offset_in_cluster = current_file_offset % cluster_size;
1435 uint32_t sector_index_in_cluster = offset_in_cluster / bytes_per_sector;
1436 uint32_t lba = fs.first_data_sector + ((current_cluster - 2) * sectors_per_cluster) + sector_index_in_cluster;
1439 uint32_t offset_in_sector = current_file_offset % bytes_per_sector;
1440 uint32_t bytes_available_in_sector = bytes_per_sector - offset_in_sector;
1441 size_t bytes_to_write = (bytes_left < bytes_available_in_sector) ? bytes_left : bytes_available_in_sector;
1445 bool full_sector_overwrite = (offset_in_sector == 0) && (bytes_to_write == bytes_per_sector);
1447 if (full_sector_overwrite) {
1449 status = write_sector(lba, (
void*)src_buffer_ptr);
1453 status = read_sector(lba, IntermediateBuffer);
1457 kmemcpy((uint8_t*)IntermediateBuffer + offset_in_sector, src_buffer_ptr, bytes_to_write);
1460 status = write_sector(lba, IntermediateBuffer);
1466 total_bytes_written += bytes_to_write;
1467 bytes_left -= bytes_to_write;
1468 src_buffer_ptr += bytes_to_write;
1469 current_file_offset += bytes_to_write;
1472 if (bytes_left > 0 && (current_file_offset % cluster_size) == 0) {
1473 uint32_t next_cluster = fat32_read_fat(current_cluster);
1478 uint32_t new_c = fat32_find_free_cluster();
1484 zero_cluster(new_c);
1485 fat32_write_fat(current_cluster, new_c);
1488 current_cluster = new_c;
1492 current_cluster = next_cluster;
1498 FileObject->CurrentOffset = current_file_offset;
1501 if (current_file_offset > FileObject->FileSize) {
1502 FileObject->FileSize = current_file_offset;
1505 fat32_update_file_entry(FileObject->FileName, 0, (uint32_t)FileObject->FileSize,
false,
true);
1508 if (IntermediateBuffer) {
1513 *BytesWritten = total_bytes_written;
1521 IN const char* path,
1526 IN const char* path,
1532 uint32_t parent_cluster_check;
1534 if (fat32_find_entry(path, &existing_entry, &parent_cluster_check)) {
1541 return fat32_open_file(path, FileObjectOut);
1545 char parent_path[260];
1548 int last_slash = -1;
1551 for (
int i = len - 1; i >= 0; i--) {
1552 if (path[i] ==
'/') {
1558 if (last_slash == -1) {
1561 parent_path[0] =
'/';
1562 parent_path[1] =
'\0';
1566 int p_len = (last_slash == 0) ? 1 : last_slash;
1567 for (
int i = 0; i < p_len; i++) parent_path[i] = path[i];
1568 parent_path[p_len] =
'\0';
1571 kstrncpy(filename, &path[last_slash + 1], 260);
1576 uint32_t parent_dir_cluster;
1579 if (
kstrcmp(parent_path,
"/") == 0) {
1580 parent_dir_cluster = fs.root_cluster;
1583 if (!fat32_find_entry(parent_path, &parent_entry, &parent_dir_cluster)) {
1586 parent_dir_cluster = get_dir_cluster(&parent_entry);
1591 format_short_name(filename, sfn);
1594 if (sfn[6] ==
' ') { sfn[6] =
'~'; sfn[7] =
'1'; }
1595 else { sfn[6] =
'~'; sfn[7] =
'1'; }
1597 uint8_t checksum = lfn_checksum((uint8_t*)sfn);
1600 uint32_t lfn_count = (
kstrlen(filename) + 12) / 13;
1601 uint32_t total_entries = lfn_count + 1;
1606 fat32_create_lfn_entries(entry_buf, filename, checksum);
1612 kmemcpy(sfn_entry->name, sfn, 11);
1614 sfn_entry->file_size = 0;
1615 sfn_entry->fst_clus_hi = 0;
1616 sfn_entry->fst_clus_lo = 0;
1620 uint32_t sector_lba;
1621 uint32_t entry_index;
1623 if (!fat32_find_free_dir_slots(parent_dir_cluster, total_entries, §or_lba, &entry_index)) {
1637 MTSTATUS status = read_sector(sector_lba, sector_buf);
1646 uint32_t total_bytes_to_write = total_entries * entry_size;
1647 uint32_t offset_in_sector = entry_index * entry_size;
1648 uint32_t bytes_available_in_sector = fs.bytes_per_sector - offset_in_sector;
1650 if (total_bytes_to_write <= bytes_available_in_sector) {
1653 kmemcpy((uint8_t*)sector_buf + offset_in_sector, entry_buf, total_bytes_to_write);
1656 status = write_sector(sector_lba, sector_buf);
1660 kmemcpy((uint8_t*)sector_buf + offset_in_sector, entry_buf, bytes_available_in_sector);
1661 status = write_sector(sector_lba, sector_buf);
1667 uint32_t next_sector_lba = sector_lba + 1;
1669 status = read_sector(next_sector_lba, sector_buf);
1672 uint32_t bytes_remaining = total_bytes_to_write - bytes_available_in_sector;
1675 kmemcpy(sector_buf, (uint8_t*)entry_buf + bytes_available_in_sector, bytes_remaining);
1678 status = write_sector(next_sector_lba, sector_buf);
1691 return fat32_open_file(path, FileObjectOut);
1698 if (!fat32_find_entry(path, &dir_entry, NULL) || !(dir_entry.attr &
ATTR_DIRECTORY)) {
1699 gop_printf(0xFFFF0000,
"Error: Directory not found or path is not a directory: %s\n", path);
1703 uint32_t cluster = (uint32_t)((dir_entry.fst_clus_hi << 16) | dir_entry.fst_clus_lo);
1705 cluster = fs.root_cluster;
1711 if (max_len > 0) listings[0] =
'\0';
1715 uint32_t sector = first_sector_of_cluster(cluster);
1716 bool end_of_dir =
false;
1718 for (uint32_t i = 0; i < fs.sectors_per_cluster; ++i) {
1719 status = read_sector(sector + i, buf);
1723 uint32_t entries = fs.bytes_per_sector /
sizeof(*dir);
1725 for (uint32_t j = 0; j < entries; ) {
1734 (current_entry->name[0] ==
'.' && (current_entry->name[1] ==
'\0' || current_entry->name[1] ==
'.'))) {
1740 uint32_t consumed = 0;
1741 FAT32_DIR_ENTRY* sfn_entry = read_lfn(current_entry, entries - j, lfn_name, &consumed);
1745 ksnprintf(line_buf,
sizeof(line_buf),
"<DIR> %s\n", lfn_name);
1748 ksnprintf(line_buf,
sizeof(line_buf),
"%s (%u bytes)\n", lfn_name, sfn_entry->file_size);
1751 size_t avail = (used < max_len) ? (max_len - used) : 0;
1754 ksnprintf(listings + used, avail,
"%s", line_buf);
1764 if (end_of_dir)
break;
1767 if (end_of_dir)
break;
1769 cluster = fat32_read_fat(cluster);
1781 uint32_t parent_cluster = 0;
1782 fat32_find_entry(path, &entry, &parent_cluster);
1784 uint32_t dir_cluster = get_dir_cluster(&entry);
1785 if (dir_cluster == 0)
return false;
1788 if (!buf)
return false;
1790 uint32_t cluster = dir_cluster;
1793 uint32_t sector_lba = first_sector_of_cluster(cluster);
1794 for (uint32_t s = 0; s < fs.sectors_per_cluster; ++s) {
1795 status = read_sector(sector_lba + s, buf);
1799 uint32_t entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
1801 for (uint32_t j = 0; j < entries_per_sector; ) {
1802 uint8_t first = (uint8_t)entries[j].name[0];
1809 uint32_t consumed = 0;
1810 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], entries_per_sector - j, lfn_buf, &consumed);
1811 if (!sfn) { j++;
continue; }
1814 if ((
unsigned char)sfn->name[0] ==
'.') {
1824 cluster = fat32_read_fat(cluster);
1834static bool mark_entry_and_lfns_deleted(
const char* path, uint32_t parent_cluster) {
1836 char path_copy[260];
1837 kstrncpy(path_copy, path,
sizeof(path_copy));
1838 int len = (int)
kstrlen(path_copy);
1840 while (len > 1 && path_copy[len - 1] ==
'/') { path_copy[--len] =
'\0'; }
1842 int last_slash = -1;
1843 for (
int i = len - 1; i >= 0; --i) {
1844 if (path_copy[i] ==
'/') { last_slash = i;
break; }
1847 const char* filename = (last_slash == -1) ? path_copy : &path_copy[last_slash + 1];
1850 char sfn_formatted[11];
1851 format_short_name(filename, sfn_formatted);
1854 if (!buf)
return false;
1856 uint32_t cluster = parent_cluster;
1859 uint32_t sector_lba = first_sector_of_cluster(cluster);
1860 for (uint32_t s = 0; s < fs.sectors_per_cluster; ++s) {
1861 status = read_sector(sector_lba + s, buf);
1865 uint32_t entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
1867 for (uint32_t j = 0; j < entries_per_sector; ) {
1868 uint8_t first = (uint8_t)entries[j].name[0];
1874 uint32_t consumed = 0;
1875 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], entries_per_sector - j, lfn_buf, &consumed);
1882 if (
kstrcmp(lfn_buf, filename) == 0) {
1887 if (!match && ci_equal(lfn_buf, filename)) {
1892 if (!match && cmp_short_name(sfn->name, sfn_formatted)) {
1898 for (uint32_t k = 0; k < consumed; ++k) {
1903 bool ok = write_sector(sector_lba + s, buf);
1917 cluster = fat32_read_fat(cluster);
1929static bool fat32_rm_rf_dir(uint32_t dir_cluster) {
1931 if (dir_cluster == 0 || dir_cluster == fs.root_cluster)
return false;
1934 if (!buf)
return false;
1936 uint32_t cluster = dir_cluster;
1940 uint32_t sector_lba = first_sector_of_cluster(cluster);
1942 for (uint32_t s = 0; s < fs.sectors_per_cluster; ++s) {
1943 status = read_sector(sector_lba + s, buf);
1947 uint32_t entries_per_sector = fs.bytes_per_sector /
sizeof(
FAT32_DIR_ENTRY);
1949 for (uint32_t j = 0; j < entries_per_sector; ) {
1950 uint8_t first = (uint8_t)entries[j].name[0];
1957 goto free_and_return;
1965 uint32_t consumed = 0;
1966 FAT32_DIR_ENTRY* sfn = read_lfn(&entries[j], entries_per_sector - j, lfn_name, &consumed);
1975 if ((
unsigned char)sfn->name[0] ==
'.') {
1982 uint32_t child_cluster = get_dir_cluster(sfn);
1983 if (child_cluster != 0 && child_cluster != 1 && child_cluster != dir_cluster) {
1985 if (!fat32_rm_rf_dir(child_cluster)) {
1993 for (uint32_t k = 0; k < consumed; ++k) {
1997 status = write_sector(sector_lba + s, buf);
2005 uint32_t file_cluster = get_dir_cluster(sfn);
2006 if (file_cluster >= 2) {
2007 if (!fat32_free_cluster_chain(file_cluster)) {
2013 for (uint32_t k = 0; k < consumed; ++k) {
2017 status = write_sector(sector_lba + s, buf);
2025 cluster = fat32_read_fat(cluster);
2030 if (!fat32_free_cluster_chain(dir_cluster)) {
2041 uint32_t parent_cluster;
2047 uint32_t dir_cluster = get_dir_cluster(&entry);
2048 if (dir_cluster == 0) dir_cluster = fs.root_cluster;
2063 uint8_t attr = entry->attr;
2073 uint32_t parent_cluster;
2074 if (!fat32_find_entry(path, &entry, &parent_cluster)) {
2079 if (!is_file(&entry)) {
2084 uint32_t file_cluster = get_dir_cluster(&entry);
2088 if (!fat32_free_cluster_chain(file_cluster)) {
2094 if (!mark_entry_and_lfns_deleted(path, parent_cluster)) {
2102 IN const char* path,
2109 uint32_t parent_cluster;
2110 if (!fat32_find_entry(path, &entry, &parent_cluster)) {
2115 if (!is_file(&entry)) {
2120 uint32_t file_cluster = get_dir_cluster(&entry);
2130 size_t length =
kstrlen(path) + 1;
2136 FileObject->
FileSize = entry.file_size;
2138 FileObject->
FsContext = (
void*)(uintptr_t)file_cluster;
2142 *FileObjectOut = FileObject;
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
MTSTATUS fat32_create_file(IN const char *path, OUT PFILE_OBJECT *FileObjectOut)
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')
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(IN PFILE_OBJECT FileObject, IN uint64_t FileOffset, OUT void *Buffer, IN size_t BufferSize, _Out_Opt size_t *BytesRead)
MTSTATUS fat32_write_file(IN PFILE_OBJECT FileObject, IN uint64_t FileOffset, IN void *Buffer, IN size_t BufferSize, _Out_Opt size_t *BytesWritten)
MTSTATUS fat32_delete_file(const char *path)
This function deletes the file given to the function from the system.
void fat32_deletion_routine(void *Object)
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
struct _FILE_OBJECT * PFILE_OBJECT
struct _FILE_OBJECT FILE_OBJECT
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 * 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_FILENAME
#define MT_FAT32_FILE_NOT_FOUND
#define MT_FAT32_PARENT_PATH_NOT_DIR
#define MT_SUCCEEDED(Status)
Macros to test status.
#define MT_FAT32_DIR_FULL
MTSTATUS ObCreateObject(IN POBJECT_TYPE ObjectType, IN uint32_t ObjectSize, OUT void **ObjectCreated)
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)