2 * FAT12/16/32 Filesystem Driver
5 * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include <exception.h>
27 const char driver_name[] = "fatfs";
29 static dword_t fatfs_mount(const char *device, const char *mountpoint, dword_t flags);
30 static dword_t fatfs_unmount(mounted_volume_t *volume);
31 static dword_t fatfs_load_file(file_t **file);
32 static dword_t fatfs_unload_file(file_t *file);
33 static dword_t fatfs_open_file(file_instance_t **instance);
34 static dword_t fatfs_close_file(file_instance_t *instance);
35 static dword_t fatfs_delete_file(mounted_volume_t *volume, const char *path, bool_t purge);
36 static dword_t fatfs_read_file(file_instance_t *file, void *buffer, qword_t offset, size_t length, size_t *bytes_read);
37 static dword_t fatfs_write_file(file_instance_t *file, const void *buffer, qword_t offset, size_t length, size_t *bytes_written);
38 static dword_t fatfs_list_dir(file_instance_t *directory, char *filename, bool_t continue_scan);
39 static dword_t fatfs_set_file(file_t *file, dword_t info_type, const void *buffer, size_t size);
41 static dword_t fatfs_read_internal(object_t *obj, void *buffer, qword_t offset, size_t length, size_t *bytes_read);
42 static dword_t fatfs_write_internal(object_t *obj, const void *buffer, qword_t offset, size_t length, size_t *bytes_written);
44 static fs_driver_t fatfs_driver =
48 .unmount = fatfs_unmount,
49 .load_file = fatfs_load_file,
50 .unload_file = fatfs_unload_file,
51 .open_file = fatfs_open_file,
52 .close_file = fatfs_close_file,
53 .delete_file = fatfs_delete_file,
54 .read_file = fatfs_read_file,
55 .write_file = fatfs_write_file,
56 .list_dir = fatfs_list_dir,
57 .set_file = fatfs_set_file
60 static void fatfs_get_entry_name(fatfs_dirent_t *dirent, char *name)
62 byte_t *src = dirent->filename;
64 byte_t *last_name_ptr = &dirent->filename[7];
65 byte_t *last_ext_ptr = &dirent->extension[2];
67 while (*last_name_ptr == ' ' && last_name_ptr >= dirent->filename) last_name_ptr--;
68 while (*last_ext_ptr == ' ' && last_ext_ptr >= dirent->extension) last_ext_ptr--;
69 while (src <= last_name_ptr) *dest++ = *src++;
71 src = dirent->extension;
72 if (src <= last_ext_ptr) *dest++ = '.';
73 while (src <= last_ext_ptr) *dest++ = *src++;
77 static bool_t fatfs_check_name(const char *name)
79 const char *illegal = "\"*+,/:;<=>?[\\]|";
81 size_t count_before = 0;
82 size_t count_after = 0;
86 if (strrchr(illegal, *name) || (*name >= 'a' && *name <= 'z')) return FALSE;
91 if (num_dots > 1) return FALSE;
93 else if (num_dots == 0)
96 if (count_before > 8) return FALSE;
101 if (count_after > 3) return FALSE;
110 static void fatfs_set_entry_name(fatfs_dirent_t *dirent, const char *name)
112 const char *src = name;
113 byte_t *dest = dirent->filename;
115 while (*src != '.' && *src != '\0') *dest++ = toupper(*src++);
116 while (dest < &dirent->filename[8]) *dest++ = ' ';
121 dest = dirent->extension;
122 while (*src != '\0') *dest++ = toupper(*src++);
126 static inline void fatfs_pack_file_time(clock_time_t *os_time, word_t *date, word_t *time)
128 if (date) *date = (os_time->year << 9) | (os_time->month << 5) | os_time->day;
129 if (time) *time = (os_time->hours << 11) | (os_time->minutes << 5) | (os_time->seconds >> 1);
132 static inline void fatfs_unpack_file_time(word_t date, word_t time, clock_time_t *os_time)
134 os_time->day = date & 0x1F;
135 os_time->month = (date >> 5) & 0x0F;
136 os_time->year = (date >> 9) & 0x7F;
137 os_time->seconds = (time & 0x1F) << 1;
138 os_time->minutes = (time >> 5) & 0x3F;
139 os_time->hours = (time >> 11) & 0x1F;
142 static dword_t fatfs_get_next_cluster(fatfs_volume_t *volume, dword_t cluster)
144 qword_t entry_offset = (qword_t)(volume->reserved_sectors * volume->bytes_per_sector);
146 switch (volume->type)
149 entry_offset += (qword_t)(cluster + (cluster >> 1));
153 entry_offset += (qword_t)(cluster << 1);
157 entry_offset += (qword_t)(cluster << 2);
163 dword_t ret = device_read(volume->header.device,
166 (volume->type == FAT32) ? sizeof(dword_t) : sizeof(word_t),
168 if (ret != ERR_SUCCESS) return FATFS_INVALID_CLUSTER;
170 switch (volume->type)
173 entry = ((cluster & 1) ? (entry >> 4) : entry) & 0xFFF;
174 if (entry >= 0xFF0) entry |= FATFS_INVALID_CLUSTER;
179 if (entry >= 0xFFF0) entry |= FATFS_INVALID_CLUSTER;
184 if (entry >= 0x0FFFFFF0) entry |= FATFS_INVALID_CLUSTER;
188 if (entry == 0) entry = FATFS_INVALID_CLUSTER;
192 static dword_t fatfs_set_next_cluster(fatfs_volume_t *volume, dword_t cluster, dword_t next)
194 qword_t entry_offset = (qword_t)(volume->reserved_sectors * volume->bytes_per_sector);
196 switch (volume->type)
200 entry_offset += (qword_t)(cluster + (cluster >> 1));
205 entry_offset += (qword_t)(cluster << 1);
210 entry_offset += (qword_t)(cluster << 2);
216 if (volume->type == FAT12)
219 dword_t ret = device_read(volume->header.device, (byte_t*)&entry, entry_offset, sizeof(word_t), &bytes_read);
220 if (ret != ERR_SUCCESS) return ret;
222 entry &= 0xF000 >> ((cluster & 1) * 12);
223 entry |= next << ((cluster & 1) * 4);
230 dword_t bytes_written;
231 return device_write(volume->header.device,
234 (volume->type == FAT32) ? sizeof(dword_t) : sizeof(word_t),
238 static qword_t fatfs_get_cluster_offset(fatfs_volume_t *volume, dword_t number)
240 qword_t sector = (qword_t)(number - volume->root_dir_cluster)
241 * (qword_t)volume->sectors_per_cluster
242 + (qword_t)volume->reserved_sectors
243 + (qword_t)(volume->num_fats * volume->sectors_per_fat);
244 qword_t offset = sector * (qword_t)volume->bytes_per_sector;
246 if (number != volume->root_dir_cluster)
248 offset += (qword_t)(volume->num_root_dirents * sizeof(fatfs_dirent_t));
254 static dword_t fatfs_read_cluster(fatfs_volume_t *volume, dword_t number, void *buffer)
257 return device_read(volume->header.device,
259 fatfs_get_cluster_offset(volume, number),
260 volume->sectors_per_cluster * volume->bytes_per_sector,
264 static dword_t fatfs_zero_cluster(fatfs_volume_t *volume, dword_t number)
266 byte_t *buffer = __builtin_alloca(volume->sectors_per_cluster * volume->bytes_per_sector);
267 memset(buffer, 0, volume->sectors_per_cluster * volume->bytes_per_sector);
269 dword_t bytes_written;
270 return device_write(volume->header.device,
272 fatfs_get_cluster_offset(volume, number),
273 volume->sectors_per_cluster * volume->bytes_per_sector,
277 static dword_t fatfs_get_free_cluster(fatfs_volume_t *volume, dword_t *cluster)
279 dword_t starting_cluster = volume->last_free_cluster;
283 if (fatfs_get_next_cluster(volume, volume->last_free_cluster) == FATFS_FREE_CLUSTER)
285 *cluster = volume->last_free_cluster;
289 volume->last_free_cluster++;
290 volume->last_free_cluster %= volume->total_clusters;
291 if (volume->last_free_cluster <= volume->root_dir_cluster) volume->last_free_cluster = volume->root_dir_cluster + 1;
293 while (volume->last_free_cluster != starting_cluster);
298 static dword_t fatfs_find_entry(fatfs_volume_t *volume, const char *path, dword_t *cluster_num, dword_t *entry_num, fatfs_dirent_t *dirent)
300 dword_t ret = ERR_SUCCESS;
302 byte_t *cluster_buffer = NULL;
303 char path_copy[MAX_PATH];
304 fatfs_dirent_t root_dirent =
306 .attributes = FATFS_ATTR_DIRECTORY,
307 .first_cluster_high = volume->root_dir_cluster >> 16,
308 .first_cluster_low = volume->root_dir_cluster & 0xFFFF,
309 .size = volume->num_root_dirents * sizeof(fatfs_dirent_t)
314 if (cluster_num) *cluster_num = (dword_t)-1;
315 if (entry_num) *entry_num = (dword_t)-1;
316 if (dirent) *dirent = root_dirent;
320 dword_t cluster_size = volume->sectors_per_cluster * volume->bytes_per_sector;
321 cluster_buffer = (byte_t*)malloc(cluster_size);
323 if (cluster_buffer == NULL)
329 dword_t previous_cluster = (dword_t)-1;
330 dword_t current_cluster = volume->root_dir_cluster;
331 dword_t current_index = 0;
332 fatfs_dirent_t current_dirent = root_dirent;
334 char *token, *endptr;
335 strcpy(path_copy, path);
337 for (token = strtok_r(path_copy, PATH_DELIMITER_STRING, &endptr); token != NULL; token = strtok_r(NULL, PATH_DELIMITER_STRING, &endptr))
339 if (!(current_dirent.attributes & FATFS_ATTR_DIRECTORY))
347 ret = fatfs_read_cluster(volume, current_cluster, cluster_buffer);
348 if (ret != ERR_SUCCESS) goto cleanup;
350 fatfs_dirent_t *entries = (fatfs_dirent_t*)cluster_buffer;
351 dword_t num_entries = cluster_size / sizeof(fatfs_dirent_t);
353 for (i = 0; i < num_entries; i++)
355 if (!(entries[i].attributes & FATFS_ATTR_VOLUME_ID)
356 && entries[i].filename[0] != 0
357 && entries[i].filename[0] != FATFS_DELETED)
360 fatfs_get_entry_name(&entries[i], filename);
361 if (strcmp(token, filename) == 0) break;
365 previous_cluster = current_cluster;
367 if (i != num_entries)
369 current_cluster = entries[i].first_cluster_low | (entries[i].first_cluster_high << 16);
371 current_dirent = entries[i];
375 current_cluster = fatfs_get_next_cluster(volume, current_cluster);
376 if (current_cluster >= FATFS_INVALID_CLUSTER)
384 if (cluster_num) *cluster_num = previous_cluster;
385 if (entry_num) *entry_num = current_index;
386 if (dirent) *dirent = current_dirent;
389 if (cluster_buffer) free(cluster_buffer);
393 static dword_t fatfs_resize_file(fatfs_file_t *file, qword_t new_size)
397 fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
399 if (new_size == file->header.size) return ERR_SUCCESS;
401 dword_t cluster_size = volume->sectors_per_cluster * volume->bytes_per_sector;
402 dword_t num_clusters_old = (file->header.size + cluster_size - 1) / cluster_size;
403 dword_t num_clusters_new = (new_size + cluster_size - 1) / cluster_size;
405 dword_t prev_cluster = FATFS_FREE_CLUSTER;
406 dword_t current_cluster = file->first_cluster;
408 if (num_clusters_new > num_clusters_old)
410 while (current_cluster != FATFS_FREE_CLUSTER && current_cluster < FATFS_INVALID_CLUSTER)
412 prev_cluster = current_cluster;
413 current_cluster = fatfs_get_next_cluster(volume, current_cluster);
416 dword_t new_clusters = num_clusters_new - num_clusters_old;
417 while (new_clusters--)
420 ret = fatfs_get_free_cluster(volume, &new_cluster);
421 if (ret != ERR_SUCCESS) break;
423 ret = fatfs_zero_cluster(volume, new_cluster);
424 if (ret != ERR_SUCCESS)
426 fatfs_set_next_cluster(volume, new_cluster, FATFS_BAD_CLUSTER);
431 if (prev_cluster == FATFS_FREE_CLUSTER)
433 file->first_cluster = new_cluster;
437 ret = fatfs_set_next_cluster(volume, prev_cluster, new_cluster);
438 if (ret != ERR_SUCCESS) break;
441 prev_cluster = new_cluster;
444 ret = fatfs_set_next_cluster(volume, prev_cluster, FATFS_LAST_CLUSTER);
446 else if (num_clusters_new < num_clusters_old)
448 while (num_clusters_new--)
450 prev_cluster = current_cluster;
451 current_cluster = fatfs_get_next_cluster(volume, current_cluster);
452 if (current_cluster >= FATFS_INVALID_CLUSTER) break;
455 if (prev_cluster == FATFS_FREE_CLUSTER)
457 file->first_cluster = 0;
461 ret = fatfs_set_next_cluster(volume, prev_cluster, FATFS_LAST_CLUSTER);
464 while (current_cluster < FATFS_INVALID_CLUSTER)
466 dword_t next_cluster = fatfs_get_next_cluster(volume, current_cluster);
467 ret = fatfs_set_next_cluster(volume, current_cluster, FATFS_FREE_CLUSTER);
468 if (ret != ERR_SUCCESS) break;
469 current_cluster = next_cluster;
473 clock_time_t current_time;
474 syscall(SYSCALL_CLOCK_GET_TIME, ¤t_time);
476 file->header.size = new_size;
477 fatfs_dirent_t dirent;
479 ret = device_read(volume->header.device,
481 fatfs_get_cluster_offset(volume, file->dirent_cluster) + (qword_t)file->dirent_index * sizeof(fatfs_dirent_t),
482 sizeof(fatfs_dirent_t),
484 if (ret != ERR_SUCCESS) return ret;
486 dirent.size = file->header.size;
487 dirent.first_cluster_low = file->first_cluster & 0xFFFF;
488 dirent.first_cluster_high = file->first_cluster >> 16;
489 fatfs_pack_file_time(¤t_time, &dirent.modification_date, &dirent.modification_time);
491 return device_write(volume->header.device,
493 fatfs_get_cluster_offset(volume, file->dirent_cluster) + (qword_t)file->dirent_index * sizeof(fatfs_dirent_t),
494 sizeof(fatfs_dirent_t),
498 static inline dword_t fatfs_rw_file(object_t *object, byte_t *buffer, qword_t offset, size_t length, size_t *bytes, bool_t write)
503 fatfs_file_instance_t *instance;
505 if (object->type == OBJECT_FILE_INSTANCE)
507 instance = CONTAINER_OF(CONTAINER_OF(object, file_instance_t, header), fatfs_file_instance_t, header);
508 file = CONTAINER_OF(instance->header.global, fatfs_file_t, header);
512 ASSERT(object->type == OBJECT_FILE);
513 file = CONTAINER_OF(CONTAINER_OF(object, file_t, header), fatfs_file_t, header);
517 fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
521 if (bytes) *bytes = 0;
525 if (offset > 0xFFFFFFFFULL)
527 if (bytes) *bytes = 0;
531 if (write && (offset + (qword_t)length) < file->header.size)
533 ret = fatfs_resize_file(file, offset + (qword_t)length);
534 if (ret != ERR_SUCCESS) return ret;
537 if (file->header.size == 0)
539 if (bytes) *bytes = 0;
543 dword_t offset_low = (dword_t)offset;
544 dword_t cluster_size = volume->sectors_per_cluster * volume->bytes_per_sector;
545 dword_t current_cluster = file->first_cluster;
547 while (offset_low >= cluster_size)
549 current_cluster = fatfs_get_next_cluster(volume, current_cluster);
550 if (current_cluster >= FATFS_INVALID_CLUSTER)
552 if (bytes) *bytes = 0;
556 offset_low -= cluster_size;
561 dword_t amount = MIN(length - count, cluster_size - offset_low);
563 if (amount == 0) break;
567 ret = device_write(volume->header.device,
569 fatfs_get_cluster_offset(volume, current_cluster) + (qword_t)offset_low,
576 ret = device_read(volume->header.device,
578 fatfs_get_cluster_offset(volume, current_cluster) + (qword_t)offset_low,
583 if (ret != ERR_SUCCESS) goto cleanup;
588 current_cluster = fatfs_get_next_cluster(volume, current_cluster);
589 if (current_cluster >= FATFS_INVALID_CLUSTER) break;
592 ret = (count == length) ? ERR_SUCCESS : ERR_BEYOND;
595 if (bytes) *bytes = count;
599 static dword_t fatfs_read_internal(object_t *obj, void *buffer, qword_t offset, size_t length, size_t *bytes_read)
601 return fatfs_rw_file(obj, buffer, offset, length, bytes_read, FALSE);
604 static dword_t fatfs_write_internal(object_t *obj, const void *buffer, qword_t offset, size_t length, size_t *bytes_written)
606 return fatfs_rw_file(obj, (void*)buffer, offset, length, bytes_written, TRUE);
609 static dword_t fatfs_mount(const char *device, const char *mountpoint, dword_t flags)
613 device_t *block_device = get_block_device(device);
614 if (block_device == NULL) return ERR_NOTFOUND;
616 dword_t ret = device_read(block_device, (byte_t*)&bpb, 0ULL, sizeof(fatfs_bpb_t), NULL);
617 if (ret != ERR_SUCCESS) return ret;
618 if (bpb.sectors_per_cluster == 0) return ERR_INVALID;
620 dword_t total_sectors;
621 if (bpb.total_sectors) total_sectors = bpb.total_sectors;
622 else total_sectors = bpb.total_sectors_32;
624 dword_t sectors_per_fat;
625 if (bpb.sectors_per_fat) sectors_per_fat = bpb.sectors_per_fat;
626 else sectors_per_fat = bpb.ext_bpb_32.sectors_per_fat;
628 dword_t root_dir_size = (bpb.num_dirent * sizeof(fatfs_dirent_t) + bpb.bytes_per_sector - 1) / bpb.bytes_per_sector;
629 dword_t total_clusters = (total_sectors - bpb.reserved_sectors - bpb.num_fats * sectors_per_fat - root_dir_size) / bpb.sectors_per_cluster;
631 if (total_clusters < 4086) type = FAT12;
632 else if (total_clusters < 65525) type = FAT16;
635 if ((type != FAT32 && bpb.ext_bpb.signature != 0x28 && bpb.ext_bpb.signature != 0x29)
636 || (type == FAT32 && bpb.ext_bpb_32.signature != 0x28 && bpb.ext_bpb_32.signature != 0x29))
641 fatfs_volume_t *volume = (fatfs_volume_t*)malloc(sizeof(fatfs_volume_t));
642 if (volume == NULL) return ERR_NOMEMORY;
644 volume->header.device = get_block_device(device);
645 volume->header.mountpoint = strdup(mountpoint);
646 volume->header.driver = &fatfs_driver;
648 volume->bytes_per_sector = bpb.bytes_per_sector;
649 volume->sectors_per_cluster = bpb.sectors_per_cluster;
650 volume->reserved_sectors = bpb.reserved_sectors;
651 volume->root_dir_cluster = (type == FAT32) ? bpb.ext_bpb_32.root_dir_cluster : 2;
652 volume->num_root_dirents = bpb.num_dirent;
653 volume->num_fats = bpb.num_fats;
654 volume->sectors_per_fat = sectors_per_fat;
655 volume->total_clusters = total_clusters;
656 volume->last_free_cluster = volume->root_dir_cluster + 1;
657 volume->owner_uid = get_current_uid();
659 ret = register_mounted_volume(&volume->header);
660 if (ret != ERR_SUCCESS) free(volume);
665 static dword_t fatfs_unmount(mounted_volume_t *volume)
667 dword_t ret = unregister_mounted_volume(volume);
668 if (ret != ERR_SUCCESS) return ret;
670 free(volume->mountpoint);
675 static dword_t fatfs_load_file(file_t **_file)
677 fatfs_file_t *file = (fatfs_file_t*)realloc(*_file, sizeof(fatfs_file_t));
678 if (file == NULL) return ERR_NOMEMORY;
679 *_file = &file->header;
681 fatfs_dirent_t dirent;
682 dword_t cluster, entry;
683 fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
685 dword_t ret = fatfs_find_entry(volume, file->header.path, &cluster, &entry, &dirent);
687 if (ret == ERR_NOTFOUND && (file->header.global_mode & FILE_MODE_CREATE))
691 char *parent_path = __builtin_alloca(strlen(file->header.path) + 1);
692 strcpy(parent_path, file->header.path);
694 char *file_name = NULL;
695 char *last_slash = strrchr(parent_path, '/');
699 file_name = last_slash + 1;
704 file_name = file->header.path;
707 if (!fatfs_check_name(file_name)) return ERR_INVALID;
709 fatfs_dirent_t parent_dirent;
710 dword_t parent_cluster, parent_entry;
712 ret = fatfs_find_entry(volume, parent_path, &parent_cluster, &parent_entry, &parent_dirent);
713 if (ret != ERR_SUCCESS) return ret;
715 dword_t entries_per_cluster = (volume->sectors_per_cluster * volume->bytes_per_sector) / sizeof(fatfs_dirent_t);
716 fatfs_dirent_t *entries = (fatfs_dirent_t*)malloc(volume->sectors_per_cluster * volume->bytes_per_sector);
717 if (entries == NULL) return ERR_NOMEMORY;
719 dword_t prev_cluster = FATFS_FREE_CLUSTER;
720 dword_t current_cluster = parent_dirent.first_cluster_low | (parent_dirent.first_cluster_high << 16);
724 if (current_cluster == FATFS_FREE_CLUSTER || (current_cluster >= FATFS_END_CLUSTER))
727 ret = fatfs_get_free_cluster(volume, &new_cluster);
728 if (ret != ERR_SUCCESS) break;
730 ret = fatfs_zero_cluster(volume, new_cluster);
731 if (ret != ERR_SUCCESS)
733 fatfs_set_next_cluster(volume, new_cluster, FATFS_BAD_CLUSTER);
737 if (prev_cluster == FATFS_FREE_CLUSTER)
739 parent_dirent.first_cluster_low = new_cluster & 0xFFFF;
740 parent_dirent.first_cluster_high = new_cluster >> 16;
744 ret = fatfs_set_next_cluster(volume, prev_cluster, new_cluster);
745 if (ret != ERR_SUCCESS) break;
748 current_cluster = new_cluster;
751 ret = fatfs_read_cluster(volume, current_cluster, entries);
752 if (ret != ERR_SUCCESS) break;
754 bool_t found = FALSE;
756 for (i = 0; i < entries_per_cluster; i++)
758 if (entries[i].filename[0] == '\0' || entries[i].filename[0] == FATFS_DELETED)
760 cluster = current_cluster;
769 prev_cluster = current_cluster;
770 current_cluster = fatfs_get_next_cluster(volume, current_cluster);
774 if (ret != ERR_SUCCESS) return ret;
776 clock_time_t current_time;
777 syscall(SYSCALL_CLOCK_GET_TIME, ¤t_time);
779 dirent.attributes = 0;
780 if (!(file->header.attributes & FILE_ATTR_OWNER_WRITABLE)) dirent.attributes |= FATFS_ATTR_READONLY;
781 if (file->header.attributes & FILE_ATTR_DIRECTORY) dirent.attributes |= FATFS_ATTR_DIRECTORY;
783 fatfs_set_entry_name(&dirent, file_name);
785 fatfs_pack_file_time(¤t_time, &dirent.creation_date, &dirent.creation_time);
786 fatfs_pack_file_time(¤t_time, &dirent.modification_date, &dirent.modification_time);
787 fatfs_pack_file_time(¤t_time, &dirent.last_accessed_date, NULL);
788 dirent.first_cluster_high = 0;
789 dirent.first_cluster_low = 0;
792 dword_t actually_written;
793 ret = device_write(volume->header.device,
795 fatfs_get_cluster_offset(volume, cluster) + (qword_t)(entry * sizeof(fatfs_dirent_t)),
796 sizeof(fatfs_dirent_t),
798 if (ret != ERR_SUCCESS) return ret;
801 file->header.attributes = FILE_ATTR_OWNER_READABLE;
802 if (!(dirent.attributes & FATFS_ATTR_READONLY)) file->header.attributes |= FILE_ATTR_OWNER_WRITABLE;
803 if (dirent.attributes & FATFS_ATTR_DIRECTORY) file->header.attributes |= FILE_ATTR_DIRECTORY;
805 file->header.size = dirent.size;
806 file->first_cluster = dirent.first_cluster_low | (dirent.first_cluster_high << 16);
807 file->dirent_cluster = cluster;
808 file->dirent_index = entry;
810 init_cache(&file->cache,
812 volume->bytes_per_sector,
813 (read_write_buffer_proc_t)fatfs_read_internal,
814 (read_write_buffer_proc_t)fatfs_write_internal);
819 static dword_t fatfs_purge_file(fatfs_volume_t *volume, dword_t starting_cluster)
821 dword_t current_cluster = starting_cluster;
825 dword_t next_cluster = fatfs_get_next_cluster(volume, current_cluster);
826 fatfs_set_next_cluster(volume, current_cluster, 0);
827 current_cluster = next_cluster;
833 static dword_t fatfs_unload_file(file_t *_file)
835 fatfs_file_t *file = CONTAINER_OF(_file, fatfs_file_t, header);
836 fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
838 if (file->header.attributes & FILE_ATTR_DELETED)
840 return fatfs_purge_file(volume, file->first_cluster);
844 return flush_cache(&file->cache, &file->header.header);
848 static dword_t fatfs_open_file(file_instance_t **_instance)
850 fatfs_file_t *file = CONTAINER_OF((*_instance)->global, fatfs_file_t, header);
852 fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
853 if (get_current_uid() != volume->owner_uid) return ERR_FORBIDDEN;
855 fatfs_file_instance_t *instance = (fatfs_file_instance_t*)realloc(*_instance, sizeof(fatfs_file_instance_t));
856 if (instance == NULL) return ERR_NOMEMORY;
857 *_instance = &instance->header;
859 instance->last_offset = 0;
860 instance->last_cluster = file->first_cluster;
864 static dword_t fatfs_close_file(file_instance_t *_instance)
869 static dword_t fatfs_delete_file(mounted_volume_t *_volume, const char *path, bool_t purge)
871 fatfs_volume_t *volume = CONTAINER_OF(volume, fatfs_volume_t, header);
872 if (get_current_uid() != volume->owner_uid) return ERR_FORBIDDEN;
874 fatfs_dirent_t dirent;
878 dword_t ret = fatfs_find_entry(volume, path, &cluster_num, &entry_num, &dirent);
879 if (ret != ERR_SUCCESS) return ret;
881 byte_t deleted = FATFS_DELETED;
882 size_t actually_written = 0;
884 ret = device_write(volume->header.device,
886 fatfs_get_cluster_offset(volume, cluster_num) + (qword_t)(entry_num * sizeof(fatfs_dirent_t)),
889 if (ret != ERR_SUCCESS) return ret;
891 if (cluster_num != volume->root_dir_cluster)
893 dword_t cluster_size = volume->sectors_per_cluster * volume->bytes_per_sector;
894 dword_t entries_per_cluster = cluster_size / sizeof(fatfs_dirent_t);
896 byte_t *cluster_buffer = (byte_t*)malloc(cluster_size);
897 if (cluster_buffer == NULL) return ERR_SUCCESS;
899 ret = fatfs_read_cluster(volume, cluster_num, cluster_buffer);
900 if (ret != ERR_SUCCESS)
902 free(cluster_buffer);
907 bool_t in_use = FALSE;
908 fatfs_dirent_t *entries = (fatfs_dirent_t*)cluster_buffer;
910 for (i = 0; i < entries_per_cluster; i++)
912 if (entries[i].filename[0] != FATFS_DELETED && entries[i].filename[0] == 0)
919 free(cluster_buffer);
920 cluster_buffer = NULL;
925 dword_t next_in_directory = fatfs_get_next_cluster(volume, cluster_num);
927 dword_t directory_start = volume->root_dir_cluster;
928 fatfs_dirent_t parent_dirent;
929 dword_t parent_dir_entry_cluster;
930 dword_t parent_dir_entry_number;
931 char *parent_path = __builtin_alloca(strlen(path) + 1);
932 strcpy(parent_path, path);
933 char *last_slash = strrchr(parent_path, '/');
939 ret = fatfs_find_entry(volume, parent_path, &parent_dir_entry_cluster, &parent_dir_entry_number, &parent_dirent);
940 ASSERT(ret == ERR_SUCCESS);
942 directory_start = parent_dirent.first_cluster_low | (parent_dirent.first_cluster_high << 16);
945 if (directory_start == cluster_num)
947 if (next_in_directory >= FATFS_INVALID_CLUSTER) next_in_directory = 0;
948 parent_dirent.first_cluster_low = next_in_directory & 0xFFFF;
949 parent_dirent.first_cluster_high = next_in_directory >> 16;
951 device_write(volume->header.device,
953 fatfs_get_cluster_offset(volume, parent_dir_entry_cluster)
954 + (qword_t)(parent_dir_entry_number * sizeof(fatfs_dirent_t)),
955 sizeof(fatfs_dirent_t),
960 dword_t current_cluster = directory_start;
964 dword_t next_cluster = fatfs_get_next_cluster(volume, current_cluster);
965 ASSERT(next_cluster < FATFS_INVALID_CLUSTER);
966 if (next_cluster == cluster_num) break;
969 fatfs_set_next_cluster(volume, current_cluster, next_in_directory);
972 fatfs_set_next_cluster(volume, cluster_num, 0);
976 if (purge) return fatfs_purge_file(volume, dirent.first_cluster_low | (dirent.first_cluster_high << 16));
980 static dword_t fatfs_read_file(file_instance_t *instance, void *buffer, qword_t offset, size_t length, size_t *bytes_read)
982 if (instance->mode & FILE_MODE_NO_CACHE)
984 return fatfs_read_internal(&instance->header, buffer, offset, length, bytes_read);
988 fatfs_file_t *file = CONTAINER_OF(instance->global, fatfs_file_t, header);
989 return read_cache(&file->cache, &instance->header, buffer, offset, length, bytes_read);
993 static dword_t fatfs_write_file(file_instance_t *instance, const void *buffer, qword_t offset, size_t length, size_t *bytes_written)
995 if (instance->mode & FILE_MODE_NO_CACHE)
997 return fatfs_write_internal(&instance->header, buffer, offset, length, bytes_written);
1001 fatfs_file_t *file = CONTAINER_OF(instance->global, fatfs_file_t, header);
1002 return write_cache(&file->cache, &instance->header, buffer, offset, length, bytes_written);
1006 static dword_t fatfs_list_dir(file_instance_t *_directory, char *filename, bool_t continue_scan)
1008 fatfs_volume_t *volume = CONTAINER_OF(_directory->global->volume, fatfs_volume_t, header);
1009 fatfs_file_t *directory = CONTAINER_OF(_directory->global, fatfs_file_t, header);
1010 fatfs_file_instance_t *instance = CONTAINER_OF(_directory, fatfs_file_instance_t, header);
1014 instance->last_offset = 0ULL;
1015 instance->last_cluster = directory->first_cluster;
1018 if (instance->last_cluster >= FATFS_INVALID_CLUSTER) return ERR_NOMORE;
1020 fatfs_dirent_t dirent;
1021 size_t actually_read;
1023 dword_t ret = device_read(volume->header.device,
1025 fatfs_get_cluster_offset(volume, instance->last_cluster) + (instance->last_offset & 0x1FF),
1026 sizeof(fatfs_dirent_t),
1028 if (ret != ERR_SUCCESS) return ret;
1030 instance->last_offset += sizeof(fatfs_dirent_t);
1032 if ((instance->last_offset & 0x1FF) == 0)
1034 instance->last_cluster = fatfs_get_next_cluster(volume, instance->last_cluster);
1037 fatfs_get_entry_name(&dirent, filename);
1041 static dword_t fatfs_set_file(file_t *_file, dword_t info_type, const void *buffer, size_t size)
1043 fatfs_file_t *file = CONTAINER_OF(_file, fatfs_file_t, header);
1047 case FILE_INFO_ATTRIBUTES:
1048 case FILE_INFO_TIME:
1049 return ERR_NOSYSCALL; // TODO
1051 case FILE_INFO_SIZE:
1052 if (size >= sizeof(qword_t))
1054 return fatfs_resize_file(file, *(qword_t*)buffer);
1058 return ERR_SMALLBUF;
1066 dword_t driver_load(const char *parameters)
1068 register_filesystem_driver(&fatfs_driver);