dad9ec92f19e1f6401936e59a29b2eb1409dff0d
[monolithium.git] / kernel / src / drivers / fs / fat.c
1 /*
2  * fat.c
3  *
4  * Copyright (C) 2016 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as
8  * published by the Free Software Foundation, either version 3 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "fat.h"
21 #include <syscalls.h>
22 #include <heap.h>
23 #include <exception.h>
24 #include <user.h>
25
26 static dword_t fatfs_mount(const char *device, dword_t flags);
27 static dword_t fatfs_unmount(mounted_volume_t *volume);
28 static dword_t fatfs_load_file(file_t **file);
29 static dword_t fatfs_unload_file(file_t *file);
30 static dword_t fatfs_open_file(file_instance_t **instance);
31 static dword_t fatfs_close_file(file_instance_t *instance);
32 static dword_t fatfs_delete_file(mounted_volume_t *volume, const char *path, bool_t purge);
33 static dword_t fatfs_read_file(file_instance_t *file, void *buffer, qword_t offset, size_t length, size_t *bytes_read);
34 static dword_t fatfs_write_file(file_instance_t *file, const void *buffer, qword_t offset, size_t length, size_t *bytes_written);
35 static dword_t fatfs_list_dir(file_instance_t *directory, char *filename, bool_t continue_scan);
36 static dword_t fatfs_set_file(file_t *file, dword_t info_type, const void *buffer, size_t size);
37
38 static dword_t fatfs_read_internal(object_t *obj, void *buffer, qword_t offset, size_t length, size_t *bytes_read);
39 static dword_t fatfs_write_internal(object_t *obj, const void *buffer, qword_t offset, size_t length, size_t *bytes_written);
40
41 static fs_driver_t fatfs_driver =
42 {
43     .name = "FAT",
44     .mount = fatfs_mount,
45     .unmount = fatfs_unmount,
46     .load_file = fatfs_load_file,
47     .unload_file = fatfs_unload_file,
48     .open_file = fatfs_open_file,
49     .close_file = fatfs_close_file,
50     .delete_file = fatfs_delete_file,
51     .read_file = fatfs_read_file,
52     .write_file = fatfs_write_file,
53     .list_dir = fatfs_list_dir,
54     .set_file = fatfs_set_file
55 };
56
57 static void fatfs_get_entry_name(fatfs_dirent_t *dirent, char *name)
58 {
59     byte_t *src = dirent->filename;
60     char *dest = name;
61     byte_t *last_name_ptr = &dirent->filename[7];
62     byte_t *last_ext_ptr = &dirent->extension[2];
63
64     while (*last_name_ptr == ' ' && last_name_ptr >= dirent->filename) last_name_ptr--;
65     while (*last_ext_ptr == ' ' && last_ext_ptr >= dirent->extension) last_ext_ptr--;
66     while (src <= last_name_ptr) *dest++ = *src++;
67
68     src = dirent->extension;
69     if (src <= last_ext_ptr) *dest++ = '.';
70     while (src <= last_ext_ptr) *dest++ = *src++;
71     *dest = '\0';
72 }
73
74 static bool_t fatfs_check_name(const char *name)
75 {
76     const char *illegal = "\"*+,/:;<=>?[\\]|";
77     size_t num_dots = 0;
78     size_t count_before = 0;
79     size_t count_after = 0;
80
81     while (*name)
82     {
83         if (strrchr(illegal, *name) || (*name >= 'a' && *name <= 'z')) return FALSE;
84
85         if (*name == '.')
86         {
87             num_dots++;
88             if (num_dots > 1) return FALSE;
89         }
90         else if (num_dots == 0)
91         {
92             count_before++;
93             if (count_before > 8) return FALSE;
94         }
95         else
96         {
97             count_after++;
98             if (count_after > 3) return FALSE;
99         }
100
101         name++;
102     }
103
104     return TRUE;
105 }
106
107 static void fatfs_set_entry_name(fatfs_dirent_t *dirent, const char *name)
108 {
109     const char *src = name;
110     byte_t *dest = dirent->filename;
111
112     while (*src != '.' && *src != '\0') *dest++ = toupper(*src++);
113     while (dest < &dirent->filename[8]) *dest++ = ' ';
114
115     if (*src == '.')
116     {
117         src++;
118         dest = dirent->extension;
119         while (*src != '\0') *dest++ = toupper(*src++);
120     }
121 }
122
123 static inline void fatfs_pack_file_time(clock_time_t *os_time, word_t *date, word_t *time)
124 {
125     if (date) *date = (os_time->year << 9) | (os_time->month << 5) | os_time->day;
126     if (time) *time = (os_time->hours << 11) | (os_time->minutes << 5) | (os_time->seconds >> 1);
127 }
128
129 static inline void fatfs_unpack_file_time(word_t date, word_t time, clock_time_t *os_time)
130 {
131     os_time->day = date & 0x1F;
132     os_time->month = (date >> 5) & 0x0F;
133     os_time->year = (date >> 9) & 0x7F;
134     os_time->seconds = (time & 0x1F) << 1;
135     os_time->minutes = (time >> 5) & 0x3F;
136     os_time->hours = (time >> 11) & 0x1F;
137 }
138
139 static dword_t fatfs_get_next_cluster(fatfs_volume_t *volume, dword_t cluster)
140 {
141     qword_t entry_offset = (qword_t)(volume->reserved_sectors * volume->bytes_per_sector);
142
143     switch (volume->type)
144     {
145     case FAT12:
146         entry_offset += (qword_t)(cluster + (cluster >> 1));
147         break;
148
149     case FAT16:
150         entry_offset += (qword_t)(cluster << 1);
151         break;
152
153     case FAT32:
154         entry_offset += (qword_t)(cluster << 2);
155         break;
156     }
157
158     dword_t entry;
159     dword_t bytes_read;
160     dword_t ret = device_read(volume->header.device,
161                               (byte_t*)&entry,
162                               entry_offset,
163                               (volume->type == FAT32) ? sizeof(dword_t) : sizeof(word_t),
164                               &bytes_read);
165     if (ret != ERR_SUCCESS) return FATFS_INVALID_CLUSTER;
166
167     switch (volume->type)
168     {
169     case FAT12:
170         entry = ((cluster & 1) ? (entry >> 4) : entry) & 0xFFF;
171         if (entry >= 0xFF0) entry |= FATFS_INVALID_CLUSTER;
172         break;
173
174     case FAT16:
175         entry &= 0xFFFF;
176         if (entry >= 0xFFF0) entry |= FATFS_INVALID_CLUSTER;
177         break;
178
179     case FAT32:
180         entry &= 0x0FFFFFFF;
181         if (entry >= 0x0FFFFFF0) entry |= FATFS_INVALID_CLUSTER;
182         break;
183     }
184
185     if (entry == 0) entry = FATFS_INVALID_CLUSTER;
186     return entry;
187 }
188
189 static dword_t fatfs_set_next_cluster(fatfs_volume_t *volume, dword_t cluster, dword_t next)
190 {
191     qword_t entry_offset = (qword_t)(volume->reserved_sectors * volume->bytes_per_sector);
192
193     switch (volume->type)
194     {
195     case FAT12:
196         next &= 0xFFF;
197         entry_offset += (qword_t)(cluster + (cluster >> 1));
198         break;
199
200     case FAT16:
201         next &= 0xFFFF;
202         entry_offset += (qword_t)(cluster << 1);
203         break;
204
205     case FAT32:
206         next &= 0xFFFFFFFF;
207         entry_offset += (qword_t)(cluster << 2);
208         break;
209     }
210
211     dword_t entry;
212
213     if (volume->type == FAT12)
214     {
215         dword_t bytes_read;
216         dword_t ret = device_read(volume->header.device, (byte_t*)&entry, entry_offset, sizeof(word_t), &bytes_read);
217         if (ret != ERR_SUCCESS) return ret;
218
219         entry &= 0xF000 >> ((cluster & 1) * 12);
220         entry |= next << ((cluster & 1) * 4);
221     }
222     else
223     {
224         entry = next;
225     }
226
227     dword_t bytes_written;
228     return device_write(volume->header.device,
229                         (byte_t*)&entry,
230                         entry_offset,
231                         (volume->type == FAT32) ? sizeof(dword_t) : sizeof(word_t),
232                         &bytes_written);
233 }
234
235 static qword_t fatfs_get_cluster_offset(fatfs_volume_t *volume, dword_t number)
236 {
237     qword_t sector = (qword_t)(number - volume->root_dir_cluster)
238                      * (qword_t)volume->sectors_per_cluster
239                      + (qword_t)volume->reserved_sectors
240                      + (qword_t)(volume->num_fats * volume->sectors_per_fat);
241     qword_t offset = sector * (qword_t)volume->bytes_per_sector;
242
243     if (number != volume->root_dir_cluster)
244     {
245         offset += (qword_t)(volume->num_root_dirents * sizeof(fatfs_dirent_t));
246     }
247
248     return offset;
249 }
250
251 static dword_t fatfs_read_cluster(fatfs_volume_t *volume, dword_t number, void *buffer)
252 {
253     dword_t bytes_read;
254     return device_read(volume->header.device,
255                        buffer,
256                        fatfs_get_cluster_offset(volume, number),
257                        volume->sectors_per_cluster * volume->bytes_per_sector,
258                        &bytes_read);
259 }
260
261 static dword_t fatfs_zero_cluster(fatfs_volume_t *volume, dword_t number)
262 {
263     byte_t *buffer = __builtin_alloca(volume->sectors_per_cluster * volume->bytes_per_sector);
264     memset(buffer, 0, volume->sectors_per_cluster * volume->bytes_per_sector);
265
266     dword_t bytes_written;
267     return device_write(volume->header.device,
268                         buffer,
269                         fatfs_get_cluster_offset(volume, number),
270                         volume->sectors_per_cluster * volume->bytes_per_sector,
271                         &bytes_written);
272 }
273
274 static dword_t fatfs_get_free_cluster(fatfs_volume_t *volume, dword_t *cluster)
275 {
276     dword_t starting_cluster = volume->last_free_cluster;
277
278     do
279     {
280         if (fatfs_get_next_cluster(volume, volume->last_free_cluster) == FATFS_FREE_CLUSTER)
281         {
282             *cluster = volume->last_free_cluster;
283             return ERR_SUCCESS;
284         }
285
286         volume->last_free_cluster++;
287         volume->last_free_cluster %= volume->total_clusters;
288         if (volume->last_free_cluster <= volume->root_dir_cluster) volume->last_free_cluster = volume->root_dir_cluster + 1;
289     }
290     while (volume->last_free_cluster != starting_cluster);
291
292     return ERR_DISKFULL;
293 }
294
295 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)
296 {
297     dword_t ret = ERR_SUCCESS;
298     dword_t i;
299     byte_t *cluster_buffer = NULL;
300     char path_copy[MAX_PATH];
301     fatfs_dirent_t root_dirent =
302     {
303         .attributes = FATFS_ATTR_DIRECTORY,
304         .first_cluster_high = volume->root_dir_cluster >> 16,
305         .first_cluster_low = volume->root_dir_cluster & 0xFFFF,
306         .size = volume->num_root_dirents * sizeof(fatfs_dirent_t)
307     };
308
309     if (path[0] == '\0')
310     {
311         if (cluster_num) *cluster_num = (dword_t)-1;
312         if (entry_num) *entry_num = (dword_t)-1;
313         if (dirent) *dirent = root_dirent;
314         goto cleanup;
315     }
316
317     dword_t cluster_size = volume->sectors_per_cluster * volume->bytes_per_sector;
318     cluster_buffer = (byte_t*)malloc(cluster_size);
319
320     if (cluster_buffer == NULL)
321     {
322         ret = ERR_NOMEMORY;
323         goto cleanup;
324     }
325
326     dword_t previous_cluster = (dword_t)-1;
327     dword_t current_cluster = volume->root_dir_cluster;
328     dword_t current_index = 0;
329     fatfs_dirent_t current_dirent = root_dirent;
330
331     char *token, *endptr;
332     strcpy(path_copy, path);
333
334     for (token = strtok(path_copy, PATH_DELIMITER_STRING, &endptr); token != NULL; token = strtok(NULL, PATH_DELIMITER_STRING, &endptr))
335     {
336         if (!(current_dirent.attributes & FATFS_ATTR_DIRECTORY))
337         {
338             ret = ERR_NOTFOUND;
339             goto cleanup;
340         }
341
342         while (TRUE)
343         {
344             ret = fatfs_read_cluster(volume, current_cluster, cluster_buffer);
345             if (ret != ERR_SUCCESS) goto cleanup;
346
347             fatfs_dirent_t *entries = (fatfs_dirent_t*)cluster_buffer;
348             dword_t num_entries = cluster_size / sizeof(fatfs_dirent_t);
349
350             for (i = 0; i < num_entries; i++)
351             {
352                 if (!(entries[i].attributes & FATFS_ATTR_VOLUME_ID)
353                     && entries[i].filename[0] != 0
354                     && entries[i].filename[0] != FATFS_DELETED)
355                 {
356                     char filename[13];
357                     fatfs_get_entry_name(&entries[i], filename);
358                     if (strcmp(token, filename) == 0) break;
359                 }
360             }
361
362             previous_cluster = current_cluster;
363
364             if (i != num_entries)
365             {
366                 current_cluster = entries[i].first_cluster_low | (entries[i].first_cluster_high << 16);
367                 current_index = i;
368                 current_dirent = entries[i];
369                 break;
370             }
371
372             current_cluster = fatfs_get_next_cluster(volume, current_cluster);
373             if (current_cluster >= FATFS_INVALID_CLUSTER)
374             {
375                 ret = ERR_NOTFOUND;
376                 break;
377             }
378         }
379     }
380
381     if (cluster_num) *cluster_num = previous_cluster;
382     if (entry_num) *entry_num = current_index;
383     if (dirent) *dirent = current_dirent;
384
385 cleanup:
386     if (cluster_buffer) free(cluster_buffer);
387     return ret;
388 }
389
390 static dword_t fatfs_resize_file(fatfs_file_t *file, qword_t new_size)
391 {
392     dword_t ret;
393     dword_t bytes;
394     fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
395
396     if (new_size == file->header.size) return ERR_SUCCESS;
397
398     dword_t cluster_size = volume->sectors_per_cluster * volume->bytes_per_sector;
399     dword_t num_clusters_old = (file->header.size + cluster_size - 1) / cluster_size;
400     dword_t num_clusters_new = (new_size + cluster_size - 1) / cluster_size;
401
402     dword_t prev_cluster = FATFS_FREE_CLUSTER;
403     dword_t current_cluster = file->first_cluster;
404
405     if (num_clusters_new > num_clusters_old)
406     {
407         while (current_cluster != FATFS_FREE_CLUSTER && current_cluster < FATFS_INVALID_CLUSTER)
408         {
409             prev_cluster = current_cluster;
410             current_cluster = fatfs_get_next_cluster(volume, current_cluster);
411         }
412
413         dword_t new_clusters = num_clusters_new - num_clusters_old;
414         while (new_clusters--)
415         {
416             dword_t new_cluster;
417             ret = fatfs_get_free_cluster(volume, &new_cluster);
418             if (ret != ERR_SUCCESS) break;
419
420             ret = fatfs_zero_cluster(volume, new_cluster);
421             if (ret != ERR_SUCCESS)
422             {
423                 fatfs_set_next_cluster(volume, new_cluster, FATFS_BAD_CLUSTER);
424                 new_clusters++;
425                 continue;
426             }
427
428             if (prev_cluster == FATFS_FREE_CLUSTER)
429             {
430                 file->first_cluster = new_cluster;
431             }
432             else
433             {
434                 ret = fatfs_set_next_cluster(volume, prev_cluster, new_cluster);
435                 if (ret != ERR_SUCCESS) break;
436             }
437
438             prev_cluster = new_cluster;
439         }
440
441         ret = fatfs_set_next_cluster(volume, prev_cluster, FATFS_LAST_CLUSTER);
442     }
443     else if (num_clusters_new < num_clusters_old)
444     {
445         while (num_clusters_new--)
446         {
447             prev_cluster = current_cluster;
448             current_cluster = fatfs_get_next_cluster(volume, current_cluster);
449             if (current_cluster >= FATFS_INVALID_CLUSTER) break;
450         }
451
452         if (prev_cluster == FATFS_FREE_CLUSTER)
453         {
454             file->first_cluster = 0;
455         }
456         else
457         {
458             ret = fatfs_set_next_cluster(volume, prev_cluster, FATFS_LAST_CLUSTER);
459         }
460
461         while (current_cluster < FATFS_INVALID_CLUSTER)
462         {
463             dword_t next_cluster = fatfs_get_next_cluster(volume, current_cluster);
464             ret = fatfs_set_next_cluster(volume, current_cluster, FATFS_FREE_CLUSTER);
465             if (ret != ERR_SUCCESS) break;
466             current_cluster = next_cluster;
467         }
468     }
469
470     clock_time_t current_time;
471     syscall(SYSCALL_CLOCK_GET_TIME, &current_time);
472
473     file->header.size = new_size;
474     fatfs_dirent_t dirent;
475
476     ret = device_read(volume->header.device,
477                       &dirent,
478                       fatfs_get_cluster_offset(volume, file->dirent_cluster) + (qword_t)file->dirent_index * sizeof(fatfs_dirent_t),
479                       sizeof(fatfs_dirent_t),
480                       &bytes);
481     if (ret != ERR_SUCCESS) return ret;
482
483     dirent.size = file->header.size;
484     dirent.first_cluster_low = file->first_cluster & 0xFFFF;
485     dirent.first_cluster_high = file->first_cluster >> 16;
486     fatfs_pack_file_time(&current_time, &dirent.modification_date, &dirent.modification_time);
487
488     return device_write(volume->header.device,
489                         &dirent,
490                         fatfs_get_cluster_offset(volume, file->dirent_cluster) + (qword_t)file->dirent_index * sizeof(fatfs_dirent_t),
491                         sizeof(fatfs_dirent_t),
492                         &bytes);
493 }
494
495 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)
496 {
497     dword_t ret;
498     dword_t count = 0;
499     fatfs_file_t *file;
500     fatfs_file_instance_t *instance;
501
502     if (object->type == OBJECT_FILE_INSTANCE)
503     {
504         instance = CONTAINER_OF(CONTAINER_OF(object, file_instance_t, header), fatfs_file_instance_t, header);
505         file = CONTAINER_OF(instance->header.global, fatfs_file_t, header);
506     }
507     else
508     {
509         ASSERT(object->type == OBJECT_FILE);
510         file = CONTAINER_OF(CONTAINER_OF(object, file_t, header), fatfs_file_t, header);
511         instance = NULL;
512     }
513
514     fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
515
516     if (!length)
517     {
518         if (bytes) *bytes = 0;
519         return ERR_SUCCESS;
520     }
521
522     if (offset > 0xFFFFFFFFULL)
523     {
524         if (bytes) *bytes = 0;
525         return ERR_BEYOND;
526     }
527
528     if (write && (offset + (qword_t)length) < file->header.size)
529     {
530         ret = fatfs_resize_file(file, offset + (qword_t)length);
531         if (ret != ERR_SUCCESS) return ret;
532     }
533
534     if (file->header.size == 0)
535     {
536         if (bytes) *bytes = 0;
537         return ERR_BEYOND;
538     }
539
540     dword_t offset_low = (dword_t)offset;
541     dword_t cluster_size = volume->sectors_per_cluster * volume->bytes_per_sector;
542     dword_t current_cluster = file->first_cluster;
543
544     while (offset_low >= cluster_size)
545     {
546         current_cluster = fatfs_get_next_cluster(volume, current_cluster);
547         if (current_cluster >= FATFS_INVALID_CLUSTER)
548         {
549             if (bytes) *bytes = 0;
550             return ERR_BEYOND;
551         }
552
553         offset_low -= cluster_size;
554     }
555
556     while (TRUE)
557     {
558         dword_t amount = MIN(length - count, cluster_size - offset_low);
559         dword_t actually_rw;
560         if (amount == 0) break;
561
562         if (write)
563         {
564             ret = device_write(volume->header.device,
565                                &buffer[count],
566                                fatfs_get_cluster_offset(volume, current_cluster) + (qword_t)offset_low,
567                                amount,
568                                &actually_rw);
569
570         }
571         else
572         {
573             ret = device_read(volume->header.device,
574                               &buffer[count],
575                               fatfs_get_cluster_offset(volume, current_cluster) + (qword_t)offset_low,
576                               amount,
577                               &actually_rw);
578         }
579
580         if (ret != ERR_SUCCESS) goto cleanup;
581
582         offset_low = 0;
583         count += amount;
584
585         current_cluster = fatfs_get_next_cluster(volume, current_cluster);
586         if (current_cluster >= FATFS_INVALID_CLUSTER) break;
587     }
588
589     ret = (count == length) ? ERR_SUCCESS : ERR_BEYOND;
590
591 cleanup:
592     if (bytes) *bytes = count;
593     return ret;
594 }
595
596 static dword_t fatfs_read_internal(object_t *obj, void *buffer, qword_t offset, size_t length, size_t *bytes_read)
597 {
598     return fatfs_rw_file(obj, buffer, offset, length, bytes_read, FALSE);
599 }
600
601 static dword_t fatfs_write_internal(object_t *obj, const void *buffer, qword_t offset, size_t length, size_t *bytes_written)
602 {
603     return fatfs_rw_file(obj, (void*)buffer, offset, length, bytes_written, TRUE);
604 }
605
606 static dword_t fatfs_mount(const char *device, dword_t flags)
607 {
608     fatfs_bpb_t bpb;
609     fat_version_t type;
610     device_t *block_device = get_block_device(device);
611
612     dword_t ret = device_read(block_device, (byte_t*)&bpb, 0ULL, sizeof(fatfs_bpb_t), NULL);
613     if (ret != ERR_SUCCESS) return ret;
614     if (bpb.sectors_per_cluster == 0) return ERR_INVALID;
615
616     dword_t total_sectors;
617     if (bpb.total_sectors) total_sectors = bpb.total_sectors;
618     else total_sectors = bpb.total_sectors_32;
619
620     dword_t sectors_per_fat;
621     if (bpb.sectors_per_fat) sectors_per_fat = bpb.sectors_per_fat;
622     else sectors_per_fat = bpb.ext_bpb_32.sectors_per_fat;
623
624     dword_t root_dir_size = (bpb.num_dirent * sizeof(fatfs_dirent_t) + bpb.bytes_per_sector - 1) / bpb.bytes_per_sector;
625     dword_t total_clusters = (total_sectors - bpb.reserved_sectors - bpb.num_fats * sectors_per_fat - root_dir_size) / bpb.sectors_per_cluster;
626
627     if (total_clusters < 4086) type = FAT12;
628     else if (total_clusters < 65525) type = FAT16;
629     else type = FAT32;
630
631     if ((type != FAT32 && bpb.ext_bpb.signature != 0x28 && bpb.ext_bpb.signature != 0x29)
632         || (type == FAT32 && bpb.ext_bpb_32.signature != 0x28 && bpb.ext_bpb_32.signature != 0x29))
633     {
634         return ERR_INVALID;
635     }
636
637     fatfs_volume_t *volume = (fatfs_volume_t*)malloc(sizeof(fatfs_volume_t));
638     if (volume == NULL) return ERR_NOMEMORY;
639
640     volume->header.device = get_block_device(device);
641     volume->header.driver = &fatfs_driver;
642     volume->type = type;
643     volume->bytes_per_sector = bpb.bytes_per_sector;
644     volume->sectors_per_cluster = bpb.sectors_per_cluster;
645     volume->reserved_sectors = bpb.reserved_sectors;
646     volume->root_dir_cluster = (type == FAT32) ? bpb.ext_bpb_32.root_dir_cluster : 2;
647     volume->num_root_dirents = bpb.num_dirent;
648     volume->num_fats = bpb.num_fats;
649     volume->sectors_per_fat = sectors_per_fat;
650     volume->total_clusters = total_clusters;
651     volume->last_free_cluster = volume->root_dir_cluster + 1;
652     volume->owner_uid = get_user_id();
653
654     ret = register_mounted_volume(&volume->header);
655     if (ret != ERR_SUCCESS) free(volume);
656
657     return ret;
658 }
659
660 static dword_t fatfs_unmount(mounted_volume_t *volume)
661 {
662     dword_t ret = unregister_mounted_volume(volume);
663     if (ret != ERR_SUCCESS) return ret;
664
665     free(volume);
666     return ERR_SUCCESS;
667 }
668
669 static dword_t fatfs_load_file(file_t **_file)
670 {
671     fatfs_file_t *file = (fatfs_file_t*)realloc(*_file, sizeof(fatfs_file_t));
672     if (file == NULL) return ERR_NOMEMORY;
673     *_file = &file->header;
674
675     fatfs_dirent_t dirent;
676     dword_t cluster, entry;
677     fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
678
679     dword_t ret = fatfs_find_entry(volume, file->header.path, &cluster, &entry, &dirent);
680
681     if (ret == ERR_NOTFOUND && (file->header.global_mode & FILE_MODE_CREATE))
682     {
683         dword_t i;
684
685         char *parent_path = __builtin_alloca(strlen(file->header.path) + 1);
686         strcpy(parent_path, file->header.path);
687
688         char *file_name = NULL;
689         char *last_slash = strrchr(parent_path, '/');
690         if (last_slash)
691         {
692             *last_slash = '\0';
693             file_name = last_slash + 1;
694         }
695         else
696         {
697             *parent_path = '\0';
698             file_name = file->header.path;
699         }
700
701         if (!fatfs_check_name(file_name)) return ERR_INVALID;
702
703         fatfs_dirent_t parent_dirent;
704         dword_t parent_cluster, parent_entry;
705
706         ret = fatfs_find_entry(volume, parent_path, &parent_cluster, &parent_entry, &parent_dirent);
707         if (ret != ERR_SUCCESS) return ret;
708
709         dword_t entries_per_cluster = (volume->sectors_per_cluster * volume->bytes_per_sector) / sizeof(fatfs_dirent_t);
710         fatfs_dirent_t *entries = (fatfs_dirent_t*)malloc(volume->sectors_per_cluster * volume->bytes_per_sector);
711         if (entries == NULL) return ERR_NOMEMORY;
712
713         dword_t prev_cluster = FATFS_FREE_CLUSTER;
714         dword_t current_cluster = parent_dirent.first_cluster_low | (parent_dirent.first_cluster_high << 16);
715
716         while (TRUE)
717         {
718             if (current_cluster == FATFS_FREE_CLUSTER || (current_cluster >= FATFS_END_CLUSTER))
719             {
720                 dword_t new_cluster;
721                 ret = fatfs_get_free_cluster(volume, &new_cluster);
722                 if (ret != ERR_SUCCESS) break;
723
724                 ret = fatfs_zero_cluster(volume, new_cluster);
725                 if (ret != ERR_SUCCESS)
726                 {
727                     fatfs_set_next_cluster(volume, new_cluster, FATFS_BAD_CLUSTER);
728                     continue;
729                 }
730
731                 if (prev_cluster == FATFS_FREE_CLUSTER)
732                 {
733                     parent_dirent.first_cluster_low = new_cluster & 0xFFFF;
734                     parent_dirent.first_cluster_high = new_cluster >> 16;
735                 }
736                 else
737                 {
738                     ret = fatfs_set_next_cluster(volume, prev_cluster, new_cluster);
739                     if (ret != ERR_SUCCESS) break;
740                 }
741
742                 current_cluster = new_cluster;
743             }
744
745             ret = fatfs_read_cluster(volume, current_cluster, entries);
746             if (ret != ERR_SUCCESS) break;
747
748             bool_t found = FALSE;
749
750             for (i = 0; i < entries_per_cluster; i++)
751             {
752                 if (entries[i].filename[0] == '\0' || entries[i].filename[0] == FATFS_DELETED)
753                 {
754                     cluster = current_cluster;
755                     entry = i;
756                     found = TRUE;
757                     break;
758                 }
759             }
760
761             if (found) break;
762
763             prev_cluster = current_cluster;
764             current_cluster = fatfs_get_next_cluster(volume, current_cluster);
765         }
766
767         free(entries);
768         if (ret != ERR_SUCCESS) return ret;
769
770         clock_time_t current_time;
771         clock_get_time(&current_time);
772
773         dirent.attributes = 0;
774         if (!(file->header.attributes & FILE_ATTR_OWNER_WRITABLE)) dirent.attributes |= FATFS_ATTR_READONLY;
775         if (file->header.attributes & FILE_ATTR_DIRECTORY) dirent.attributes |= FATFS_ATTR_DIRECTORY;
776
777         fatfs_set_entry_name(&dirent, file_name);
778         dirent.duration = 1;
779         fatfs_pack_file_time(&current_time, &dirent.creation_date, &dirent.creation_time);
780         fatfs_pack_file_time(&current_time, &dirent.modification_date, &dirent.modification_time);
781         fatfs_pack_file_time(&current_time, &dirent.last_accessed_date, NULL);
782         dirent.first_cluster_high = 0;
783         dirent.first_cluster_low = 0;
784         dirent.size = 0;
785
786         dword_t actually_written;
787         ret = device_write(volume->header.device,
788                            &dirent,
789                            fatfs_get_cluster_offset(volume, cluster) + (qword_t)(entry * sizeof(fatfs_dirent_t)),
790                            sizeof(fatfs_dirent_t),
791                            &actually_written);
792         if (ret != ERR_SUCCESS) return ret;
793     }
794
795     file->header.attributes = FILE_ATTR_OWNER_READABLE;
796     if (!(dirent.attributes & FATFS_ATTR_READONLY)) file->header.attributes |= FILE_ATTR_OWNER_WRITABLE;
797     if (dirent.attributes & FATFS_ATTR_DIRECTORY) file->header.attributes |= FILE_ATTR_DIRECTORY;
798
799     file->header.size = dirent.size;
800     file->first_cluster = dirent.first_cluster_low | (dirent.first_cluster_high << 16);
801     file->dirent_cluster = cluster;
802     file->dirent_index = entry;
803
804     file->cache.flags = 0;
805     file->cache.block_size = volume->bytes_per_sector;
806     file->cache.read_proc = (read_write_buffer_proc_t)fatfs_read_internal;
807     file->cache.write_proc = (read_write_buffer_proc_t)fatfs_write_internal;
808
809     return ret;
810 }
811
812 static dword_t fatfs_purge_file(fatfs_volume_t *volume, dword_t starting_cluster)
813 {
814     dword_t current_cluster = starting_cluster;
815
816     while (TRUE)
817     {
818         dword_t next_cluster = fatfs_get_next_cluster(volume, current_cluster);
819         fatfs_set_next_cluster(volume, current_cluster, 0);
820         current_cluster = next_cluster;
821     }
822
823     return ERR_SUCCESS;
824 }
825
826 static dword_t fatfs_unload_file(file_t *_file)
827 {
828     fatfs_file_t *file = CONTAINER_OF(_file, fatfs_file_t, header);
829     fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
830
831     if (file->header.attributes & FILE_ATTR_DELETED)
832     {
833         return fatfs_purge_file(volume, file->first_cluster);
834     }
835     else
836     {
837         return flush_cache(&file->cache, &file->header.header);
838     }
839 }
840
841 static dword_t fatfs_open_file(file_instance_t **_instance)
842 {
843     fatfs_file_t *file = CONTAINER_OF((*_instance)->global, fatfs_file_t, header);
844
845     fatfs_volume_t *volume = CONTAINER_OF(file->header.volume, fatfs_volume_t, header);
846     if (get_user_id() != volume->owner_uid) return ERR_FORBIDDEN;
847
848     fatfs_file_instance_t *instance = (fatfs_file_instance_t*)realloc(*_instance, sizeof(fatfs_file_instance_t));
849     if (instance == NULL) return ERR_NOMEMORY;
850     *_instance = &instance->header;
851
852     instance->last_offset = 0;
853     instance->last_cluster = file->first_cluster;
854     return ERR_SUCCESS;
855 }
856
857 static dword_t fatfs_close_file(file_instance_t *_instance)
858 {
859     return ERR_SUCCESS;
860 }
861
862 static dword_t fatfs_delete_file(mounted_volume_t *_volume, const char *path, bool_t purge)
863 {
864     fatfs_volume_t *volume = CONTAINER_OF(volume, fatfs_volume_t, header);
865     if (get_user_id() != volume->owner_uid) return ERR_FORBIDDEN;
866
867     fatfs_dirent_t dirent;
868     dword_t cluster_num;
869     dword_t entry_num;
870
871     dword_t ret = fatfs_find_entry(volume, path, &cluster_num, &entry_num, &dirent);
872     if (ret != ERR_SUCCESS) return ret;
873
874     byte_t deleted = FATFS_DELETED;
875     size_t actually_written = 0;
876
877     ret = device_write(volume->header.device,
878                        &deleted,
879                        fatfs_get_cluster_offset(volume, cluster_num) + (qword_t)(entry_num * sizeof(fatfs_dirent_t)),
880                        sizeof(byte_t),
881                        &actually_written);
882     if (ret != ERR_SUCCESS) return ret;
883
884     if (cluster_num != volume->root_dir_cluster)
885     {
886         dword_t cluster_size = volume->sectors_per_cluster * volume->bytes_per_sector;
887         dword_t entries_per_cluster = cluster_size / sizeof(fatfs_dirent_t);
888
889         byte_t *cluster_buffer = (byte_t*)malloc(cluster_size);
890         if (cluster_buffer == NULL) return ERR_SUCCESS;
891
892         ret = fatfs_read_cluster(volume, cluster_num, cluster_buffer);
893         if (ret != ERR_SUCCESS)
894         {
895             free(cluster_buffer);
896             return ERR_SUCCESS;
897         }
898
899         dword_t i;
900         bool_t in_use = FALSE;
901         fatfs_dirent_t *entries = (fatfs_dirent_t*)cluster_buffer;
902
903         for (i = 0; i < entries_per_cluster; i++)
904         {
905             if (entries[i].filename[0] != FATFS_DELETED && entries[i].filename[0] == 0)
906             {
907                 in_use = TRUE;
908                 break;
909             }
910         }
911
912         free(cluster_buffer);
913         cluster_buffer = NULL;
914         entries = NULL;
915
916         if (!in_use)
917         {
918             dword_t next_in_directory = fatfs_get_next_cluster(volume, cluster_num);
919
920             dword_t directory_start = volume->root_dir_cluster;
921             fatfs_dirent_t parent_dirent;
922             dword_t parent_dir_entry_cluster;
923             dword_t parent_dir_entry_number;
924             char *parent_path = __builtin_alloca(strlen(path) + 1);
925             strcpy(parent_path, path);
926             char *last_slash = strrchr(parent_path, '/');
927
928             if (last_slash)
929             {
930                 *last_slash = '\0';
931
932                 ret = fatfs_find_entry(volume, parent_path, &parent_dir_entry_cluster, &parent_dir_entry_number, &parent_dirent);
933                 ASSERT(ret == ERR_SUCCESS);
934
935                 directory_start = parent_dirent.first_cluster_low | (parent_dirent.first_cluster_high << 16);
936             }
937
938             if (directory_start == cluster_num)
939             {
940                 if (next_in_directory >= FATFS_INVALID_CLUSTER) next_in_directory = 0;
941                 parent_dirent.first_cluster_low = next_in_directory & 0xFFFF;
942                 parent_dirent.first_cluster_high = next_in_directory >> 16;
943
944                 device_write(volume->header.device,
945                              &parent_dirent,
946                              fatfs_get_cluster_offset(volume, parent_dir_entry_cluster)
947                              + (qword_t)(parent_dir_entry_number * sizeof(fatfs_dirent_t)),
948                              sizeof(fatfs_dirent_t),
949                              &actually_written);
950             }
951             else
952             {
953                 dword_t current_cluster = directory_start;
954
955                 while (TRUE)
956                 {
957                     dword_t next_cluster = fatfs_get_next_cluster(volume, current_cluster);
958                     ASSERT(next_cluster < FATFS_INVALID_CLUSTER);
959                     if (next_cluster == cluster_num) break;
960                 }
961
962                 fatfs_set_next_cluster(volume, current_cluster, next_in_directory);
963             }
964
965             fatfs_set_next_cluster(volume, cluster_num, 0);
966         }
967     }
968
969     if (purge) return fatfs_purge_file(volume, dirent.first_cluster_low | (dirent.first_cluster_high << 16));
970     else return TRUE;
971 }
972
973 static dword_t fatfs_read_file(file_instance_t *instance, void *buffer, qword_t offset, size_t length, size_t *bytes_read)
974 {
975     if (instance->mode & FILE_MODE_NO_CACHE)
976     {
977         return fatfs_read_internal(&instance->header, buffer, offset, length, bytes_read);
978     }
979     else
980     {
981         fatfs_file_t *file = CONTAINER_OF(instance->global, fatfs_file_t, header);
982         return read_cache(&file->cache, &instance->header, buffer, offset, length, bytes_read);
983     }
984 }
985
986 static dword_t fatfs_write_file(file_instance_t *instance, const void *buffer, qword_t offset, size_t length, size_t *bytes_written)
987 {
988     if (instance->mode & FILE_MODE_NO_CACHE)
989     {
990         return fatfs_write_internal(&instance->header, buffer, offset, length, bytes_written);
991     }
992     else
993     {
994         fatfs_file_t *file = CONTAINER_OF(instance->global, fatfs_file_t, header);
995         return write_cache(&file->cache, &instance->header, buffer, offset, length, bytes_written);
996     }
997 }
998
999 static dword_t fatfs_list_dir(file_instance_t *_directory, char *filename, bool_t continue_scan)
1000 {
1001     fatfs_volume_t *volume = CONTAINER_OF(_directory->global->volume, fatfs_volume_t, header);
1002     fatfs_file_t *directory = CONTAINER_OF(_directory->global, fatfs_file_t, header);
1003     fatfs_file_instance_t *instance = CONTAINER_OF(_directory, fatfs_file_instance_t, header);
1004
1005     if (!continue_scan)
1006     {
1007         instance->last_offset = 0ULL;
1008         instance->last_cluster = directory->first_cluster;
1009     }
1010
1011     if (instance->last_cluster >= FATFS_INVALID_CLUSTER) return ERR_NOMORE;
1012
1013     fatfs_dirent_t dirent;
1014     size_t actually_read;
1015
1016     dword_t ret = device_read(volume->header.device,
1017                               &dirent,
1018                               fatfs_get_cluster_offset(volume, instance->last_cluster) + (instance->last_offset & 0x1FF),
1019                               sizeof(fatfs_dirent_t),
1020                               &actually_read);
1021     if (ret != ERR_SUCCESS) return ret;
1022
1023     instance->last_offset += sizeof(fatfs_dirent_t);
1024
1025     if ((instance->last_offset & 0x1FF) == 0)
1026     {
1027         instance->last_cluster = fatfs_get_next_cluster(volume, instance->last_cluster);
1028     }
1029
1030     fatfs_get_entry_name(&dirent, filename);
1031     return ERR_SUCCESS;
1032 }
1033
1034 static dword_t fatfs_set_file(file_t *_file, dword_t info_type, const void *buffer, size_t size)
1035 {
1036     fatfs_file_t *file = CONTAINER_OF(_file, fatfs_file_t, header);
1037
1038     switch (info_type)
1039     {
1040     case FILE_INFO_ATTRIBUTES:
1041     case FILE_INFO_TIME:
1042         return ERR_NOSYSCALL; // TODO
1043
1044     case FILE_INFO_SIZE:
1045         if (size >= sizeof(qword_t))
1046         {
1047             return fatfs_resize_file(file, *(qword_t*)buffer);
1048         }
1049         else
1050         {
1051             return ERR_SMALLBUF;
1052         }
1053
1054     default:
1055         return ERR_INVALID;
1056     }
1057 }
1058
1059 dword_t fatfs_driver_load(void)
1060 {
1061     register_filesystem_driver(&fatfs_driver);
1062     return ERR_SUCCESS;
1063 }