1 /*
2  * Copyright (c) 2015 Steve White
3  * Copyright (c) 2022 Travis Geiselbrecht
4  *
5  * Use of this source code is governed by a MIT-style
6  * license that can be found in the LICENSE file or at
7  * https://opensource.org/licenses/MIT
8  */
9 #pragma once
10 
11 #include <lib/bio.h>
12 #include <lib/bcache.h>
13 #include <lib/fs.h>
14 #include <kernel/mutex.h>
15 
16 // computed constants about a particular mount
17 struct fat_info {
18     uint32_t bytes_per_sector = 0;
19     uint32_t sectors_per_cluster = 0;
20     uint32_t bytes_per_cluster = 0;
21     uint32_t reserved_sectors = 0;
22     uint32_t fat_bits = 0;
23     uint32_t fat_count = 0;
24     uint32_t sectors_per_fat = 0;
25     uint32_t total_sectors = 0;
26     uint32_t active_fat = 0;
27     uint32_t data_start_sector = 0;
28     uint32_t total_clusters = 0;
29     uint32_t root_cluster = 0;
30     uint32_t root_entries = 0;
31     uint32_t root_start_sector = 0;
32     uint32_t root_dir_sectors = 0;
33 };
34 
35 class fat_file;
36 struct dir_entry_location;
37 
38 // main fs object representing a mount
39 class fat_fs {
40 public:
41     // mount hook, creates a new fs instance and passes it back in fscookie
42     static status_t mount(bdev_t *dev, fscookie **cookie);
43     static status_t unmount(fscookie *cookie);
44 
dev()45     bdev_t *dev() { return dev_; }
bcache()46     bcache_t bcache() { return bcache_; }
info()47     const fat_info &info() const { return info_; }
48 
49     // file list apis
50     // must be called with lock held
51     void add_to_file_list(fat_file *file);
52     fat_file *lookup_file(const dir_entry_location &loc);
53 
54     // for now keep the lock public
55     Mutex lock;
56 
57 private:
58     fat_fs();
59     ~fat_fs();
60 
61     bdev_t *dev_ = nullptr;
62     bcache_t bcache_ = nullptr;
63 
64     // list of all the open files and directories
65     list_node file_list_ = LIST_INITIAL_VALUE(file_list_);
66 
67     // data computed from BPB
68     fat_info info_ {};
69 };
70 
71 enum class fat_attribute : uint8_t {
72     read_only = 0x01,
73     hidden = 0x02,
74     system = 0x04,
75     volume_id = 0x08,
76     directory = 0x10,
77     archive = 0x20,
78     lfn = read_only | hidden | system | volume_id,
79 };
80 
fat_read32(const void * _buffer,size_t offset)81 inline uint32_t fat_read32(const void *_buffer, size_t offset) {
82     auto *buffer = (const uint8_t *)_buffer;
83 
84     return buffer[offset] +
85           (buffer[offset + 1] << 8) +
86           (buffer[offset + 2] << 16) +
87           (buffer[offset + 3] << 24);
88 }
89 
fat_read16(const void * _buffer,size_t offset)90 inline uint16_t fat_read16(const void *_buffer, size_t offset) {
91     auto *buffer = (const uint8_t *)_buffer;
92 
93     return buffer[offset] +
94           (buffer[offset + 1] << 8);
95 }
96 
97 // In fat32, clusters between 0x0fff.fff8 and 0x0fff.ffff are interpreted as
98 // end of file.
99 const uint32_t EOF_CLUSTER_BASE = 0x0ffffff8;
100 const uint32_t EOF_CLUSTER = 0x0fffffff;
101 
is_eof_cluster(uint32_t cluster)102 inline bool is_eof_cluster(uint32_t cluster) {
103     return cluster >= EOF_CLUSTER_BASE && cluster <= EOF_CLUSTER;
104 }
105 
106 const int DIR_ENTRY_LENGTH = 32;
107 const size_t MAX_FILE_NAME_LEN = 256;
108 
109