1 /* 2 * Copyright (c) 2023 Antmicro <www.antmicro.com> 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #ifndef __EXT2_IMPL_H__ 8 #define __EXT2_IMPL_H__ 9 10 #include <zephyr/fs/fs.h> 11 #include <zephyr/fs/ext2.h> 12 13 #include "ext2_struct.h" 14 15 extern struct k_heap direntry_heap; 16 17 void error_behavior(struct ext2_data *fs, const char *msg); 18 19 /* Memory allocation for ext2 implementation */ 20 void *ext2_heap_alloc(size_t size); 21 void ext2_heap_free(void *ptr); 22 23 /* Initialization of disk storage. */ 24 int ext2_init_disk_access_backend(struct ext2_data *fs, const void *storage_dev, int flags); 25 26 /** 27 * @brief Get block from the disk. 28 */ 29 struct ext2_block *ext2_get_block(struct ext2_data *fs, uint32_t block); 30 31 struct ext2_block *ext2_get_empty_block(struct ext2_data *fs); 32 33 /** 34 * @brief Free the block structure. 35 */ 36 void ext2_drop_block(struct ext2_block *b); 37 38 /** 39 * @brief Write block to the disk. 40 * 41 * NOTICE: to ensure that all writes has ended the sync of disk must be triggered 42 * (fs::sync function). 43 */ 44 int ext2_write_block(struct ext2_data *fs, struct ext2_block *b); 45 46 void ext2_init_blocks_slab(struct ext2_data *fs); 47 48 /** 49 * @brief Write block to the disk. 50 * 51 * NOTICE: to ensure that all writes has ended the sync of disk must be triggered 52 * (fs::sync function). 53 */ 54 int ext2_write_block(struct ext2_data *fs, struct ext2_block *b); 55 56 int ext2_assign_block_num(struct ext2_data *fs, struct ext2_block *b); 57 58 /* FS operations */ 59 60 /** 61 * @brief Initialize structure with data needed to access the storage device 62 * 63 * @param fs File system data structure to initialize 64 * @param storage_dev Pointer to storage 65 * @param flags Additional flags (e.g. RO flag) 66 * 67 * @retval 0 on success 68 * @retval -EINVAL when superblock of ext2 was not detected 69 * @retval -ENOTSUP when described file system is not supported 70 * @retval <0 other error 71 */ 72 int ext2_init_storage(struct ext2_data **fsp, const void *storage_dev, int flags); 73 74 /** 75 * @brief Verify superblock of file system 76 * 77 * Checks if file system is supported by the implementation. 78 * @retval 0 when superblock is valid 79 * @retval -EROFS when superblock is not valid but file system may be mounted read only 80 * @retval -EINVAL when superblock is not valid and file system cannot be mounted at all 81 * @retval -ENOTSUP when superblock has some field set to value that we don't support 82 */ 83 int ext2_verify_disk_superblock(struct ext2_disk_superblock *sb); 84 85 /** 86 * @brief Initialize all data needed to perform operations on file system 87 * 88 * Fetches the superblock. Initializes structure fields. 89 */ 90 int ext2_init_fs(struct ext2_data *fs); 91 92 /** 93 * @brief Clear the data used by file system implementation 94 * 95 */ 96 int ext2_close_fs(struct ext2_data *fs); 97 98 /** 99 * @brief Clear the data used to communicate with storage device 100 * 101 */ 102 int ext2_close_struct(struct ext2_data *fs); 103 104 /** 105 * @brief Create the ext2 file system 106 * 107 * This function uses functions stored in `ext2_data` structure to create new 108 * file system on storage device. 109 * 110 * NOTICE: fs structure must be first initialized with `ext2_init_fs` function. 111 * 112 * After this function succeeds the `ext2_clean` function must be called. 113 * 114 * @param fs File system data (must be initialized before) 115 * 116 * @retval 0 on success 117 * @retval -ENOSPC when storage device is too small for ext2 file system 118 * @retval -ENOTSUP when storage device is too big (file systems with more than 119 * 8192 blocks are not supported) 120 */ 121 int ext2_format(struct ext2_data *fs, struct ext2_cfg *cfg); 122 123 /* Lookup flags */ 124 #define LOOKUP_ARG_OPEN BIT(0) 125 #define LOOKUP_ARG_CREATE BIT(1) 126 #define LOOKUP_ARG_STAT BIT(2) 127 #define LOOKUP_ARG_UNLINK BIT(3) 128 129 /* Structure for lookup arguments and results. 130 * 131 * Required fields (must be filled when lookup function is invoked): 132 * - path 133 * - flags 134 * 135 * Fields that hold the result: 136 * - inode 137 * - parent 138 * - offset 139 * - name_pos 140 * - name_len 141 * 142 * Some of these fields have a meaning only for a specific function. 143 * (E.g. during stat only the fields parent and offset are used) 144 * 145 * Field is marked with these labels when lookup is used from other function: 146 * OP -- open 147 * CR -- create 148 * ST -- stat 149 * UN -- unlink 150 */ 151 struct ext2_lookup_args { 152 const char *path; /* path of inode */ 153 struct ext2_inode *inode; /* (OP, CR, ST, UN) found inode */ 154 struct ext2_inode *parent; /* (CR, ST, UN) parent of found inode */ 155 uint32_t offset; /* (CR, ST, UN) offset of entry in directory */ 156 uint32_t name_pos; /* (CR) position of name in input path */ 157 uint32_t name_len; /* (CR) length of name */ 158 uint8_t flags; /* indicates from which function lookup is invoked */ 159 }; 160 161 /** 162 * @brief Look for an inode. 163 * 164 * @param fs File system data 165 * @param args All needed arguments for lookup 166 * 167 * @retval 0 on success 168 * @retval -ENOENT inode or path component not found 169 * @retval -ENOTDIR path component not a directory 170 * @retval <0 other error 171 */ 172 int ext2_lookup_inode(struct ext2_data *fs, struct ext2_lookup_args *args); 173 174 /* Inode operations */ 175 176 /** 177 * @brief Read from inode at given offset 178 * 179 * @param inode Inode 180 * @param buf Buffer to hold read data 181 * @param offset Offset in inode 182 * @param nbytes Number of bytes to read 183 * 184 * @retval >=0 number of bytes read on success 185 * @retval <0 error code 186 */ 187 ssize_t ext2_inode_read(struct ext2_inode *inode, void *buf, uint32_t offset, 188 size_t nbytes); 189 190 /** 191 * @brief Write to inode at given offset 192 * 193 * @param inode Inode 194 * @param buf Buffer with data to write 195 * @param offset Offset in inode 196 * @param nbytes Number of bytes to write 197 * 198 * @retval >=0 number of bytes read on success 199 * @retval <0 error code 200 */ 201 ssize_t ext2_inode_write(struct ext2_inode *inode, const void *buf, 202 uint32_t offset, size_t nbytes); 203 204 /** 205 * @brief Truncate the inode 206 * 207 * @param inode Inode 208 * @param size New size for inode 209 * 210 * @retval 0 on success 211 * @retval -ENOTSUP when requested size is too big 212 * @retval <0 other error 213 */ 214 int ext2_inode_trunc(struct ext2_inode *inode, off_t size); 215 216 /** 217 * @brief Sync currently fetched blocks 218 * 219 * @param inode Inode 220 * 221 */ 222 int ext2_inode_sync(struct ext2_inode *inode); 223 224 /* Directory operations */ 225 226 /** 227 * @brief Get directory entry 228 * 229 * Reads directory entry that is at offset specified in `ext2_file` structure. 230 * 231 * @param dir Read directory 232 * @param ent Directory entry to fill in 233 * 234 * @retval 0 on success 235 * @retval <0 on error 236 */ 237 int ext2_get_direntry(struct ext2_file *dir, struct fs_dirent *ent); 238 239 /** 240 * @brief Create a directory entry with given attributes 241 * 242 * Automatically calculates and sets de_rec_len field. 243 * 244 * NOTE: if you need to adjust the size (e.g. when this entry is the last one in the block) 245 * then just update the size after this function returns. 246 * 247 * @param name Name of direntry 248 * @param namelen Length of name 249 * @param ino Inode associated with that entry 250 * @param filetype File type of that entry 251 * 252 * @returns structure allocated on direntry_heap filled with given data 253 */ 254 struct ext2_direntry *ext2_create_direntry(const char *name, uint8_t namelen, uint32_t ino, 255 uint8_t filetype); 256 257 /** 258 * @brief Create a file 259 * 260 * @param parent Parent directory 261 * @param inode Pointer to inode structure that will be filled with new inode 262 * @param args Lookup arguments that describe file to create 263 * 264 * @retval 0 on success 265 * @retval -ENOSPC there is not enough memory on storage device to create a file 266 * @retval <0 on error 267 */ 268 int ext2_create_file(struct ext2_inode *parent, struct ext2_inode *inode, 269 struct ext2_lookup_args *args); 270 271 272 /** 273 * @brief Create a directory 274 * 275 * @param parent Parent directory 276 * @param inode Pointer to inode structure that will be filled with new inode 277 * @param args Lookup arguments that describe directory to create 278 * 279 * @retval 0 on success 280 * @retval -ENOSPC there is not enough memory on storage device to create a file 281 * @retval <0 on error 282 */ 283 int ext2_create_dir(struct ext2_inode *parent, struct ext2_inode *inode, 284 struct ext2_lookup_args *args); 285 286 /** 287 * @brief Unlink the directory entry at given offset in parent directory 288 * 289 * @param parent Parent directory 290 * @param inode File to unlink 291 * @param offset Offset of unlinked file in the parent directory 292 * 293 * @retval 0 on success 294 * @retval -ENOTEMPTY when directory to unlink is not empty 295 * @retval <0 other error 296 */ 297 int ext2_inode_unlink(struct ext2_inode *parent, struct ext2_inode *inode, 298 uint32_t offset); 299 300 /** 301 * @brief Move a file 302 * 303 * Invoked when rename destination entry doesn't exist. 304 * 305 * @param args_from Describe source file 306 * @param args_to Describe destination 307 * 308 * @retval 0 on success 309 * @retval <0 on error 310 */ 311 int ext2_move_file(struct ext2_lookup_args *args_from, struct ext2_lookup_args *args_to); 312 313 /** 314 * @brief Replace the file with another 315 * 316 * Invoked when rename destination entry does exist 317 * 318 * @param args_from Describe source file 319 * @param args_to Describe destination file 320 * 321 * @retval 0 on success 322 * @retval <0 on error 323 */ 324 int ext2_replace_file(struct ext2_lookup_args *args_from, struct ext2_lookup_args *args_to); 325 326 /* Inode pool operations */ 327 328 /** 329 * @brief Get the inode 330 * 331 * Retrieves inode structure and stores it in the inode pool. The inode is 332 * filled with data of requested inode. 333 * 334 * @param fs File system data 335 * @param ino Inode number 336 * @param ret Pointer to place where to store new inode pointer 337 * 338 * @retval 0 on success 339 * @retval -ENOMEM when there is no memory to hold the requested inode 340 * @retval <0 on error 341 */ 342 int ext2_inode_get(struct ext2_data *fs, uint32_t ino, struct ext2_inode **ret); 343 344 /** 345 * @brief Remove reference to the inode structure 346 * 347 * When removed reference is the last reference to that inode then it is freed. 348 * 349 * @param inode Dropped inode 350 * 351 * @retval 0 on success 352 * @retval -EINVAL the dropped inode is not stored in the inode pool 353 * @retval <0 on error 354 */ 355 int ext2_inode_drop(struct ext2_inode *inode); 356 357 /* Drop blocks fetched in inode structure. */ 358 void ext2_inode_drop_blocks(struct ext2_inode *inode); 359 360 /** 361 * @brief Remove all blocks starting with some block 362 * 363 * @param first First block to remove 364 * 365 * @retval >=0 number of removed blocks 366 * @retval <0 error code 367 */ 368 int64_t ext2_inode_remove_blocks(struct ext2_inode *inode, uint32_t first); 369 370 #endif /* __EXT2_IMPL_H__ */ 371