blob: 9b6d5ba2f30fe0faec90f268f69d8676bdfc68fd [file] [log] [blame]
swissChilief829f32021-06-13 20:00:54 -07001#pragma once
2
3#include <vfs.h>
4
5struct ext2_superblock
6{
swissChilib7ef65d2021-07-17 12:51:52 -07007 /// Total number of inodes
swissChilief829f32021-06-13 20:00:54 -07008 uint total_inodes;
swissChilib7ef65d2021-07-17 12:51:52 -07009
10 /// Total number of blocks
swissChilief829f32021-06-13 20:00:54 -070011 uint total_blocks;
swissChilib7ef65d2021-07-17 12:51:52 -070012
13 /// Number of blocks reserved for superuser
swissChilief829f32021-06-13 20:00:54 -070014 uint blocks_reserved_for_superuser;
swissChilib7ef65d2021-07-17 12:51:52 -070015
16 /// Number of unallocated blocks
swissChilief829f32021-06-13 20:00:54 -070017 uint unallocated_blocks;
swissChilib7ef65d2021-07-17 12:51:52 -070018
19 /// Number of unallocated inodes
swissChilief829f32021-06-13 20:00:54 -070020 uint unallocated_inodes;
swissChilib7ef65d2021-07-17 12:51:52 -070021
22 /// Block number containing the superblock
swissChilief829f32021-06-13 20:00:54 -070023 uint superblock_block_number;
swissChilib7ef65d2021-07-17 12:51:52 -070024
25 /// the number to shift 1024 to the left by to get the block size
swissChilief829f32021-06-13 20:00:54 -070026 uint block_size_shift;
swissChilib7ef65d2021-07-17 12:51:52 -070027
28 /// the number to shift 1024 to the left by to get the fragment size
swissChilief829f32021-06-13 20:00:54 -070029 uint fragment_size_shift;
swissChilib7ef65d2021-07-17 12:51:52 -070030
31 /// Number of blocks in one block group
swissChilief829f32021-06-13 20:00:54 -070032 uint blocks_per_block_group;
swissChilib7ef65d2021-07-17 12:51:52 -070033
34 /// Number of fragments in one block group
swissChilief829f32021-06-13 20:00:54 -070035 uint fragments_per_block_group;
swissChilib7ef65d2021-07-17 12:51:52 -070036
37 /// Number of inodse in one block group
swissChilief829f32021-06-13 20:00:54 -070038 uint inodes_per_block_group;
swissChilib7ef65d2021-07-17 12:51:52 -070039
40 /// UNIX time of last mount
swissChilief829f32021-06-13 20:00:54 -070041 uint last_mount_time;
swissChilib7ef65d2021-07-17 12:51:52 -070042
43 /// UNIX time of last write
swissChilief829f32021-06-13 20:00:54 -070044 uint last_write_time;
swissChilib7ef65d2021-07-17 12:51:52 -070045
46 /// Number of mounts since last consistency check
swissChilief829f32021-06-13 20:00:54 -070047 ushort mounts_since_last_fsck;
swissChilib7ef65d2021-07-17 12:51:52 -070048
49 /// Number of mounts allowed between consistency checks
swissChilief829f32021-06-13 20:00:54 -070050 ushort mounts_allowed_before_fsck;
swissChilib7ef65d2021-07-17 12:51:52 -070051
52 /// EXT2 signature, should be 0xef53
swissChilief829f32021-06-13 20:00:54 -070053 ushort signature;
swissChilib7ef65d2021-07-17 12:51:52 -070054
55 /// File system state, see enum ext2_fs_state
swissChilief829f32021-06-13 20:00:54 -070056 ushort state;
swissChilib7ef65d2021-07-17 12:51:52 -070057
58 /// What to do in case of an error, see enum ext2_error_case
swissChilief829f32021-06-13 20:00:54 -070059 ushort error_case;
swissChilib7ef65d2021-07-17 12:51:52 -070060
61 /// Minor portion of version
swissChilief829f32021-06-13 20:00:54 -070062 ushort version_minor;
swissChilib7ef65d2021-07-17 12:51:52 -070063
64 /// UNIX time of last consistency check
swissChilief829f32021-06-13 20:00:54 -070065 uint last_fsck_time;
swissChilib7ef65d2021-07-17 12:51:52 -070066
67 /// Max time between consistency checks
swissChilief829f32021-06-13 20:00:54 -070068 uint fsck_time_interval;
swissChilib7ef65d2021-07-17 12:51:52 -070069
70 /// Operating system ID of creator
swissChilief829f32021-06-13 20:00:54 -070071 uint creator_os_id;
swissChilib7ef65d2021-07-17 12:51:52 -070072
73 /// Major portion of version
swissChilief829f32021-06-13 20:00:54 -070074 uint version_major;
swissChilib7ef65d2021-07-17 12:51:52 -070075
76 /// User ID that can use reserved blocks
swissChilief829f32021-06-13 20:00:54 -070077 ushort reserved_blocks_uid;
swissChilib7ef65d2021-07-17 12:51:52 -070078
79 /// Group ID that can use reserved blocks
swissChilief829f32021-06-13 20:00:54 -070080 ushort reserved_blocks_gid;
81};
82
83enum ext2_fs_state
84{
85 EXT2_STATE_CLEAN = 1,
86 EXT2_STATE_ERRORS = 2,
87};
88
89enum ext2_error_case
90{
91 EXT2_ERROR_IGNORE = 1,
92 EXT2_ERROR_REMOUNT = 2,
93 EXT2_ERROR_KPANIC = 3,
94};
95
96enum ext2_os_id
97{
98 EXT2_OS_LINUX = 0,
99 EXT2_OS_HURD,
100 EXT2_OS_MASIX,
101 EXT2_OS_FREEBSD,
102 EXT2_OS_OTHER_BSD,
103};
104
swissChili9bd74de2021-06-15 20:30:48 -0700105#define EXT2_SIGNATURE 0xef53
106
swissChilib7ef65d2021-07-17 12:51:52 -0700107struct ext2_block_group_descriptor
108{
109 /// Address of block usage bitmap
swissChili4749d022021-07-19 12:33:06 -0700110 uint block_bitmap; // 4
swissChilib7ef65d2021-07-17 12:51:52 -0700111
112 /// Address of inode usage bitmap
swissChili4749d022021-07-19 12:33:06 -0700113 uint inode_bitmap; // 8
swissChilib7ef65d2021-07-17 12:51:52 -0700114
115 /// Starting block address of inode table
swissChili4749d022021-07-19 12:33:06 -0700116 uint inode_table_start_block; // 12
swissChilib7ef65d2021-07-17 12:51:52 -0700117
118 /// Number of unallocated blocks in this group
swissChili4749d022021-07-19 12:33:06 -0700119 ushort unallocated_blocks; // 14
swissChilib7ef65d2021-07-17 12:51:52 -0700120
121 /// Number of unallocated inodes in this group
swissChili4749d022021-07-19 12:33:06 -0700122 ushort unallocated_inodes; // 16
swissChilib7ef65d2021-07-17 12:51:52 -0700123
124 /// Number of directories in this group
swissChili4749d022021-07-19 12:33:06 -0700125 ushort num_dirs; // 18
swissChilib7ef65d2021-07-17 12:51:52 -0700126
swissChili4749d022021-07-19 12:33:06 -0700127 ushort padding; // 20
swissChilib7ef65d2021-07-17 12:51:52 -0700128
swissChili4749d022021-07-19 12:33:06 -0700129 uchar reserved[12]; // 32
swissChilib7ef65d2021-07-17 12:51:52 -0700130};
131
132struct ext2_inode
133{
134 /// The format and permissions of the file, see EXT2_S_*
135 ushort mode;
swissChili4749d022021-07-19 12:33:06 -0700136
swissChilib7ef65d2021-07-17 12:51:52 -0700137 /// The user id of the owner
138 ushort uid;
139
140 /// The lower 32 bits of the file size
141 uint size;
142
143 /// Last time this was accessed in UNIX time
144 uint access_time;
145
146 /// Time this was created in UNIX time
147 uint created_time;
148
149 /// Time this was last modified in UNIX time
150 uint modified_time;
151
152 /// Time this was deleted in UNIX time
153 uint deleted_time;
154
155 /// Owner group id
156 ushort gid;
157
158 /// Reference count for hard links
159 ushort links_count;
160
161 /// Number of 512 byte blocks storing this files data, NOT EXT2 blocks!
162 uint num_blocks;
163
164 /// Flags describing how this file can be accessed
165 uint flags;
166
167 /// First field reserved for the operating system
168 uint os_reserved_1;
169
170 union
171 {
172 /// The blocks of this file
173 uint blocks[15];
174
175 struct
176 {
177 /// The direct blocks
178 uint direct_blocks[12];
179
180 /// The single indirect block
181 uint ind_block;
182
183 /// The double indirect block
184 uint ind2_block;
185
186 /// The triple indirect block
187 uint ind3_block;
188 };
189 };
190
191 /// Used by NFS to version files
192 uint generation;
193
194 /// File attributes, unused
195 uint file_acl;
196
197 /// Directory attributes, unused
198 uint dir_acl;
199
200 /// Location of file fragment, unused
201 uint faddr;
202
203 /// Second field reserved for the operating system
204 uchar os_reserved_2[12];
205};
206
207enum
208{
209 // File types
210 EXT2_S_IFSOCK = 0xc000,
211 EXT2_S_IFLINK = 0xa000,
212 EXT2_S_IFREG = 0x8000,
213 EXT2_S_IFBLK = 0x6000,
214 EXT2_S_IFDIR = 0x4000,
215 EXT2_S_IFCHR = 0x2000,
216 EXT2_S_IFIFO = 0x1000,
217
218 /// Set UID
219 EXT2_S_ISUID = 0x0800,
220 /// Set GUID
221 EXT2_S_ISGID = 0x0400,
222 /// Sticky
223 EXT2_S_ISVTX = 0x0200,
224
225 // Normal UNIX file permissions
226 EXT2_S_IRUSR = 0x0100,
227 EXT2_S_IWUSR = 0x0080,
228 EXT2_S_IXUSR = 0x0040,
229 EXT2_S_IRGRP = 0x0020,
230 EXT2_S_IWGRP = 0x0010,
231 EXT2_S_IXGRP = 0x0008,
232 EXT2_S_IROTH = 0x0004,
233 EXT2_S_IWOTH = 0x0002,
234 EXT2_S_IXOTH = 0x0001,
235};
236
swissChilicbd43632021-07-17 16:19:44 -0700237/// File type flag (used on inode->mode)
238#define EXT2_F_TYPE 0xf000
239
swissChilid98781b2021-07-25 21:04:17 -0700240const extern uchar ext2_s_to_ft[];
241
242/// Converts the file "mode" (inode->mode, EXT2_S_*) to a file type
243/// (EXT2_FT_*).
244#define EXT2_S_TO_FT(s) (ext2_s_to_ft[s >> 12])
245
swissChilib7ef65d2021-07-17 12:51:52 -0700246struct ext2_dirent
247{
248 uint inode;
249 ushort rec_len;
250 uchar name_len;
251 uchar file_type;
252 char name[];
253};
254
swissChili36ed5d72021-07-23 14:56:36 -0700255enum
256{
257 EXT2_FT_UNKNOWN = 0,
258 EXT2_FT_REGULAR_FILE,
259 EXT2_FT_DIR,
260 EXT2_FT_CHRDEV,
261 EXT2_FT_BLKDEV,
262 EXT2_FT_FIFO,
263 EXT2_FT_SOCK,
264 EXT2_FT_SYMLINK,
265};
266
swissChili480f1762021-07-26 22:17:34 -0700267inline uint ext2_block_size(struct ext2_superblock *sb)
268{
269 return 1024 << sb->block_size_shift;
270}
271
swissChilid98781b2021-07-25 21:04:17 -0700272/// Read a file system block (0-indexed), if necessary multiple disk
273/// blocks will be read automatically
274void ext2_read_block(struct ext2_superblock *sb, void *buffer,
275 uint block);
276void ext2_write_block(struct ext2_superblock *sb, void *buffer,
277 uint block);
swissChilib7ef65d2021-07-17 12:51:52 -0700278
swissChili4418ca52021-06-14 17:36:00 -0700279struct ext2_superblock ext2_read_superblock();
swissChilib7ef65d2021-07-17 12:51:52 -0700280
281void ext2_write_superblock(struct ext2_superblock *sb);
282
swissChilid98781b2021-07-25 21:04:17 -0700283/// Just for fun, corrupt the superblock (obviously don't actually do
284/// this)
swissChilib7ef65d2021-07-17 12:51:52 -0700285void ext2_corrupt_superblock_for_fun();
286
swissChilief829f32021-06-13 20:00:54 -0700287void ext2_mount(struct fs_node *where);
swissChilib7ef65d2021-07-17 12:51:52 -0700288
swissChili9bd74de2021-06-15 20:30:48 -0700289bool ext2_valid_filesystem();
swissChilib7ef65d2021-07-17 12:51:52 -0700290
swissChilid98781b2021-07-25 21:04:17 -0700291/**
292 * @brief Get or set an inode
293 * @param inode Either a pointer to the value to be read (set=false),
294 * or the value to be written (set=true).
295 * @param set True if the inode should be set (written), false
296 * otherwise.
297 */
298bool ext2_get_or_set_inode(struct ext2_superblock *sb, uint number,
299 struct ext2_inode *inode, bool set);
300
301bool ext2_find_inode(struct ext2_superblock *sb, uint number,
302 struct ext2_inode *inode);
303
304bool ext2_set_inode(struct ext2_superblock *sb, uint number,
305 struct ext2_inode *inode);
swissChilib7ef65d2021-07-17 12:51:52 -0700306
307/// Load a block group descriptor for a certain block group
swissChili480f1762021-07-26 22:17:34 -0700308struct ext2_block_group_descriptor ext2_load_bgd(
swissChilib7ef65d2021-07-17 12:51:52 -0700309 struct ext2_superblock *sb, uint block_group);
310
swissChili480f1762021-07-26 22:17:34 -0700311/// Write a block group descriptor for a certain block group
312void ext2_write_bgd(struct ext2_superblock *sb, uint block_group,
313 struct ext2_block_group_descriptor *d);
314
315/// Load or write a BGD
316void ext2_load_or_write_bgd(struct ext2_superblock *sb,
317 uint block_group,
318 struct ext2_block_group_descriptor *d,
319 bool set);
320
swissChilid98781b2021-07-25 21:04:17 -0700321/// List the contents of a directory dir. Calls `cb` for each item. If
322/// `dir` is not a directory, returns false. Otherwise returns true.
323/// if cb returns true, ls will continue. Otherwise it will stop.
swissChilib7ef65d2021-07-17 12:51:52 -0700324bool ext2_dir_ls(struct ext2_superblock *sb,
325 struct ext2_inode *dir,
swissChilid98781b2021-07-25 21:04:17 -0700326 bool (*cb)(uint inode,
swissChilib7ef65d2021-07-17 12:51:52 -0700327 const char *name,
swissChilid98781b2021-07-25 21:04:17 -0700328 uint name_len,
swissChilib7ef65d2021-07-17 12:51:52 -0700329 void *data),
330 void *data);
331
332/// Read a data block for the inode, 0 being the first block of the file.
333bool ext2_read_inode_block(struct ext2_superblock *sb,
334 struct ext2_inode *inode,
335 void *buffer,
336 uint block);
swissChilicbd43632021-07-17 16:19:44 -0700337
swissChili36ed5d72021-07-23 14:56:36 -0700338/// Write a data block for the inode, 0 being the first block of the file.
339bool ext2_write_inode_block(struct ext2_superblock *sb, struct ext2_inode *dir,
340 void *buffer, uint block);
341
swissChili480f1762021-07-26 22:17:34 -0700342ssize_t ext2_read_inode(struct ext2_superblock *sb,
343 struct ext2_inode *inode, void *buffer,
344 ssize_t size);
swissChili4749d022021-07-19 12:33:06 -0700345
346/**
347 * @brief Set a block in a bitmap
348 * @param bitmap_block The first block of the bitmap, not necessarily the block
349 * that this specific bit is in.
350 * @param index The bit to check, starting at 0
351 * @returns The value of the bit
352 */
353bool ext2_check_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
354 uint index);
355
356/**
357 * @brief Set a block in a bitmap
358 * @param bitmap_block The first block of the bitmap, not necessarily the block
359 * that this specific bit is in.
360 * @param index The bit to set, starting at 0
361 * @param value The value of the bit, 0 for 0, non-0 for 1
362 */
363void ext2_set_in_bitmap(struct ext2_superblock *sb, uint bitmap_block,
364 uint index, bool value);
365
366/**
367 * @brief Find the first zero bit in a bitset
368 * @param bitmap_block The first block of the bitmap
369 * @param num_blocks The number of blocks in the bitmap, or ~0 for no limit
370 * (UNSAFE).
371 * @param start_at The first bit to search from, useful if you want to ignore
372 * the first reserved inodes.
373 * @returns The index of the first zero bit, or -1 if there is none
374 */
375uint ext2_first_zero_bit(struct ext2_superblock *sb, uint bitmap_block,
376 uint num_blocks, uint start_at);
377
swissChili36ed5d72021-07-23 14:56:36 -0700378/**
379 * Find the first free inode number.
380 * @returns The inode if it was found, 0 if there are no free inodes.
381 */
swissChili4749d022021-07-19 12:33:06 -0700382uint ext2_first_free_inode(struct ext2_superblock *sb);
swissChili36ed5d72021-07-23 14:56:36 -0700383
384void ext2_insert_into_dir(struct ext2_superblock *sb, struct ext2_inode *dir,
385 char *name, uint name_len, uint inode, uchar type);
swissChilid98781b2021-07-25 21:04:17 -0700386
387/**
388 * Creates a hard link
389 * @param dir Directory to create the hard link in
390 * @param name Name of the link to create
391 * @param name_len length of name, not including (optional) NULL byte
392 * @param inode Inode number of link target
393 */
394bool ext2_hard_link(struct ext2_superblock *sb, struct ext2_inode *dir,
395 char *name, uint name_len, uint inode);
396
397/**
398 * @brief Does a directory contain a certain entry?
399 * @param sb Superblock
400 * @param dir The directory to search in
401 * @param name The name of the entry to look for
402 * @param len The length of the name, not including the optional NULL byte
403 * @returns True if the entry is found, false if not, or if something
404 * goes wrong (ie: dir is not a directory)
405 */
406bool ext2_dir_contains(struct ext2_superblock *sb, struct ext2_inode *dir,
407 char *name, uint len);
408
409/**
410 * @brief Find an entry in a directory
411 * @param dir Directory to search in
412 * @param name Name of file
413 * @param name_len Length of name, not including (optional) NULL byte.
414 * @returns 0 if no entry could be found, otherwise inode number for
415 * that entry
416 */
417uint ext2_dir_find(struct ext2_superblock *sb, struct ext2_inode *dir,
418 char *name, uint name_len);