Changeset 38542dc in mainline
- Timestamp:
- 2012-08-12T18:36:10Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 49505fe
- Parents:
- b08e7970
- Location:
- uspace
- Files:
-
- 32 edited
-
app/testwrit/testwrit.c (modified) (3 diffs)
-
lib/ext4/Makefile (modified) (2 diffs)
-
lib/ext4/libext4.h (modified) (2 diffs)
-
lib/ext4/libext4_balloc.c (modified) (12 diffs)
-
lib/ext4/libext4_balloc.h (modified) (2 diffs)
-
lib/ext4/libext4_bitmap.c (modified) (12 diffs)
-
lib/ext4/libext4_bitmap.h (modified) (2 diffs)
-
lib/ext4/libext4_block_group.c (modified) (9 diffs)
-
lib/ext4/libext4_block_group.h (modified) (2 diffs)
-
lib/ext4/libext4_crc.c (modified) (3 diffs)
-
lib/ext4/libext4_crc.h (modified) (2 diffs)
-
lib/ext4/libext4_directory.c (modified) (18 diffs)
-
lib/ext4/libext4_directory.h (modified) (2 diffs)
-
lib/ext4/libext4_directory_index.c (modified) (33 diffs)
-
lib/ext4/libext4_directory_index.h (modified) (2 diffs)
-
lib/ext4/libext4_extent.c (modified) (40 diffs)
-
lib/ext4/libext4_extent.h (modified) (3 diffs)
-
lib/ext4/libext4_filesystem.c (modified) (47 diffs)
-
lib/ext4/libext4_filesystem.h (modified) (2 diffs)
-
lib/ext4/libext4_hash.c (modified) (12 diffs)
-
lib/ext4/libext4_hash.h (modified) (1 diff)
-
lib/ext4/libext4_ialloc.c (modified) (10 diffs)
-
lib/ext4/libext4_ialloc.h (modified) (2 diffs)
-
lib/ext4/libext4_inode.c (modified) (33 diffs)
-
lib/ext4/libext4_inode.h (modified) (3 diffs)
-
lib/ext4/libext4_superblock.c (modified) (92 diffs)
-
lib/ext4/libext4_superblock.h (modified) (5 diffs)
-
lib/ext4/libext4_types.h (modified) (16 diffs)
-
srv/fs/ext4fs/Makefile (modified) (1 diff)
-
srv/fs/ext4fs/ext4fs.c (modified) (3 diffs)
-
srv/fs/ext4fs/ext4fs.h (modified) (1 diff)
-
srv/fs/ext4fs/ext4fs_ops.c (modified) (63 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/testwrit/testwrit.c
rb08e7970 r38542dc 31 31 */ 32 32 33 34 33 #include <stdio.h> 35 34 #include <unistd.h> 36 35 37 #define BUF_SIZE 102436 #define BUF_SIZE 1024 38 37 39 int main(int argc, char * *argv)38 int main(int argc, char *argv[]) 40 39 { 41 42 40 char buffer[BUF_SIZE]; 43 41 uint64_t iterations, i; … … 47 45 /* Prepare some example data */ 48 46 memset(buffer, 0xcafebabe, BUF_SIZE); 49 47 50 48 if (argc != 3) { 51 49 printf("syntax: testwrit <iterations> <target file>\n"); 52 50 return 1; 53 51 } 54 52 55 53 char *end; 56 54 iterations = strtoul(argv[1], &end, 10); 57 55 file_name = argv[2]; 58 56 59 57 /* Open target file */ 60 58 file = fopen(file_name, "a"); … … 70 68 71 69 fclose(file); 72 70 73 71 return 0; 74 72 } 75 76 73 77 74 /** -
uspace/lib/ext4/Makefile
rb08e7970 r38542dc 29 29 USPACE_PREFIX = ../.. 30 30 LIBRARY = libext4 31 EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBPOSIX_PREFIX)32 LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBPOSIX_PREFIX)/libposix.a31 EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) 32 LIBS = $(LIBBLOCK_PREFIX)/libblock.a 33 33 34 34 SOURCES = \ … … 45 45 libext4_inode.c \ 46 46 libext4_superblock.c 47 48 47 49 48 include $(USPACE_PREFIX)/Makefile.common -
uspace/lib/ext4/libext4.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_H_ … … 49 49 50 50 #include <stdio.h> 51 #define EXT4FS_DBG(format, ...) {printf("ext4fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);} 51 #define EXT4FS_DBG(format, ...) \ 52 printf("ext4fs: %s: " format "\n", \ 53 __FUNCTION__, ##__VA_ARGS__) \ 52 54 53 55 #endif -
uspace/lib/ext4/libext4_balloc.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_balloc.c35 * @brief Physical block allocator.33 * @file libext4_balloc.c 34 * @brief Physical block allocator. 36 35 */ 37 36 … … 42 41 /** Compute number of block group from block address. 43 42 * 44 * @param sb superblock pointer 45 * @param block_addr absolute address of block 46 * @return block group index 43 * @param sb Superblock pointer. 44 * @param block_addr Absolute address of block. 45 * 46 * @return Block group index 47 * 47 48 */ 48 49 static uint32_t ext4_balloc_get_bgid_of_block(ext4_superblock_t *sb, 49 uint32_t block_addr)50 uint32_t block_addr) 50 51 { 51 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb); 52 uint32_t first_block = ext4_superblock_get_first_data_block(sb); 53 52 uint32_t blocks_per_group = 53 ext4_superblock_get_blocks_per_group(sb); 54 uint32_t first_block = 55 ext4_superblock_get_first_data_block(sb); 56 54 57 /* First block == 0 or 1 */ 55 if (first_block == 0) {58 if (first_block == 0) 56 59 return block_addr / blocks_per_group; 57 } else {60 else 58 61 return (block_addr - 1) / blocks_per_group; 59 }60 62 } 61 63 62 64 /** Free block. 63 65 * 64 * @param inode_ref inode, where the block is allocated 65 * @param block_addr absolute block address to free 66 * @return error code 66 * @param inode_ref Inode, where the block is allocated 67 * @param block_addr Absolute block address to free 68 * 69 * @return Error code 70 * 67 71 */ 68 72 int ext4_balloc_free_block(ext4_inode_ref_t *inode_ref, uint32_t block_addr) 69 73 { 70 int rc;71 72 74 ext4_filesystem_t *fs = inode_ref->fs; 73 75 ext4_superblock_t *sb = fs->superblock; 74 76 75 77 /* Compute indexes */ 76 78 uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, block_addr); 77 79 uint32_t index_in_group = 78 ext4_filesystem_blockaddr2_index_in_group(sb, block_addr);79 80 ext4_filesystem_blockaddr2_index_in_group(sb, block_addr); 81 80 82 /* Load block group reference */ 81 83 ext4_block_group_ref_t *bg_ref; 82 rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref); 83 if (rc != EOK) { 84 return rc; 85 } 86 84 int rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref); 85 if (rc != EOK) 86 return rc; 87 87 88 /* Load block with bitmap */ 88 uint32_t bitmap_block_addr = ext4_block_group_get_block_bitmap(89 bg_ref->block_group, sb);89 uint32_t bitmap_block_addr = 90 ext4_block_group_get_block_bitmap(bg_ref->block_group, sb); 90 91 block_t *bitmap_block; 91 92 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0); 92 if (rc != EOK) { 93 return rc; 94 } 95 93 if (rc != EOK) 94 return rc; 95 96 96 /* Modify bitmap */ 97 97 ext4_bitmap_free_bit(bitmap_block->data, index_in_group); 98 98 bitmap_block->dirty = true; 99 100 99 101 100 /* Release block with bitmap */ 102 101 rc = block_put(bitmap_block); … … 106 105 return rc; 107 106 } 108 107 109 108 uint32_t block_size = ext4_superblock_get_block_size(sb); 110 109 111 110 /* Update superblock free blocks count */ 112 uint32_t sb_free_blocks = ext4_superblock_get_free_blocks_count(sb); 111 uint32_t sb_free_blocks = 112 ext4_superblock_get_free_blocks_count(sb); 113 113 sb_free_blocks++; 114 114 ext4_superblock_set_free_blocks_count(sb, sb_free_blocks); 115 115 116 116 /* Update inode blocks count */ 117 uint64_t ino_blocks = ext4_inode_get_blocks_count(sb, inode_ref->inode); 117 uint64_t ino_blocks = 118 ext4_inode_get_blocks_count(sb, inode_ref->inode); 118 119 ino_blocks -= block_size / EXT4_INODE_BLOCK_SIZE; 119 120 ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks); 120 121 inode_ref->dirty = true; 121 122 122 123 /* Update block group free blocks count */ 123 uint32_t free_blocks = ext4_block_group_get_free_blocks_count(124 bg_ref->block_group, sb);124 uint32_t free_blocks = 125 ext4_block_group_get_free_blocks_count(bg_ref->block_group, sb); 125 126 free_blocks++; 126 127 ext4_block_group_set_free_blocks_count(bg_ref->block_group, 127 sb, free_blocks);128 sb, free_blocks); 128 129 bg_ref->dirty = true; 129 130 130 131 /* Release block group reference */ 131 132 rc = ext4_filesystem_put_block_group_ref(bg_ref); 132 if (rc != EOK) { 133 return rc; 134 } 135 133 if (rc != EOK) 134 return rc; 135 136 136 return EOK; 137 137 } 138 138 139 140 139 /** Free continuous set of blocks. 141 140 * 142 * @param inode_ref inode, where the blocks are allocated 143 * @param first first block to release 144 * @param count number of blocks to release 141 * @param inode_ref Inode, where the blocks are allocated 142 * @param first First block to release 143 * @param count Number of blocks to release 144 * 145 145 */ 146 146 int ext4_balloc_free_blocks(ext4_inode_ref_t *inode_ref, 147 uint32_t first, uint32_t count)147 uint32_t first, uint32_t count) 148 148 { 149 int rc;150 151 149 ext4_filesystem_t *fs = inode_ref->fs; 152 150 ext4_superblock_t *sb = fs->superblock; 153 151 154 152 /* Compute indexes */ 155 153 uint32_t block_group_first = 156 ext4_balloc_get_bgid_of_block(sb, first);154 ext4_balloc_get_bgid_of_block(sb, first); 157 155 uint32_t block_group_last = 158 ext4_balloc_get_bgid_of_block(sb, first + count - 1);159 156 ext4_balloc_get_bgid_of_block(sb, first + count - 1); 157 160 158 assert(block_group_first == block_group_last); 161 159 162 160 /* Load block group reference */ 163 161 ext4_block_group_ref_t *bg_ref; 164 rc = ext4_filesystem_get_block_group_ref(fs, block_group_first, &bg_ref); 165 if (rc != EOK) { 166 return rc; 167 } 168 162 int rc = ext4_filesystem_get_block_group_ref(fs, block_group_first, &bg_ref); 163 if (rc != EOK) 164 return rc; 165 169 166 uint32_t index_in_group_first = 170 ext4_filesystem_blockaddr2_index_in_group(sb, first); 171 172 167 ext4_filesystem_blockaddr2_index_in_group(sb, first); 168 173 169 /* Load block with bitmap */ 174 uint32_t bitmap_block_addr = ext4_block_group_get_block_bitmap(175 bg_ref->block_group, sb);176 170 uint32_t bitmap_block_addr = 171 ext4_block_group_get_block_bitmap(bg_ref->block_group, sb); 172 177 173 block_t *bitmap_block; 178 174 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0); 179 if (rc != EOK) { 180 return rc; 181 } 182 175 if (rc != EOK) 176 return rc; 177 183 178 /* Modify bitmap */ 184 179 ext4_bitmap_free_bits(bitmap_block->data, index_in_group_first, count); 185 180 bitmap_block->dirty = true; 186 181 187 182 /* Release block with bitmap */ 188 183 rc = block_put(bitmap_block); … … 192 187 return rc; 193 188 } 194 189 195 190 uint32_t block_size = ext4_superblock_get_block_size(sb); 196 191 197 192 /* Update superblock free blocks count */ 198 uint32_t sb_free_blocks = ext4_superblock_get_free_blocks_count(sb); 193 uint32_t sb_free_blocks = 194 ext4_superblock_get_free_blocks_count(sb); 199 195 sb_free_blocks += count; 200 196 ext4_superblock_set_free_blocks_count(sb, sb_free_blocks); 201 197 202 198 /* Update inode blocks count */ 203 uint64_t ino_blocks = ext4_inode_get_blocks_count(sb, inode_ref->inode); 199 uint64_t ino_blocks = 200 ext4_inode_get_blocks_count(sb, inode_ref->inode); 204 201 ino_blocks -= count * (block_size / EXT4_INODE_BLOCK_SIZE); 205 202 ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks); 206 203 inode_ref->dirty = true; 207 204 208 205 /* Update block group free blocks count */ 209 uint32_t free_blocks = ext4_block_group_get_free_blocks_count(210 bg_ref->block_group, sb);206 uint32_t free_blocks = 207 ext4_block_group_get_free_blocks_count(bg_ref->block_group, sb); 211 208 free_blocks += count; 212 209 ext4_block_group_set_free_blocks_count(bg_ref->block_group, 213 sb, free_blocks);210 sb, free_blocks); 214 211 bg_ref->dirty = true; 215 212 216 213 /* Release block group reference */ 217 214 rc = ext4_filesystem_put_block_group_ref(bg_ref); 218 if (rc != EOK) { 219 return rc; 220 } 221 215 if (rc != EOK) 216 return rc; 217 222 218 return EOK; 223 219 } … … 225 221 /** Compute first block for data in block group. 226 222 * 227 * @param sb pointer to superblock 228 * @param bg pointer to block group 229 * @param bgid index of block group 230 * @return absolute block index of first block 231 */ 232 uint32_t ext4_balloc_get_first_data_block_in_group( 233 ext4_superblock_t *sb, ext4_block_group_ref_t *bg_ref) 223 * @param sb Pointer to superblock 224 * @param bg Pointer to block group 225 * @param bgid Index of block group 226 * 227 * @return Absolute block index of first block 228 * 229 */ 230 uint32_t ext4_balloc_get_first_data_block_in_group(ext4_superblock_t *sb, 231 ext4_block_group_ref_t *bg_ref) 234 232 { 235 233 uint32_t block_group_count = ext4_superblock_get_block_group_count(sb); 236 uint32_t inode_table_first_block = ext4_block_group_get_inode_table_first_block(237 bg_ref->block_group, sb);234 uint32_t inode_table_first_block = 235 ext4_block_group_get_inode_table_first_block(bg_ref->block_group, sb); 238 236 uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb); 239 237 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb); 240 238 uint32_t block_size = ext4_superblock_get_block_size(sb); 241 239 uint32_t inode_table_bytes; 242 240 243 241 if (bg_ref->index < block_group_count - 1) { 244 242 inode_table_bytes = inodes_per_group * inode_table_item_size; 245 243 } else { 246 /* last block group could be smaller */244 /* Last block group could be smaller */ 247 245 uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb); 248 246 inode_table_bytes = 249 (inodes_count_total - ((block_group_count - 1) * inodes_per_group))250 *inode_table_item_size;251 } 252 247 (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) * 248 inode_table_item_size; 249 } 250 253 251 uint32_t inode_table_blocks = inode_table_bytes / block_size; 254 255 if (inode_table_bytes % block_size) {252 253 if (inode_table_bytes % block_size) 256 254 inode_table_blocks++; 257 } 258 255 259 256 return inode_table_first_block + inode_table_blocks; 260 257 } … … 262 259 /** Compute 'goal' for allocation algorithm. 263 260 * 264 * @param inode_ref reference to inode, to allocate block for 265 * @return goal block number 261 * @param inode_ref Reference to inode, to allocate block for 262 * 263 * @return Goal block number 264 * 266 265 */ 267 266 static uint32_t ext4_balloc_find_goal(ext4_inode_ref_t *inode_ref) 268 267 { 269 int rc;270 268 uint32_t goal = 0; 271 269 272 270 ext4_superblock_t *sb = inode_ref->fs->superblock; 273 271 274 272 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode); 275 273 uint32_t block_size = ext4_superblock_get_block_size(sb); 276 274 uint32_t inode_block_count = inode_size / block_size; 277 278 if (inode_size % block_size != 0) {275 276 if (inode_size % block_size != 0) 279 277 inode_block_count++; 280 } 281 278 282 279 /* If inode has some blocks, get last block address + 1 */ 283 280 if (inode_block_count > 0) { 284 285 rc = ext4_filesystem_get_inode_data_block_index(inode_ref,inode_block_count - 1, &goal);286 if (rc != EOK) {281 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 282 inode_block_count - 1, &goal); 283 if (rc != EOK) 287 284 return 0; 288 } 289 285 290 286 if (goal != 0) { 291 287 goal++; 292 288 return goal; 293 289 } 294 295 /* if goal == 0, sparse file -> continue */296 } 297 290 291 /* If goal == 0, sparse file -> continue */ 292 } 293 298 294 /* Identify block group of inode */ 299 295 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb); 300 296 uint32_t block_group = (inode_ref->index - 1) / inodes_per_group; 301 297 block_size = ext4_superblock_get_block_size(sb); 302 298 303 299 /* Load block group reference */ 304 300 ext4_block_group_ref_t *bg_ref; 305 rc = ext4_filesystem_get_block_group_ref(inode_ref->fs, block_group, &bg_ref); 306 if (rc != EOK) { 301 int rc = ext4_filesystem_get_block_group_ref(inode_ref->fs, 302 block_group, &bg_ref); 303 if (rc != EOK) 307 304 return 0; 308 } 309 305 310 306 /* Compute indexes */ 311 307 uint32_t block_group_count = ext4_superblock_get_block_group_count(sb); 312 uint32_t inode_table_first_block = ext4_block_group_get_inode_table_first_block(313 bg_ref->block_group, sb);308 uint32_t inode_table_first_block = 309 ext4_block_group_get_inode_table_first_block(bg_ref->block_group, sb); 314 310 uint16_t inode_table_item_size = ext4_superblock_get_inode_size(sb); 315 311 uint32_t inode_table_bytes; 316 312 317 313 /* Check for last block group */ 318 314 if (block_group < block_group_count - 1) { 319 315 inode_table_bytes = inodes_per_group * inode_table_item_size; 320 316 } else { 321 /* last block group could be smaller */317 /* Last block group could be smaller */ 322 318 uint32_t inodes_count_total = ext4_superblock_get_inodes_count(sb); 323 319 inode_table_bytes = 324 (inodes_count_total - ((block_group_count - 1) * inodes_per_group))325 *inode_table_item_size;326 } 327 320 (inodes_count_total - ((block_group_count - 1) * inodes_per_group)) * 321 inode_table_item_size; 322 } 323 328 324 uint32_t inode_table_blocks = inode_table_bytes / block_size; 329 330 if (inode_table_bytes % block_size) {325 326 if (inode_table_bytes % block_size) 331 327 inode_table_blocks++; 332 } 333 328 334 329 goal = inode_table_first_block + inode_table_blocks; 335 330 336 331 ext4_filesystem_put_block_group_ref(bg_ref); 337 332 338 333 return goal; 339 334 } … … 341 336 /** Data block allocation algorithm. 342 337 * 343 * @param inode_ref inode to allocate block for 344 * @param fblock allocated block address 345 * @return error code 346 */ 347 int ext4_balloc_alloc_block( 348 ext4_inode_ref_t *inode_ref, uint32_t *fblock) 338 * @param inode_ref Inode to allocate block for 339 * @param fblock Allocated block address 340 * 341 * @return Error code 342 * 343 */ 344 int ext4_balloc_alloc_block(ext4_inode_ref_t *inode_ref, uint32_t *fblock) 349 345 { 350 int rc;351 346 uint32_t allocated_block = 0; 352 347 353 348 uint32_t bitmap_block_addr; 354 349 block_t *bitmap_block; 355 350 uint32_t rel_block_idx = 0; 356 351 357 352 /* Find GOAL */ 358 353 uint32_t goal = ext4_balloc_find_goal(inode_ref); … … 361 356 return ENOSPC; 362 357 } 363 358 364 359 ext4_superblock_t *sb = inode_ref->fs->superblock; 365 360 366 361 /* Load block group number for goal and relative index */ 367 362 uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, goal); 368 363 uint32_t index_in_group = 369 ext4_filesystem_blockaddr2_index_in_group(sb, goal); 370 371 364 ext4_filesystem_blockaddr2_index_in_group(sb, goal); 365 372 366 /* Load block group reference */ 373 367 ext4_block_group_ref_t *bg_ref; 374 rc = ext4_filesystem_get_block_group_ref(inode_ref->fs, block_group, &bg_ref);375 if (rc != EOK) {376 return rc;377 }378 368 int rc = ext4_filesystem_get_block_group_ref(inode_ref->fs, 369 block_group, &bg_ref); 370 if (rc != EOK) 371 return rc; 372 379 373 /* Compute indexes */ 380 374 uint32_t first_in_group = 381 ext4_balloc_get_first_data_block_in_group(sb, bg_ref);382 383 uint32_t first_in_group_index = ext4_filesystem_blockaddr2_index_in_group(384 sb, first_in_group);385 386 if (index_in_group < first_in_group_index) {375 ext4_balloc_get_first_data_block_in_group(sb, bg_ref); 376 377 uint32_t first_in_group_index = 378 ext4_filesystem_blockaddr2_index_in_group(sb, first_in_group); 379 380 if (index_in_group < first_in_group_index) 387 381 index_in_group = first_in_group_index; 388 } 389 382 390 383 /* Load block with bitmap */ 391 bitmap_block_addr = ext4_block_group_get_block_bitmap(392 bg_ref->block_group, sb);393 384 bitmap_block_addr = 385 ext4_block_group_get_block_bitmap(bg_ref->block_group, sb); 386 394 387 rc = block_get(&bitmap_block, inode_ref->fs->device, 395 bitmap_block_addr, BLOCK_FLAGS_NONE);388 bitmap_block_addr, BLOCK_FLAGS_NONE); 396 389 if (rc != EOK) { 397 390 ext4_filesystem_put_block_group_ref(bg_ref); 398 391 return rc; 399 392 } 400 393 401 394 /* Check if goal is free */ 402 395 if (ext4_bitmap_is_free_bit(bitmap_block->data, index_in_group)) { … … 408 401 return rc; 409 402 } 410 411 allocated_block = ext4_filesystem_index_in_group2blockaddr( 412 sb, index_in_group, block_group); 413 403 404 allocated_block = 405 ext4_filesystem_index_in_group2blockaddr(sb, index_in_group, 406 block_group); 407 414 408 goto success; 415 416 }417 418 uint32_t blocks_in_group =ext4_superblock_get_blocks_in_group(sb, block_group);419 409 } 410 411 uint32_t blocks_in_group = 412 ext4_superblock_get_blocks_in_group(sb, block_group); 413 420 414 uint32_t end_idx = (index_in_group + 63) & ~63; 421 if (end_idx > blocks_in_group) {415 if (end_idx > blocks_in_group) 422 416 end_idx = blocks_in_group; 423 } 424 417 425 418 /* Try to find free block near to goal */ 426 for (uint32_t tmp_idx = index_in_group + 1; tmp_idx < end_idx; ++tmp_idx) { 419 for (uint32_t tmp_idx = index_in_group + 1; tmp_idx < end_idx; 420 ++tmp_idx) { 427 421 if (ext4_bitmap_is_free_bit(bitmap_block->data, tmp_idx)) { 428 429 422 ext4_bitmap_set_bit(bitmap_block->data, tmp_idx); 430 423 bitmap_block->dirty = true; 431 424 rc = block_put(bitmap_block); 432 if (rc != EOK) {425 if (rc != EOK) 433 426 return rc; 434 }435 436 allocated_block = ext4_filesystem_index_in_group2blockaddr(437 sb, tmp_idx,block_group);438 427 428 allocated_block = 429 ext4_filesystem_index_in_group2blockaddr(sb, tmp_idx, 430 block_group); 431 439 432 goto success; 440 433 } 441 442 } 443 434 } 435 444 436 /* Find free BYTE in bitmap */ 445 rc = ext4_bitmap_find_free_byte_and_set_bit(bitmap_block->data, index_in_group, &rel_block_idx, blocks_in_group); 437 rc = ext4_bitmap_find_free_byte_and_set_bit(bitmap_block->data, 438 index_in_group, &rel_block_idx, blocks_in_group); 446 439 if (rc == EOK) { 447 440 bitmap_block->dirty = true; 448 441 rc = block_put(bitmap_block); 449 if (rc != EOK) {442 if (rc != EOK) 450 443 return rc; 451 }452 453 allocated_block = ext4_filesystem_index_in_group2blockaddr(454 sb, rel_block_idx,block_group);455 444 445 allocated_block = 446 ext4_filesystem_index_in_group2blockaddr(sb, rel_block_idx, 447 block_group); 448 456 449 goto success; 457 450 } 458 451 459 452 /* Find free bit in bitmap */ 460 rc = ext4_bitmap_find_free_bit_and_set(bitmap_block->data, index_in_group, &rel_block_idx, blocks_in_group); 453 rc = ext4_bitmap_find_free_bit_and_set(bitmap_block->data, 454 index_in_group, &rel_block_idx, blocks_in_group); 461 455 if (rc == EOK) { 462 456 bitmap_block->dirty = true; 463 457 rc = block_put(bitmap_block); 464 if (rc != EOK) {458 if (rc != EOK) 465 459 return rc; 466 }467 468 allocated_block = ext4_filesystem_index_in_group2blockaddr(469 sb, rel_block_idx,block_group);470 460 461 allocated_block = 462 ext4_filesystem_index_in_group2blockaddr(sb, rel_block_idx, 463 block_group); 464 471 465 goto success; 472 466 } 473 467 474 468 /* No free block found yet */ 475 469 block_put(bitmap_block); 476 470 ext4_filesystem_put_block_group_ref(bg_ref); 477 471 478 472 /* Try other block groups */ 479 473 uint32_t block_group_count = ext4_superblock_get_block_group_count(sb); 480 474 481 475 uint32_t bgid = (block_group + 1) % block_group_count; 482 476 uint32_t count = block_group_count; 483 477 484 478 while (count > 0) { 485 rc = ext4_filesystem_get_block_group_ref(inode_ref->fs, bgid, &bg_ref); 486 if (rc != EOK) { 479 rc = ext4_filesystem_get_block_group_ref(inode_ref->fs, bgid, 480 &bg_ref); 481 if (rc != EOK) 487 482 return rc; 488 } 489 483 490 484 /* Load block with bitmap */ 491 bitmap_block_addr = ext4_block_group_get_block_bitmap( 492 bg_ref->block_group, sb); 493 494 rc = block_get(&bitmap_block, inode_ref->fs->device, bitmap_block_addr, 0); 485 bitmap_block_addr = 486 ext4_block_group_get_block_bitmap(bg_ref->block_group, sb); 487 488 rc = block_get(&bitmap_block, inode_ref->fs->device, 489 bitmap_block_addr, 0); 495 490 if (rc != EOK) { 496 491 ext4_filesystem_put_block_group_ref(bg_ref); 497 492 return rc; 498 493 } 499 494 500 495 /* Compute indexes */ 501 first_in_group = ext4_balloc_get_first_data_block_in_group(502 sb, bg_ref);503 index_in_group = ext4_filesystem_blockaddr2_index_in_group(sb,504 first_in_group);496 first_in_group = 497 ext4_balloc_get_first_data_block_in_group(sb, bg_ref); 498 index_in_group = 499 ext4_filesystem_blockaddr2_index_in_group(sb, first_in_group); 505 500 blocks_in_group = ext4_superblock_get_blocks_in_group(sb, bgid); 506 507 first_in_group_index = ext4_filesystem_blockaddr2_index_in_group(508 sb, first_in_group);509 510 if (index_in_group < first_in_group_index) {501 502 first_in_group_index = 503 ext4_filesystem_blockaddr2_index_in_group(sb, first_in_group); 504 505 if (index_in_group < first_in_group_index) 511 506 index_in_group = first_in_group_index; 512 } 513 507 514 508 /* Try to find free byte in bitmap */ 515 509 rc = ext4_bitmap_find_free_byte_and_set_bit(bitmap_block->data, 516 index_in_group, &rel_block_idx, blocks_in_group);510 index_in_group, &rel_block_idx, blocks_in_group); 517 511 if (rc == EOK) { 518 512 bitmap_block->dirty = true; 519 513 rc = block_put(bitmap_block); 520 if (rc != EOK) {514 if (rc != EOK) 521 515 return rc; 522 }523 524 allocated_block = ext4_filesystem_index_in_group2blockaddr(525 sb, rel_block_idx,bgid);526 516 517 allocated_block = 518 ext4_filesystem_index_in_group2blockaddr(sb, rel_block_idx, 519 bgid); 520 527 521 goto success; 528 522 } 529 523 530 524 /* Try to find free bit in bitmap */ 531 rc = ext4_bitmap_find_free_bit_and_set(bitmap_block->data, index_in_group, &rel_block_idx, blocks_in_group); 525 rc = ext4_bitmap_find_free_bit_and_set(bitmap_block->data, 526 index_in_group, &rel_block_idx, blocks_in_group); 532 527 if (rc == EOK) { 533 528 bitmap_block->dirty = true; 534 529 rc = block_put(bitmap_block); 535 if (rc != EOK) {530 if (rc != EOK) 536 531 return rc; 537 }538 539 allocated_block = ext4_filesystem_index_in_group2blockaddr(540 sb, rel_block_idx,bgid);541 532 533 allocated_block = 534 ext4_filesystem_index_in_group2blockaddr(sb, rel_block_idx, 535 bgid); 536 542 537 goto success; 543 538 } 544 539 545 540 block_put(bitmap_block); 546 541 ext4_filesystem_put_block_group_ref(bg_ref); 547 542 548 543 /* Goto next group */ 549 544 bgid = (bgid + 1) % block_group_count; 550 545 count--; 551 546 } 552 547 553 548 return ENOSPC; 554 549 555 550 success: 556 ; /* Empty command - because of syntax */ 551 /* Empty command - because of syntax */ 552 ; 557 553 558 554 uint32_t block_size = ext4_superblock_get_block_size(sb); 559 555 560 556 /* Update superblock free blocks count */ 561 557 uint32_t sb_free_blocks = ext4_superblock_get_free_blocks_count(sb); 562 558 sb_free_blocks--; 563 559 ext4_superblock_set_free_blocks_count(sb, sb_free_blocks); 564 560 565 561 /* Update inode blocks (different block size!) count */ 566 uint64_t ino_blocks = ext4_inode_get_blocks_count(sb, inode_ref->inode); 562 uint64_t ino_blocks = 563 ext4_inode_get_blocks_count(sb, inode_ref->inode); 567 564 ino_blocks += block_size / EXT4_INODE_BLOCK_SIZE; 568 565 ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks); 569 566 inode_ref->dirty = true; 570 567 571 568 /* Update block group free blocks count */ 572 uint32_t bg_free_blocks = ext4_block_group_get_free_blocks_count(573 bg_ref->block_group, sb);569 uint32_t bg_free_blocks = 570 ext4_block_group_get_free_blocks_count(bg_ref->block_group, sb); 574 571 bg_free_blocks--; 575 ext4_block_group_set_free_blocks_count(bg_ref->block_group, sb, bg_free_blocks); 572 ext4_block_group_set_free_blocks_count(bg_ref->block_group, sb, 573 bg_free_blocks); 576 574 bg_ref->dirty = true; 577 575 578 576 ext4_filesystem_put_block_group_ref(bg_ref); 579 577 580 578 *fblock = allocated_block; 581 579 return EOK; … … 584 582 /** Try to allocate concrete block. 585 583 * 586 * @param inode_ref inode to allocate block for 587 * @param fblock block address to allocate 588 * @param free output value - if target block is free 589 * @return error code 590 */ 591 int ext4_balloc_try_alloc_block(ext4_inode_ref_t *inode_ref, 592 uint32_t fblock, bool *free) 584 * @param inode_ref Inode to allocate block for 585 * @param fblock Block address to allocate 586 * @param free Output value - if target block is free 587 * 588 * @return Error code 589 * 590 */ 591 int ext4_balloc_try_alloc_block(ext4_inode_ref_t *inode_ref, uint32_t fblock, 592 bool *free) 593 593 { 594 594 int rc = EOK; 595 595 596 596 ext4_filesystem_t *fs = inode_ref->fs; 597 597 ext4_superblock_t *sb = fs->superblock; 598 598 599 599 /* Compute indexes */ 600 600 uint32_t block_group = ext4_balloc_get_bgid_of_block(sb, fblock); 601 601 uint32_t index_in_group = 602 ext4_filesystem_blockaddr2_index_in_group(sb, fblock);603 602 ext4_filesystem_blockaddr2_index_in_group(sb, fblock); 603 604 604 /* Load block group reference */ 605 605 ext4_block_group_ref_t *bg_ref; 606 606 rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref); 607 if (rc != EOK) { 608 return rc; 609 } 610 607 if (rc != EOK) 608 return rc; 609 611 610 /* Load block with bitmap */ 612 uint32_t bitmap_block_addr = ext4_block_group_get_block_bitmap(613 bg_ref->block_group, sb);611 uint32_t bitmap_block_addr = 612 ext4_block_group_get_block_bitmap(bg_ref->block_group, sb); 614 613 block_t *bitmap_block; 615 614 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 0); 616 if (rc != EOK) { 617 return rc; 618 } 619 615 if (rc != EOK) 616 return rc; 617 620 618 /* Check if block is free */ 621 619 *free = ext4_bitmap_is_free_bit(bitmap_block->data, index_in_group); 622 620 623 621 /* Allocate block if possible */ 624 622 if (*free) { … … 626 624 bitmap_block->dirty = true; 627 625 } 628 626 629 627 /* Release block with bitmap */ 630 628 rc = block_put(bitmap_block); … … 634 632 return rc; 635 633 } 636 634 637 635 /* If block is not free, return */ 638 if (!(*free)) {636 if (!(*free)) 639 637 goto terminate; 640 } 641 638 642 639 uint32_t block_size = ext4_superblock_get_block_size(sb); 643 640 644 641 /* Update superblock free blocks count */ 645 642 uint32_t sb_free_blocks = ext4_superblock_get_free_blocks_count(sb); 646 643 sb_free_blocks--; 647 644 ext4_superblock_set_free_blocks_count(sb, sb_free_blocks); 648 645 649 646 /* Update inode blocks count */ 650 uint64_t ino_blocks = ext4_inode_get_blocks_count(sb, inode_ref->inode); 647 uint64_t ino_blocks = 648 ext4_inode_get_blocks_count(sb, inode_ref->inode); 651 649 ino_blocks += block_size / EXT4_INODE_BLOCK_SIZE; 652 650 ext4_inode_set_blocks_count(sb, inode_ref->inode, ino_blocks); 653 651 inode_ref->dirty = true; 654 652 655 653 /* Update block group free blocks count */ 656 uint32_t free_blocks = ext4_block_group_get_free_blocks_count(657 bg_ref->block_group, sb);654 uint32_t free_blocks = 655 ext4_block_group_get_free_blocks_count(bg_ref->block_group, sb); 658 656 free_blocks--; 659 657 ext4_block_group_set_free_blocks_count(bg_ref->block_group, 660 sb, free_blocks);658 sb, free_blocks); 661 659 bg_ref->dirty = true; 662 660 663 661 terminate: 664 665 rc = ext4_filesystem_put_block_group_ref(bg_ref); 666 if (rc != EOK) { 667 return rc; 668 } 669 670 return rc; 662 return ext4_filesystem_put_block_group_ref(bg_ref); 671 663 } 672 664 673 665 /** 674 666 * @} 675 */ 667 */ -
uspace/lib/ext4/libext4_balloc.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_BALLOC_H_ … … 38 38 39 39 extern int ext4_balloc_free_block(ext4_inode_ref_t *, uint32_t); 40 extern int ext4_balloc_free_blocks(ext4_inode_ref_t *, 41 uint32_t , uint32_t); 42 extern uint32_t ext4_balloc_get_first_data_block_in_group( 43 ext4_superblock_t *, ext4_block_group_ref_t *); 40 extern int ext4_balloc_free_blocks(ext4_inode_ref_t *, uint32_t, uint32_t); 41 extern uint32_t ext4_balloc_get_first_data_block_in_group(ext4_superblock_t *, 42 ext4_block_group_ref_t *); 44 43 extern int ext4_balloc_alloc_block(ext4_inode_ref_t *, uint32_t *); 45 44 extern int ext4_balloc_try_alloc_block(ext4_inode_ref_t *, uint32_t, bool *); -
uspace/lib/ext4/libext4_bitmap.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_bitmap.c35 * @brief Ext4 bitmap operations.33 * @file libext4_bitmap.c 34 * @brief Ext4 bitmap operations. 36 35 */ 37 36 … … 45 44 * Index must be checked by caller, if it's not out of bounds. 46 45 * 47 * @param bitmap pointer to bitmap 48 * @param index index of bit in bitmap 46 * @param bitmap Pointer to bitmap 47 * @param index Index of bit in bitmap 48 * 49 49 */ 50 50 void ext4_bitmap_free_bit(uint8_t *bitmap, uint32_t index) … … 52 52 uint32_t byte_index = index / 8; 53 53 uint32_t bit_index = index % 8; 54 54 55 55 uint8_t *target = bitmap + byte_index; 56 56 57 57 *target &= ~ (1 << bit_index); 58 58 } … … 62 62 * Index and count must be checked by caller, if they aren't out of bounds. 63 63 * 64 * @param bitmap pointer to bitmap 65 * @param index index of first bit to zeroed 66 * @param count number of bits to be zeroed 64 * @param bitmap Pointer to bitmap 65 * @param index Index of first bit to zeroed 66 * @param count Number of bits to be zeroed 67 * 67 68 */ 68 69 void ext4_bitmap_free_bits(uint8_t *bitmap, uint32_t index, uint32_t count) … … 72 73 uint32_t remaining = count; 73 74 uint32_t byte_index; 74 75 75 76 /* Align index to multiple of 8 */ 76 77 while (((idx % 8) != 0) && (remaining > 0)) { 77 78 78 byte_index = idx / 8; 79 79 uint32_t bit_index = idx % 8; 80 80 81 81 target = bitmap + byte_index; 82 83 82 *target &= ~ (1 << bit_index); 84 83 85 84 idx++; 86 85 remaining--; 87 86 } 88 87 89 88 /* For < 8 bits this check necessary */ 90 if (remaining == 0) {89 if (remaining == 0) 91 90 return; 92 } 93 91 94 92 assert((idx % 8) == 0); 95 93 96 94 byte_index = idx / 8; 97 95 target = bitmap + byte_index; 98 96 99 97 /* Zero the whole bytes */ 100 98 while (remaining >= 8) { 101 99 *target = 0; 102 100 103 101 idx += 8; 104 102 remaining -= 8; 105 103 target++; 106 104 } 107 105 108 106 assert(remaining < 8); 109 107 110 108 /* Zero remaining bytes */ 111 109 while (remaining != 0) { 112 113 110 byte_index = idx / 8; 114 111 uint32_t bit_index = idx % 8; 115 112 116 113 target = bitmap + byte_index; 117 118 114 *target &= ~ (1 << bit_index); 119 115 120 116 idx++; 121 117 remaining--; … … 125 121 /** Set bit in bitmap to 1 (used). 126 122 * 127 * @param bitmap pointer to bitmap 128 * @param index index of bit to set 123 * @param bitmap Pointer to bitmap 124 * @param index Index of bit to set 125 * 129 126 */ 130 127 void ext4_bitmap_set_bit(uint8_t *bitmap, uint32_t index) … … 132 129 uint32_t byte_index = index / 8; 133 130 uint32_t bit_index = index % 8; 134 131 135 132 uint8_t *target = bitmap + byte_index; 136 133 137 134 *target |= 1 << bit_index; 138 135 } … … 140 137 /** Check if requested bit is free. 141 138 * 142 * @param bitmap pointer to bitmap 143 * @param index index of bit to be checked 144 * @return true if bit is free, else false 139 * @param bitmap Pointer to bitmap 140 * @param index Index of bit to be checked 141 * 142 * @return True if bit is free, else false 143 * 145 144 */ 146 145 bool ext4_bitmap_is_free_bit(uint8_t *bitmap, uint32_t index) … … 148 147 uint32_t byte_index = index / 8; 149 148 uint32_t bit_index = index % 8; 150 149 151 150 uint8_t *target = bitmap + byte_index; 152 153 if (*target & (1 << bit_index)) {151 152 if (*target & (1 << bit_index)) 154 153 return false; 155 } else {154 else 156 155 return true; 157 } 158 159 } 160 161 /** Try to find free byte and set the first bit as used. 162 * 163 * Walk through bitmap and try to find free byte ( == 0). 156 } 157 158 /** Try to find free byte and set the first bit as used. 159 * 160 * Walk through bitmap and try to find free byte (equal to 0). 164 161 * If byte found, set the first bit as used. 165 162 * 166 * @param bitmap pointer to bitmap 167 * @param start index of bit, where the algorithm will begin 168 * @param index output value - index of bit (if found free byte) 169 * @param max maximum index of bit in bitmap 170 * @return error code 171 */ 172 int ext4_bitmap_find_free_byte_and_set_bit(uint8_t *bitmap, uint32_t start, uint32_t *index, uint32_t max) 163 * @param bitmap Pointer to bitmap 164 * @param start Index of bit, where the algorithm will begin 165 * @param index Output value - index of bit (if found free byte) 166 * @param max Maximum index of bit in bitmap 167 * 168 * @return Error code 169 * 170 */ 171 int ext4_bitmap_find_free_byte_and_set_bit(uint8_t *bitmap, uint32_t start, 172 uint32_t *index, uint32_t max) 173 173 { 174 174 uint32_t idx; 175 175 176 176 /* Align idx */ 177 if (start % 8) {177 if (start % 8) 178 178 idx = start + (8 - (start % 8)); 179 } else {179 else 180 180 idx = start; 181 } 182 181 183 182 uint8_t *pos = bitmap + (idx / 8); 184 183 185 184 /* Try to find free byte */ 186 185 while (idx < max) { 187 188 186 if (*pos == 0) { 189 187 *pos |= 1; 190 188 191 189 *index = idx; 192 190 return EOK; 193 191 } 194 192 195 193 idx += 8; 196 194 ++pos; 197 195 } 198 196 199 197 /* Free byte not found */ 200 198 return ENOSPC; … … 205 203 * Walk through bitmap and try to find any free bit. 206 204 * 207 * @param bitmap pointer to bitmap 208 * @param start_idx index of bit, where algorithm will begin 209 * @param index output value - index of set bit (if found) 210 * @param max maximum index of bit in bitmap 211 * @return error code 205 * @param bitmap Pointer to bitmap 206 * @param start_idx Index of bit, where algorithm will begin 207 * @param index Output value - index of set bit (if found) 208 * @param max Maximum index of bit in bitmap 209 * 210 * @return Error code 211 * 212 212 */ 213 213 int ext4_bitmap_find_free_bit_and_set(uint8_t *bitmap, uint32_t start_idx, 214 uint32_t *index, uint32_t max)214 uint32_t *index, uint32_t max) 215 215 { 216 216 uint8_t *pos = bitmap + (start_idx / 8); 217 217 uint32_t idx = start_idx; 218 218 bool byte_part = false; 219 219 220 220 /* Check the rest of first byte */ 221 221 while ((idx % 8) != 0) { 222 222 byte_part = true; 223 223 224 224 if ((*pos & (1 << (idx % 8))) == 0) { 225 225 *pos |= (1 << (idx % 8)); … … 227 227 return EOK; 228 228 } 229 229 230 230 ++idx; 231 231 } 232 233 if (byte_part) {232 233 if (byte_part) 234 234 ++pos; 235 } 236 235 237 236 /* Check the whole bytes (255 = 11111111 binary) */ 238 237 while (idx < max) { 239 240 238 if ((*pos & 255) != 255) { 241 /* free bit found */239 /* Free bit found */ 242 240 break; 243 241 } 244 242 245 243 idx += 8; 246 244 ++pos; 247 245 } 248 246 249 247 /* If idx < max, some free bit found */ 250 248 if (idx < max) { 251 252 249 /* Check which bit from byte is free */ 253 250 for (uint8_t i = 0; i < 8; ++i) { 254 251 if ((*pos & (1 << i)) == 0) { 255 /* free bit found */ 256 *pos |= (1 << i); 252 /* Free bit found */ 253 *pos |= (1 << i); 254 257 255 *index = idx; 258 256 return EOK; 259 257 } 258 260 259 idx++; 261 260 } 262 261 } 263 262 264 263 /* Free bit not found */ 265 264 return ENOSPC; … … 268 267 /** 269 268 * @} 270 */ 269 */ -
uspace/lib/ext4/libext4_bitmap.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_BITMAP_H_ … … 41 41 extern bool ext4_bitmap_is_free_bit(uint8_t *, uint32_t); 42 42 extern int ext4_bitmap_find_free_byte_and_set_bit(uint8_t *, uint32_t, 43 uint32_t *, uint32_t);44 extern int ext4_bitmap_find_free_bit_and_set(uint8_t *, uint32_t, 45 uint32_t *,uint32_t);43 uint32_t *, uint32_t); 44 extern int ext4_bitmap_find_free_bit_and_set(uint8_t *, uint32_t, uint32_t *, 45 uint32_t); 46 46 47 47 #endif -
uspace/lib/ext4/libext4_block_group.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_block_group.c35 * @brief Ext4 block group structure operations.33 * @file libext4_block_group.c 34 * @brief Ext4 block group structure operations. 36 35 */ 37 36 … … 41 40 /** Get address of block with data block bitmap. 42 41 * 43 * @param bg pointer to block group 44 * @param sb pointer to superblock 45 * @return address of block with block bitmap 42 * @param bg Pointer to block group 43 * @param sb Pointer to superblock 44 * 45 * @return Address of block with block bitmap 46 * 46 47 */ 47 48 uint64_t ext4_block_group_get_block_bitmap(ext4_block_group_t *bg, 48 ext4_superblock_t *sb) 49 { 50 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 51 return ((uint64_t)uint32_t_le2host(bg->block_bitmap_hi) << 32) | 52 uint32_t_le2host(bg->block_bitmap_lo); 53 } else { 49 ext4_superblock_t *sb) 50 { 51 if (ext4_superblock_get_desc_size(sb) > 52 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 53 return ((uint64_t) uint32_t_le2host(bg->block_bitmap_hi) << 32) | 54 uint32_t_le2host(bg->block_bitmap_lo); 55 else 54 56 return uint32_t_le2host(bg->block_bitmap_lo); 55 }56 57 } 57 58 58 59 /** Set address of block with data block bitmap. 59 60 * 60 * @param bg pointer to block group 61 * @param sb pointer to superblock 62 * @param block_bitmap address of block with block bitmap 61 * @param bg Pointer to block group 62 * @param sb Pointer to superblock 63 * @param block_bitmap Address of block with block bitmap 64 * 63 65 */ 64 66 void ext4_block_group_set_block_bitmap(ext4_block_group_t *bg, 65 ext4_superblock_t *sb, uint64_t block_bitmap)67 ext4_superblock_t *sb, uint64_t block_bitmap) 66 68 { 67 69 bg->block_bitmap_lo = host2uint32_t_le((block_bitmap << 32) >> 32); 68 69 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 70 71 if (ext4_superblock_get_desc_size(sb) > 72 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 70 73 bg->block_bitmap_hi = host2uint32_t_le(block_bitmap >> 32); 71 }72 74 } 73 75 74 76 /** Get address of block with i-node bitmap. 75 77 * 76 * @param bg pointer to block group 77 * @param sb pointer to superblock 78 * @return address of block with i-node bitmap 78 * @param bg Pointer to block group 79 * @param sb Pointer to superblock 80 * 81 * @return Address of block with i-node bitmap 82 * 79 83 */ 80 84 uint64_t ext4_block_group_get_inode_bitmap(ext4_block_group_t *bg, 81 ext4_superblock_t *sb) 82 { 83 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 84 return ((uint64_t)uint32_t_le2host(bg->inode_bitmap_hi) << 32) | 85 uint32_t_le2host(bg->inode_bitmap_lo); 86 } else { 85 ext4_superblock_t *sb) 86 { 87 if (ext4_superblock_get_desc_size(sb) > 88 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 89 return ((uint64_t) uint32_t_le2host(bg->inode_bitmap_hi) << 32) | 90 uint32_t_le2host(bg->inode_bitmap_lo); 91 else 87 92 return uint32_t_le2host(bg->inode_bitmap_lo); 88 }89 90 93 } 91 94 92 95 /** Set address of block with i-node bitmap. 93 96 * 94 * @param bg pointer to block group 95 * @param sb pointer to superblock 96 * @param inode_bitmap address of block with i-node bitmap 97 * @param bg Pointer to block group 98 * @param sb Pointer to superblock 99 * @param inode_bitmap Address of block with i-node bitmap 100 * 97 101 */ 98 102 void ext4_block_group_set_inode_bitmap(ext4_block_group_t *bg, 99 ext4_superblock_t *sb, uint64_t inode_bitmap)103 ext4_superblock_t *sb, uint64_t inode_bitmap) 100 104 { 101 105 bg->inode_bitmap_lo = host2uint32_t_le((inode_bitmap << 32) >> 32); 102 103 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 106 107 if (ext4_superblock_get_desc_size(sb) > 108 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 104 109 bg->inode_bitmap_hi = host2uint32_t_le(inode_bitmap >> 32); 105 }106 110 } 107 111 108 112 /** Get address of the first block of the i-node table. 109 113 * 110 * @param bg pointer to block group 111 * @param sb pointer to superblock 112 * @return address of first block of i-node table 114 * @param bg Pointer to block group 115 * @param sb Pointer to superblock 116 * 117 * @return Address of first block of i-node table 118 * 113 119 */ 114 120 uint64_t ext4_block_group_get_inode_table_first_block(ext4_block_group_t *bg, 115 ext4_superblock_t *sb) 116 { 117 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 118 return ((uint64_t)uint32_t_le2host(bg->inode_table_first_block_hi) << 32) | 119 uint32_t_le2host(bg->inode_table_first_block_lo); 120 } else { 121 ext4_superblock_t *sb) 122 { 123 if (ext4_superblock_get_desc_size(sb) > 124 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 125 return ((uint64_t) 126 uint32_t_le2host(bg->inode_table_first_block_hi) << 32) | 127 uint32_t_le2host(bg->inode_table_first_block_lo); 128 else 121 129 return uint32_t_le2host(bg->inode_table_first_block_lo); 122 }123 130 } 124 131 125 132 /** Set address of the first block of the i-node table. 126 133 * 127 * @param bg pointer to block group 128 * @param sb pointer to superblock 129 * @param inode_table_first address of first block of i-node table 134 * @param bg Pointer to block group 135 * @param sb Pointer to superblock 136 * @param inode_table_first Address of first block of i-node table 137 * 130 138 */ 131 139 void ext4_block_group_set_inode_table_first_block(ext4_block_group_t *bg, 132 ext4_superblock_t *sb, uint64_t inode_table_first)140 ext4_superblock_t *sb, uint64_t inode_table_first) 133 141 { 134 142 bg->inode_table_first_block_lo = 135 host2uint32_t_le((inode_table_first << 32) >> 32); 136 137 if (ext4_superblock_get_desc_size(sb) > 138 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 139 143 host2uint32_t_le((inode_table_first << 32) >> 32); 144 145 if (ext4_superblock_get_desc_size(sb) > 146 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 140 147 bg->inode_table_first_block_hi = 141 host2uint32_t_le(inode_table_first >> 32); 142 } 148 host2uint32_t_le(inode_table_first >> 32); 143 149 } 144 150 145 151 /** Get number of free blocks in block group. 146 152 * 147 * @param bg pointer to block group 148 * @param sb pointer to superblock 149 * @return number of free blocks in block group 153 * @param bg Pointer to block group 154 * @param sb Pointer to superblock 155 * 156 * @return Number of free blocks in block group 157 * 150 158 */ 151 159 uint32_t ext4_block_group_get_free_blocks_count(ext4_block_group_t *bg, 152 ext4_superblock_t *sb)153 { 154 if (ext4_superblock_get_desc_size(sb) > 155 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) {156 157 return ((uint32_t)uint16_t_le2host(bg->free_blocks_count_hi) << 16) |158 uint16_t_le2host(bg->free_blocks_count_lo);159 } else {160 ext4_superblock_t *sb) 161 { 162 if (ext4_superblock_get_desc_size(sb) > 163 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 164 return ((uint32_t) 165 uint16_t_le2host(bg->free_blocks_count_hi) << 16) | 166 uint16_t_le2host(bg->free_blocks_count_lo); 167 else 160 168 return uint16_t_le2host(bg->free_blocks_count_lo); 161 }162 169 } 163 170 164 171 /** Set number of free blocks in block group. 165 172 * 166 * @param bg pointer to block group 167 * @param sb pointer to superblock 168 * @param value number of free blocks in block group 173 * @param bg Pointer to block group 174 * @param sb Pointer to superblock 175 * @param value Number of free blocks in block group 176 * 169 177 */ 170 178 void ext4_block_group_set_free_blocks_count(ext4_block_group_t *bg, 171 ext4_superblock_t *sb, uint32_t value)179 ext4_superblock_t *sb, uint32_t value) 172 180 { 173 181 bg->free_blocks_count_lo = host2uint16_t_le((value << 16) >> 16); 174 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 182 if (ext4_superblock_get_desc_size(sb) > 183 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 175 184 bg->free_blocks_count_hi = host2uint16_t_le(value >> 16); 176 }177 185 } 178 186 179 187 /** Get number of free i-nodes in block group. 180 188 * 181 * @param bg pointer to block group 182 * @param sb pointer to superblock 183 * @return number of free i-nodes in block group 189 * @param bg Pointer to block group 190 * @param sb Pointer to superblock 191 * 192 * @return Number of free i-nodes in block group 193 * 184 194 */ 185 195 uint32_t ext4_block_group_get_free_inodes_count(ext4_block_group_t *bg, 186 ext4_superblock_t *sb) 187 { 188 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 189 return ((uint32_t)uint16_t_le2host(bg->free_inodes_count_hi) << 16) | 190 uint16_t_le2host(bg->free_inodes_count_lo); 191 } else { 196 ext4_superblock_t *sb) 197 { 198 if (ext4_superblock_get_desc_size(sb) > 199 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 200 return ((uint32_t) 201 uint16_t_le2host(bg->free_inodes_count_hi) << 16) | 202 uint16_t_le2host(bg->free_inodes_count_lo); 203 else 192 204 return uint16_t_le2host(bg->free_inodes_count_lo); 193 }194 205 } 195 206 196 207 /** Set number of free i-nodes in block group. 197 208 * 198 * @param bg pointer to block group 199 * @param sb pointer to superblock 200 * @param value number of free i-nodes in block group 209 * @param bg Pointer to block group 210 * @param sb Pointer to superblock 211 * @param value Number of free i-nodes in block group 212 * 201 213 */ 202 214 void ext4_block_group_set_free_inodes_count(ext4_block_group_t *bg, 203 ext4_superblock_t *sb, uint32_t value)215 ext4_superblock_t *sb, uint32_t value) 204 216 { 205 217 bg->free_inodes_count_lo = host2uint16_t_le((value << 16) >> 16); 206 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 218 if (ext4_superblock_get_desc_size(sb) > 219 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 207 220 bg->free_inodes_count_hi = host2uint16_t_le(value >> 16); 208 }209 221 } 210 222 211 223 /** Get number of used directories in block group. 212 224 * 213 * @param bg pointer to block group 214 * @param sb pointer to superblock 215 * @return number of used directories in block group 225 * @param bg Pointer to block group 226 * @param sb Pointer to superblock 227 * 228 * @return Number of used directories in block group 229 * 216 230 */ 217 231 uint32_t ext4_block_group_get_used_dirs_count(ext4_block_group_t *bg, 218 ext4_superblock_t *sb) 219 { 220 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 221 return ((uint32_t)uint16_t_le2host(bg->used_dirs_count_hi) << 16) | 222 uint16_t_le2host(bg->used_dirs_count_lo); 223 } else { 232 ext4_superblock_t *sb) 233 { 234 if (ext4_superblock_get_desc_size(sb) > 235 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 236 return ((uint32_t) 237 uint16_t_le2host(bg->used_dirs_count_hi) << 16) | 238 uint16_t_le2host(bg->used_dirs_count_lo); 239 else 224 240 return uint16_t_le2host(bg->used_dirs_count_lo); 225 }226 241 } 227 242 228 243 /** Set number of used directories in block group. 229 244 * 230 * @param bg pointer to block group 231 * @param sb pointer to superblock 232 * @param value number of used directories in block group 245 * @param bg Pointer to block group 246 * @param sb Pointer to superblock 247 * @param value Number of used directories in block group 248 * 233 249 */ 234 250 void ext4_block_group_set_used_dirs_count(ext4_block_group_t *bg, 235 ext4_superblock_t *sb, uint32_t count)251 ext4_superblock_t *sb, uint32_t count) 236 252 { 237 253 bg->used_dirs_count_lo = host2uint16_t_le((count << 16) >> 16); 238 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 254 if (ext4_superblock_get_desc_size(sb) > 255 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 239 256 bg->used_dirs_count_hi = host2uint16_t_le(count >> 16); 240 }241 257 } 242 258 243 259 /** Get flags of block group. 244 260 * 245 * @param bg pointer to block group 246 * @return flags of block group 261 * @param bg Pointer to block group 262 * 263 * @return Flags of block group 264 * 247 265 */ 248 266 uint16_t ext4_block_group_get_flags(ext4_block_group_t *bg) … … 253 271 /** Set flags for block group. 254 272 * 255 * @param bg pointer to block group 256 * @param flags flags for block group 273 * @param bg Pointer to block group 274 * @param flags Flags for block group 275 * 257 276 */ 258 277 void ext4_block_group_set_flags(ext4_block_group_t *bg, uint16_t flags) … … 263 282 /** Get number of unused i-nodes. 264 283 * 265 * @param bg pointer to block group 266 * @param sb pointer to superblock 267 * @return number of unused i-nodes 284 * @param bg Pointer to block group 285 * @param sb Pointer to superblock 286 * 287 * @return Number of unused i-nodes 288 * 268 289 */ 269 290 uint32_t ext4_block_group_get_itable_unused(ext4_block_group_t *bg, 270 ext4_superblock_t *sb) 271 { 272 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 273 return ((uint32_t)uint16_t_le2host(bg->itable_unused_hi) << 16) | 274 uint16_t_le2host(bg->itable_unused_lo); 275 } else { 291 ext4_superblock_t *sb) 292 { 293 if (ext4_superblock_get_desc_size(sb) > 294 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 295 return ((uint32_t) 296 uint16_t_le2host(bg->itable_unused_hi) << 16) | 297 uint16_t_le2host(bg->itable_unused_lo); 298 else 276 299 return uint16_t_le2host(bg->itable_unused_lo); 277 }278 300 } 279 301 280 302 /** Set number of unused i-nodes. 281 303 * 282 * @param bg pointer to block group 283 * @param sb pointer to superblock 284 * @param value number of unused i-nodes 304 * @param bg Pointer to block group 305 * @param sb Pointer to superblock 306 * @param value Number of unused i-nodes 307 * 285 308 */ 286 309 void ext4_block_group_set_itable_unused(ext4_block_group_t *bg, 287 ext4_superblock_t *sb, uint32_t value)310 ext4_superblock_t *sb, uint32_t value) 288 311 { 289 312 bg->itable_unused_lo = host2uint16_t_le((value << 16) >> 16); 290 if (ext4_superblock_get_desc_size(sb) > EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) { 313 if (ext4_superblock_get_desc_size(sb) > 314 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 291 315 bg->itable_unused_hi = host2uint16_t_le(value >> 16); 292 }293 294 316 } 295 317 296 318 /** Get checksum of block group. 297 319 * 298 * @param bg pointer to block group 299 * @return checksum of block group 320 * @param bg Pointer to block group 321 * 322 * @return checksum of block group 323 * 300 324 */ 301 325 uint16_t ext4_block_group_get_checksum(ext4_block_group_t *bg) … … 306 330 /** Set checksum of block group. 307 331 * 308 * @param bg pointer to block group 309 * @param checksum cheksum of block group 332 * @param bg Pointer to block group 333 * @param checksum Cheksum of block group 334 * 310 335 */ 311 336 void ext4_block_group_set_checksum(ext4_block_group_t *bg, uint16_t checksum) … … 316 341 /** Check if block group has a flag. 317 342 * 318 * @param bg pointer to block group 319 * @param flag flag to be checked 320 * @return true if flag is set to 1 343 * @param bg Pointer to block group 344 * @param flag Flag to be checked 345 * 346 * @return True if flag is set to 1 347 * 321 348 */ 322 349 bool ext4_block_group_has_flag(ext4_block_group_t *bg, uint32_t flag) 323 350 { 324 if (ext4_block_group_get_flags(bg) & flag) {351 if (ext4_block_group_get_flags(bg) & flag) 325 352 return true; 326 }353 327 354 return false; 328 355 } … … 330 357 /** Set (add) flag of block group. 331 358 * 332 * @param bg pointer to block group 333 * @param flag flag to be set 359 * @param bg Pointer to block group 360 * @param flag Flag to be set 361 * 334 362 */ 335 363 void ext4_block_group_set_flag(ext4_block_group_t *bg, uint32_t set_flag) … … 342 370 /** Clear (remove) flag of block group. 343 371 * 344 * @param bg pointer to block group 345 * @param flag flag to be cleared 372 * @param bg Pointer to block group 373 * @param flag Flag to be cleared 374 * 346 375 */ 347 376 void ext4_block_group_clear_flag(ext4_block_group_t *bg, uint32_t clear_flag) … … 352 381 } 353 382 354 355 383 /** 356 384 * @} 357 */ 385 */ -
uspace/lib/ext4/libext4_block_group.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_BLOCK_GROUP_H_ … … 39 39 40 40 extern uint64_t ext4_block_group_get_block_bitmap(ext4_block_group_t *, 41 ext4_superblock_t *);41 ext4_superblock_t *); 42 42 extern void ext4_block_group_set_block_bitmap(ext4_block_group_t *, 43 ext4_superblock_t *, uint64_t);43 ext4_superblock_t *, uint64_t); 44 44 extern uint64_t ext4_block_group_get_inode_bitmap(ext4_block_group_t *, 45 ext4_superblock_t *);45 ext4_superblock_t *); 46 46 extern void ext4_block_group_set_inode_bitmap(ext4_block_group_t *, 47 ext4_superblock_t *, uint64_t);47 ext4_superblock_t *, uint64_t); 48 48 extern uint64_t ext4_block_group_get_inode_table_first_block( 49 ext4_block_group_t *, ext4_superblock_t *);50 extern void ext4_block_group_set_inode_table_first_block( 51 ext4_block_group_t *,ext4_superblock_t *, uint64_t);49 ext4_block_group_t *, ext4_superblock_t *); 50 extern void ext4_block_group_set_inode_table_first_block(ext4_block_group_t *, 51 ext4_superblock_t *, uint64_t); 52 52 extern uint32_t ext4_block_group_get_free_blocks_count(ext4_block_group_t *, 53 ext4_superblock_t *);53 ext4_superblock_t *); 54 54 extern void ext4_block_group_set_free_blocks_count(ext4_block_group_t *, 55 ext4_superblock_t *, uint32_t);55 ext4_superblock_t *, uint32_t); 56 56 extern uint32_t ext4_block_group_get_free_inodes_count(ext4_block_group_t *, 57 ext4_superblock_t *);57 ext4_superblock_t *); 58 58 extern void ext4_block_group_set_free_inodes_count(ext4_block_group_t *, 59 ext4_superblock_t *, uint32_t);59 ext4_superblock_t *, uint32_t); 60 60 extern void ext4_block_group_set_free_inodes_count(ext4_block_group_t *, 61 ext4_superblock_t *, uint32_t);61 ext4_superblock_t *, uint32_t); 62 62 extern uint32_t ext4_block_group_get_used_dirs_count(ext4_block_group_t *, 63 ext4_superblock_t *);63 ext4_superblock_t *); 64 64 extern void ext4_block_group_set_used_dirs_count(ext4_block_group_t *, 65 ext4_superblock_t *, uint32_t);65 ext4_superblock_t *, uint32_t); 66 66 extern uint16_t ext4_block_group_get_flags(ext4_block_group_t *); 67 67 extern void ext4_block_group_set_flags(ext4_block_group_t *, uint16_t); 68 68 extern uint32_t ext4_block_group_get_itable_unused(ext4_block_group_t *, 69 ext4_superblock_t *);69 ext4_superblock_t *); 70 70 extern void ext4_block_group_set_itable_unused(ext4_block_group_t *, 71 ext4_superblock_t *, uint32_t);71 ext4_superblock_t *, uint32_t); 72 72 extern uint16_t ext4_block_group_get_checksum(ext4_block_group_t *); 73 73 extern void ext4_block_group_set_checksum(ext4_block_group_t *, uint16_t); -
uspace/lib/ext4/libext4_crc.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 /** 34 * @file libext4_crc.c35 * @brief CRC checksumming implementation from Linux.34 * @file libext4_crc.c 35 * @brief CRC checksumming implementation from Linux. 36 36 */ 37 37 … … 45 45 */ 46 46 uint16_t const crc16_table[256] = { 47 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,48 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,49 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,50 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,51 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,52 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,53 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,54 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,55 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,56 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,57 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,58 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,59 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,60 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,61 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,62 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,63 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,64 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,65 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,66 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,67 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,68 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,69 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,70 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,71 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,72 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,73 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,74 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,75 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,76 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,77 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,78 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x404047 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 48 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 49 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 50 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 51 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 52 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 53 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 54 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 55 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 56 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 57 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 58 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 59 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 60 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 61 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 62 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 63 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 64 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 65 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 66 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 67 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 68 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 69 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 70 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 71 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 72 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 73 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 74 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 75 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 76 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 77 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 78 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 79 79 }; 80 80 81 81 /** Modify CRC value. 82 82 * 83 * @param crc current CRC value 84 * @param data new byte of data to be "added" to CRC 85 * @return updated CRC value 83 * @param crc Current CRC value 84 * @param data New byte of data to be "added" to CRC 85 * 86 * @return Updated CRC value 87 * 86 88 */ 87 89 static inline uint16_t crc16_byte(uint16_t crc, const uint8_t data) … … 92 94 /** Compute the CRC-16 for the data buffer. 93 95 * 94 * @param crc previous CRC value 95 * @param buffer data pointer 96 * @param len number of bytes in the buffer 97 * @return updated CRC value 96 * @param crc Previous CRC value 97 * @param buffer Data pointer 98 * @param len Number of bytes in the buffer 99 * 100 * @return Updated CRC value 101 * 98 102 */ 99 103 uint16_t crc16(uint16_t crc, const uint8_t *buffer, size_t len) 100 104 { 101 while (len--) {102 crc = crc16_byte(crc, *buffer++);103 }104 return crc;105 while (len--) 106 crc = crc16_byte(crc, *buffer++); 107 108 return crc; 105 109 } 106 107 110 108 111 /** 109 112 * @} 110 */ 113 */ -
uspace/lib/ext4/libext4_crc.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_CRC_H_ … … 35 35 36 36 extern uint16_t crc16(uint16_t, const uint8_t *, size_t); 37 37 38 #endif 38 39 -
uspace/lib/ext4/libext4_directory.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_directory.c35 * @brief Ext4 directory structure operations.33 * @file libext4_directory.c 34 * @brief Ext4 directory structure operations. 36 35 */ 37 36 … … 39 38 #include <errno.h> 40 39 #include <malloc.h> 41 #include <string.h>42 40 #include "libext4.h" 43 41 44 45 42 /** Get i-node number from directory entry. 46 43 * 47 * @param de directory entry 48 * @return i-node number 44 * @param de Directory entry 45 * 46 * @return I-node number 47 * 49 48 */ 50 49 uint32_t ext4_directory_entry_ll_get_inode(ext4_directory_entry_ll_t *de) … … 55 54 /** Set i-node number to directory entry. 56 55 * 57 * @param de directory entry 58 * @param inode i-node number 56 * @param de Directory entry 57 * @param inode I-node number 58 * 59 59 */ 60 60 void ext4_directory_entry_ll_set_inode(ext4_directory_entry_ll_t *de, 61 uint32_t inode)61 uint32_t inode) 62 62 { 63 63 de->inode = host2uint32_t_le(inode); … … 66 66 /** Get directory entry length. 67 67 * 68 * @param de directory entry 69 * @return entry length 70 */ 71 uint16_t ext4_directory_entry_ll_get_entry_length( 72 ext4_directory_entry_ll_t *de) 68 * @param de Directory entry 69 * 70 * @return Entry length 71 * 72 */ 73 uint16_t ext4_directory_entry_ll_get_entry_length(ext4_directory_entry_ll_t *de) 73 74 { 74 75 return uint16_t_le2host(de->entry_length); … … 77 78 /** Set directory entry length. 78 79 * 79 * @param de directory entry80 * @param length entry length81 * /82 80 * @param de Directory entry 81 * @param length Entry length 82 * 83 */ 83 84 void ext4_directory_entry_ll_set_entry_length(ext4_directory_entry_ll_t *de, 84 uint16_t length)85 uint16_t length) 85 86 { 86 87 de->entry_length = host2uint16_t_le(length); … … 89 90 /** Get directory entry name length. 90 91 * 91 * @param sb superblock 92 * @param de directory entry 93 * @return entry name length 94 */ 95 uint16_t ext4_directory_entry_ll_get_name_length( 96 ext4_superblock_t *sb, ext4_directory_entry_ll_t *de) 97 { 98 if (ext4_superblock_get_rev_level(sb) == 0 && 99 ext4_superblock_get_minor_rev_level(sb) < 5) { 100 92 * @param sb Superblock 93 * @param de Directory entry 94 * 95 * @return Entry name length 96 * 97 */ 98 uint16_t ext4_directory_entry_ll_get_name_length(ext4_superblock_t *sb, 99 ext4_directory_entry_ll_t *de) 100 { 101 if ((ext4_superblock_get_rev_level(sb) == 0) && 102 (ext4_superblock_get_minor_rev_level(sb) < 5)) 101 103 return ((uint16_t)de->name_length_high) << 8 | 102 ((uint16_t)de->name_length); 103 104 } 104 ((uint16_t)de->name_length); 105 105 106 return de->name_length; 106 107 … … 109 110 /** Set directory entry name length. 110 111 * 111 * @param sb superblock 112 * @param de directory entry 113 * @param length entry name length 112 * @param sb Superblock 113 * @param de Directory entry 114 * @param length Entry name length 115 * 114 116 */ 115 117 void ext4_directory_entry_ll_set_name_length(ext4_superblock_t *sb, 116 ext4_directory_entry_ll_t *de, uint16_t length)118 ext4_directory_entry_ll_t *de, uint16_t length) 117 119 { 118 120 de->name_length = (length << 8) >> 8; 119 120 if (ext4_superblock_get_rev_level(sb) == 0 && 121 ext4_superblock_get_minor_rev_level(sb) < 5) { 122 121 122 if ((ext4_superblock_get_rev_level(sb) == 0) && 123 (ext4_superblock_get_minor_rev_level(sb) < 5)) 123 124 de->name_length_high = length >> 8; 124 } 125 126 /* Else do nothing */ 125 127 } 126 128 127 129 /** Get i-node type of directory entry. 128 130 * 129 * @param sb superblock130 * @param de directory entry131 * @return i-node type (file, dir, etc.)132 * /133 uint8_t ext4_directory_entry_ll_get_inode_type( 134 ext4_superblock_t *sb, ext4_directory_entry_ll_t *de) 135 { 136 if (ext4_superblock_get_rev_level(sb) > 0 || 137 ext4_superblock_get_minor_rev_level(sb) >= 5){138 139 return de->inode_type;140 }141 131 * @param sb Superblock 132 * @param de Directory entry 133 * 134 * @return I-node type (file, dir, etc.) 135 * 136 */ 137 uint8_t ext4_directory_entry_ll_get_inode_type(ext4_superblock_t *sb, 138 ext4_directory_entry_ll_t *de) 139 { 140 if ((ext4_superblock_get_rev_level(sb) > 0) || 141 (ext4_superblock_get_minor_rev_level(sb) >= 5)) 142 return de->inode_type; 143 142 144 return EXT4_DIRECTORY_FILETYPE_UNKNOWN; 143 144 145 } 145 146 146 147 /** Set i-node type of directory entry. 147 148 * 148 * @param sb superblock149 * @param de directory entry150 * @param type i-node type (file, dir, etc.)151 * /152 void ext4_directory_entry_ll_set_inode_type( 153 ext4_superblock_t *sb, ext4_directory_entry_ll_t *de, uint8_t type) 154 { 155 if (ext4_superblock_get_rev_level(sb) > 0 || 156 ext4_superblock_get_minor_rev_level(sb) >= 5) {157 149 * @param sb Superblock 150 * @param de Directory entry 151 * @param type I-node type (file, dir, etc.) 152 * 153 */ 154 void ext4_directory_entry_ll_set_inode_type(ext4_superblock_t *sb, 155 ext4_directory_entry_ll_t *de, uint8_t type) 156 { 157 if ((ext4_superblock_get_rev_level(sb) > 0) || 158 (ext4_superblock_get_minor_rev_level(sb) >= 5)) 158 159 de->inode_type = type; 159 } 160 161 /* else do nothing */ 162 163 } 164 165 static int ext4_directory_iterator_seek( 166 ext4_directory_iterator_t *, aoff64_t); 167 static int ext4_directory_iterator_set( 168 ext4_directory_iterator_t *, uint32_t); 169 160 161 /* Else do nothing */ 162 } 163 164 static int ext4_directory_iterator_seek(ext4_directory_iterator_t *, aoff64_t); 165 static int ext4_directory_iterator_set(ext4_directory_iterator_t *, uint32_t); 170 166 171 167 /** Initialize directory iterator. … … 173 169 * Set position to the first valid entry from the required position. 174 170 * 175 * @param it pointer to iterator to be initialized 176 * @param inode_ref directory i-node 177 * @param pos position to start reading entries from 178 * @return error code 171 * @param it Pointer to iterator to be initialized 172 * @param inode_ref Directory i-node 173 * @param pos Position to start reading entries from 174 * 175 * @return Error code 176 * 179 177 */ 180 178 int ext4_directory_iterator_init(ext4_directory_iterator_t *it, 181 ext4_inode_ref_t *inode_ref, aoff64_t pos)179 ext4_inode_ref_t *inode_ref, aoff64_t pos) 182 180 { 183 181 it->inode_ref = inode_ref; … … 185 183 it->current_offset = 0; 186 184 it->current_block = NULL; 187 185 188 186 return ext4_directory_iterator_seek(it, pos); 189 187 } … … 191 189 /** Jump to the next valid entry 192 190 * 193 * @param it initialized iterator 194 * @return error code 191 * @param it Initialized iterator 192 * 193 * @return Error code 194 * 195 195 */ 196 196 int ext4_directory_iterator_next(ext4_directory_iterator_t *it) 197 197 { 198 uint16_t skip;199 200 198 assert(it->current != NULL); 201 202 skip = ext4_directory_entry_ll_get_entry_length(it->current);203 199 200 uint16_t skip = ext4_directory_entry_ll_get_entry_length(it->current); 201 204 202 return ext4_directory_iterator_seek(it, it->current_offset + skip); 205 203 } … … 209 207 * Here can be jumped to the next data block. 210 208 * 211 * @param it initialized iterator 212 * @param pos position of the next entry 213 * @return error code 209 * @param it Initialized iterator 210 * @param pos Position of the next entry 211 * 212 * @return Error code 213 * 214 214 */ 215 215 int ext4_directory_iterator_seek(ext4_directory_iterator_t *it, aoff64_t pos) 216 216 { 217 int rc; 218 219 uint64_t size = ext4_inode_get_size( 220 it->inode_ref->fs->superblock, it->inode_ref->inode); 221 217 uint64_t size = ext4_inode_get_size(it->inode_ref->fs->superblock, 218 it->inode_ref->inode); 219 222 220 /* The iterator is not valid until we seek to the desired position */ 223 221 it->current = NULL; 224 222 225 223 /* Are we at the end? */ 226 224 if (pos >= size) { 227 225 if (it->current_block) { 228 rc = block_put(it->current_block);226 int rc = block_put(it->current_block); 229 227 it->current_block = NULL; 230 if (rc != EOK) { 228 229 if (rc != EOK) 231 230 return rc; 232 } 233 } 234 231 } 232 235 233 it->current_offset = pos; 236 234 return EOK; 237 235 } 238 236 239 237 /* Compute next block address */ 240 uint32_t block_size = ext4_superblock_get_block_size(241 it->inode_ref->fs->superblock);238 uint32_t block_size = 239 ext4_superblock_get_block_size(it->inode_ref->fs->superblock); 242 240 aoff64_t current_block_idx = it->current_offset / block_size; 243 241 aoff64_t next_block_idx = pos / block_size; 244 245 /* If we don't have a block or are moving accross block boundary, 242 243 /* 244 * If we don't have a block or are moving accross block boundary, 246 245 * we need to get another block 247 246 */ 248 if (it->current_block == NULL || current_block_idx != next_block_idx) { 247 if ((it->current_block == NULL) || 248 (current_block_idx != next_block_idx)) { 249 249 if (it->current_block) { 250 rc = block_put(it->current_block);250 int rc = block_put(it->current_block); 251 251 it->current_block = NULL; 252 if (rc != EOK) { 252 253 if (rc != EOK) 253 254 return rc; 254 } 255 } 256 255 } 256 257 257 uint32_t next_block_phys_idx; 258 rc = ext4_filesystem_get_inode_data_block_index(it->inode_ref,259 next_block_idx, &next_block_phys_idx);260 if (rc != EOK) {258 int rc = ext4_filesystem_get_inode_data_block_index(it->inode_ref, 259 next_block_idx, &next_block_phys_idx); 260 if (rc != EOK) 261 261 return rc; 262 } 263 262 264 263 rc = block_get(&it->current_block, it->inode_ref->fs->device, 265 next_block_phys_idx, BLOCK_FLAGS_NONE);264 next_block_phys_idx, BLOCK_FLAGS_NONE); 266 265 if (rc != EOK) { 267 266 it->current_block = NULL; … … 269 268 } 270 269 } 271 270 272 271 it->current_offset = pos; 273 272 274 273 return ext4_directory_iterator_set(it, block_size); 275 274 } … … 277 276 /** Do some checks before returning iterator. 278 277 * 279 * @param it iterator to be checked 280 * @param block_size size of data block 281 * @return error code 278 * @param it Iterator to be checked 279 * @param block_size Size of data block 280 * 281 * @return Error code 282 * 282 283 */ 283 284 static int ext4_directory_iterator_set(ext4_directory_iterator_t *it, 284 285 uint32_t block_size) 285 286 { 286 287 287 it->current = NULL; 288 288 289 289 uint32_t offset_in_block = it->current_offset % block_size; 290 290 291 291 /* Ensure proper alignment */ 292 if ((offset_in_block % 4) != 0) {292 if ((offset_in_block % 4) != 0) 293 293 return EIO; 294 } 295 294 296 295 /* Ensure that the core of the entry does not overflow the block */ 297 if (offset_in_block > block_size - 8) {296 if (offset_in_block > block_size - 8) 298 297 return EIO; 299 }300 301 ext4_directory_entry_ll_t *entry =it->current_block->data + offset_in_block;302 298 299 ext4_directory_entry_ll_t *entry = 300 it->current_block->data + offset_in_block; 301 303 302 /* Ensure that the whole entry does not overflow the block */ 304 303 uint16_t length = ext4_directory_entry_ll_get_entry_length(entry); 305 if (offset_in_block + length > block_size) {304 if (offset_in_block + length > block_size) 306 305 return EIO; 307 } 308 306 309 307 /* Ensure the name length is not too large */ 310 if (ext4_directory_entry_ll_get_name_length( it->inode_ref->fs->superblock,311 entry) > length-8) {308 if (ext4_directory_entry_ll_get_name_length( 309 it->inode_ref->fs->superblock, entry) > length-8) 312 310 return EIO; 313 } 314 311 315 312 /* Everything OK - "publish" the entry */ 316 313 it->current = entry; … … 318 315 } 319 316 320 321 317 /** Uninitialize directory iterator. 322 318 * 323 319 * Release all allocated structures. 324 320 * 325 * @param it iterator to be finished 326 * @return error code 321 * @param it Iterator to be finished 322 * 323 * @return Error code 324 * 327 325 */ 328 326 int ext4_directory_iterator_fini(ext4_directory_iterator_t *it) 329 327 { 330 int rc;331 332 328 it->inode_ref = NULL; 333 329 it->current = NULL; 334 335 if (it->current_block) { 336 rc = block_put(it->current_block); 337 if (rc != EOK) { 338 return rc; 339 } 340 } 341 330 331 if (it->current_block) 332 return block_put(it->current_block); 333 342 334 return EOK; 343 335 } 344 336 345 /** Write directory entry to concrete data block. 346 * 347 * @param sb superblock 348 * @param entry pointer to entry to be written 349 * @param entry_len lenght of new entry 350 * @param child child i-node to be written to new entry 351 * @param name name of the new entry 352 * @param name_len length of entry name 337 /** Write directory entry to concrete data block. 338 * 339 * @param sb Superblock 340 * @param entry Pointer to entry to be written 341 * @param entry_len Length of new entry 342 * @param child Child i-node to be written to new entry 343 * @param name Name of the new entry 344 * @param name_len Length of entry name 345 * 353 346 */ 354 347 void ext4_directory_write_entry(ext4_superblock_t *sb, 355 ext4_directory_entry_ll_t *entry, uint16_t entry_len, 356 ext4_inode_ref_t *child, const char *name, size_t name_len) 357 { 358 348 ext4_directory_entry_ll_t *entry, uint16_t entry_len, 349 ext4_inode_ref_t *child, const char *name, size_t name_len) 350 { 359 351 /* Check maximum entry length */ 360 352 uint32_t block_size = ext4_superblock_get_block_size(sb); 361 353 assert(entry_len <= block_size); 362 354 363 355 /* Set basic attributes */ 364 356 ext4_directory_entry_ll_set_inode(entry, child->index); 365 357 ext4_directory_entry_ll_set_entry_length(entry, entry_len); 366 358 ext4_directory_entry_ll_set_name_length(sb, entry, name_len); 367 359 368 360 /* Write name */ 369 361 memcpy(entry->name, name, name_len); 370 362 371 363 /* Set type of entry */ 372 if (ext4_inode_is_type(sb, child->inode, EXT4_INODE_MODE_DIRECTORY)) { 373 ext4_directory_entry_ll_set_inode_type( 374 sb, entry, EXT4_DIRECTORY_FILETYPE_DIR); 375 } else { 376 ext4_directory_entry_ll_set_inode_type( 377 sb, entry, EXT4_DIRECTORY_FILETYPE_REG_FILE); 378 } 379 364 if (ext4_inode_is_type(sb, child->inode, EXT4_INODE_MODE_DIRECTORY)) 365 ext4_directory_entry_ll_set_inode_type(sb, entry, 366 EXT4_DIRECTORY_FILETYPE_DIR); 367 else 368 ext4_directory_entry_ll_set_inode_type(sb, entry, 369 EXT4_DIRECTORY_FILETYPE_REG_FILE); 380 370 } 381 371 382 372 /** Add new entry to the directory. 383 373 * 384 * @param parent directory i-node385 * @param name name of new entry386 * @param child i-node to be referenced from new entry387 * @return error code388 * /389 int ext4_directory_add_entry(ext4_inode_ref_t * parent, 390 const char *name, ext4_inode_ref_t *child) 391 { 392 int rc; 393 374 * @param parent Directory i-node 375 * @param name Name of new entry 376 * @param child I-node to be referenced from new entry 377 * 378 * @return Error code 379 * 380 */ 381 int ext4_directory_add_entry(ext4_inode_ref_t *parent, const char *name, 382 ext4_inode_ref_t *child) 383 { 394 384 ext4_filesystem_t *fs = parent->fs; 395 385 396 386 /* Index adding (if allowed) */ 397 if ( ext4_superblock_has_feature_compatible(fs->superblock, EXT4_FEATURE_COMPAT_DIR_INDEX) &&398 ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX)) {399 400 rc = ext4_directory_dx_add_entry(parent, child, name);401 387 if ((ext4_superblock_has_feature_compatible(fs->superblock, 388 EXT4_FEATURE_COMPAT_DIR_INDEX)) && 389 (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) { 390 int rc = ext4_directory_dx_add_entry(parent, child, name); 391 402 392 /* Check if index is not corrupted */ 403 393 if (rc != EXT4_ERR_BAD_DX_DIR) { 404 405 if (rc != EOK) { 394 if (rc != EOK) 406 395 return rc; 407 } 408 396 409 397 return EOK; 410 398 } 411 399 412 400 /* Needed to clear dir index flag if corrupted */ 413 401 ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX); 414 402 parent->dirty = true; 415 403 } 416 404 417 405 /* Linear algorithm */ 418 419 uint32_t iblock = 0, fblock = 0; 406 407 uint32_t iblock = 0; 408 uint32_t fblock = 0; 420 409 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 421 410 uint32_t inode_size = ext4_inode_get_size(fs->superblock, parent->inode); 422 411 uint32_t total_blocks = inode_size / block_size; 423 424 uint32_t name_len = str len(name);425 412 413 uint32_t name_len = str_size(name); 414 426 415 /* Find block, where is space for new entry and try to add */ 427 416 bool success = false; 428 417 for (iblock = 0; iblock < total_blocks; ++iblock) { 429 430 rc = ext4_filesystem_get_inode_data_block_index(parent,iblock, &fblock);431 if (rc != EOK) {418 int rc = ext4_filesystem_get_inode_data_block_index(parent, 419 iblock, &fblock); 420 if (rc != EOK) 432 421 return rc; 433 } 434 422 435 423 block_t *block; 436 424 rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE); 437 if (rc != EOK) {425 if (rc != EOK) 438 426 return rc; 439 } 440 427 441 428 /* If adding is successful, function can finish */ 442 rc = ext4_directory_try_insert_entry(fs->superblock, block, child, name, name_len); 443 if (rc == EOK) { 429 rc = ext4_directory_try_insert_entry(fs->superblock, block, 430 child, name, name_len); 431 if (rc == EOK) 444 432 success = true; 445 } 446 433 447 434 rc = block_put(block); 448 if (rc != EOK) {435 if (rc != EOK) 449 436 return rc; 450 } 451 452 if (success) { 437 438 if (success) 453 439 return EOK; 454 } 455 } 456 440 } 441 457 442 /* No free block found - needed to allocate next data block */ 458 443 459 444 iblock = 0; 460 445 fblock = 0; 461 rc = ext4_filesystem_append_inode_block(parent, &fblock, &iblock);462 if (rc != EOK) {446 int rc = ext4_filesystem_append_inode_block(parent, &fblock, &iblock); 447 if (rc != EOK) 463 448 return rc; 464 } 465 449 466 450 /* Load new block */ 467 451 block_t *new_block; 468 452 rc = block_get(&new_block, fs->device, fblock, BLOCK_FLAGS_NOREAD); 469 if (rc != EOK) {453 if (rc != EOK) 470 454 return rc; 471 } 472 455 473 456 /* Fill block with zeroes */ 474 457 memset(new_block->data, 0, block_size); 475 458 ext4_directory_entry_ll_t *block_entry = new_block->data; 476 ext4_directory_write_entry(fs->superblock, block_entry, block_size, child, name, name_len); 477 459 ext4_directory_write_entry(fs->superblock, block_entry, block_size, 460 child, name, name_len); 461 478 462 /* Save new block */ 479 463 new_block->dirty = true; 480 464 rc = block_put(new_block); 481 if (rc != EOK) { 482 return rc; 483 } 484 485 return EOK; 465 466 return rc; 486 467 } 487 468 488 469 /** Find directory entry with passed name. 489 470 * 490 * @param result result structure to be returned if entry found 491 * @param parent directory i-node 492 * @param name name of entry to be found 493 * @return error code 471 * @param result Result structure to be returned if entry found 472 * @param parent Directory i-node 473 * @param name Name of entry to be found 474 * 475 * @return Error code 476 * 494 477 */ 495 478 int ext4_directory_find_entry(ext4_directory_search_result_t *result, 496 ext4_inode_ref_t *parent, const char *name) 497 { 498 int rc; 499 uint32_t name_len = strlen(name); 500 479 ext4_inode_ref_t *parent, const char *name) 480 { 481 uint32_t name_len = str_size(name); 482 501 483 ext4_superblock_t *sb = parent->fs->superblock; 502 484 503 485 /* Index search */ 504 if (ext4_superblock_has_feature_compatible(sb, EXT4_FEATURE_COMPAT_DIR_INDEX) && 505 ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX)) { 506 507 rc = ext4_directory_dx_find_entry(result, parent, name_len, name); 508 486 if ((ext4_superblock_has_feature_compatible(sb, 487 EXT4_FEATURE_COMPAT_DIR_INDEX)) && 488 (ext4_inode_has_flag(parent->inode, EXT4_INODE_FLAG_INDEX))) { 489 int rc = ext4_directory_dx_find_entry(result, parent, name_len, 490 name); 491 509 492 /* Check if index is not corrupted */ 510 493 if (rc != EXT4_ERR_BAD_DX_DIR) { 511 512 if (rc != EOK) { 494 if (rc != EOK) 513 495 return rc; 514 }496 515 497 return EOK; 516 498 } 517 499 518 500 /* Needed to clear dir index flag if corrupted */ 519 501 ext4_inode_clear_flag(parent->inode, EXT4_INODE_FLAG_INDEX); 520 502 parent->dirty = true; 521 522 } 523 503 } 504 524 505 /* Linear algorithm */ 525 526 uint32_t iblock, fblock; 506 507 uint32_t iblock; 508 uint32_t fblock; 527 509 uint32_t block_size = ext4_superblock_get_block_size(sb); 528 510 uint32_t inode_size = ext4_inode_get_size(sb, parent->inode); 529 511 uint32_t total_blocks = inode_size / block_size; 530 512 531 513 /* Walk through all data blocks */ 532 514 for (iblock = 0; iblock < total_blocks; ++iblock) { 533 534 515 /* Load block address */ 535 rc = ext4_filesystem_get_inode_data_block_index(parent, iblock, &fblock); 536 if (rc != EOK) { 516 int rc = ext4_filesystem_get_inode_data_block_index(parent, iblock, 517 &fblock); 518 if (rc != EOK) 537 519 return rc; 538 } 539 520 540 521 /* Load data block */ 541 522 block_t *block; 542 523 rc = block_get(&block, parent->fs->device, fblock, BLOCK_FLAGS_NONE); 543 if (rc != EOK) {524 if (rc != EOK) 544 525 return rc; 545 } 546 526 547 527 /* Try to find entry in block */ 548 528 ext4_directory_entry_ll_t *res_entry; 549 rc = ext4_directory_find_in_block(block, sb, name_len, name, &res_entry); 529 rc = ext4_directory_find_in_block(block, sb, name_len, name, 530 &res_entry); 550 531 if (rc == EOK) { 551 532 result->block = block; … … 553 534 return EOK; 554 535 } 555 536 556 537 /* Entry not found - put block and continue to the next block */ 557 538 558 539 rc = block_put(block); 559 if (rc != EOK) {540 if (rc != EOK) 560 541 return rc; 561 } 562 } 563 542 } 543 564 544 /* Entry was not found */ 565 545 566 546 result->block = NULL; 567 547 result->dentry = NULL; 568 548 569 549 return ENOENT; 570 550 } 571 551 572 573 552 /** Remove directory entry. 574 553 * 575 * @param parent directory i-node 576 * @param name name of the entry to be removed 577 * @return error code 554 * @param parent Directory i-node 555 * @param name Name of the entry to be removed 556 * 557 * @return Error code 558 * 578 559 */ 579 560 int ext4_directory_remove_entry(ext4_inode_ref_t *parent, const char *name) 580 561 { 581 int rc;582 583 562 /* Check if removing from directory */ 584 563 if (!ext4_inode_is_type(parent->fs->superblock, parent->inode, 585 EXT4_INODE_MODE_DIRECTORY)) {564 EXT4_INODE_MODE_DIRECTORY)) 586 565 return ENOTDIR; 587 } 588 566 589 567 /* Try to find entry */ 590 568 ext4_directory_search_result_t result; 591 rc= ext4_directory_find_entry(&result, parent, name);592 if (rc != EOK) {569 int rc = ext4_directory_find_entry(&result, parent, name); 570 if (rc != EOK) 593 571 return rc; 594 } 595 572 596 573 /* Invalidate entry */ 597 574 ext4_directory_entry_ll_set_inode(result.dentry, 0); 598 575 599 576 /* Store entry position in block */ 600 uint32_t pos = (void *)result.dentry - result.block->data; 601 602 /* If entry is not the first in block, it must be merged 577 uint32_t pos = (void *) result.dentry - result.block->data; 578 579 /* 580 * If entry is not the first in block, it must be merged 603 581 * with previous entry 604 582 */ 605 583 if (pos != 0) { 606 607 584 uint32_t offset = 0; 608 585 609 586 /* Start from the first entry in block */ 610 587 ext4_directory_entry_ll_t *tmp_dentry = result.block->data; 611 588 uint16_t tmp_dentry_length = 612 ext4_directory_entry_ll_get_entry_length(tmp_dentry);613 589 ext4_directory_entry_ll_get_entry_length(tmp_dentry); 590 614 591 /* Find direct predecessor of removed entry */ 615 592 while ((offset + tmp_dentry_length) < pos) { 616 offset += ext4_directory_entry_ll_get_entry_length(tmp_dentry); 593 offset += 594 ext4_directory_entry_ll_get_entry_length(tmp_dentry); 617 595 tmp_dentry = result.block->data + offset; 618 596 tmp_dentry_length = 619 ext4_directory_entry_ll_get_entry_length(tmp_dentry);620 } 621 597 ext4_directory_entry_ll_get_entry_length(tmp_dentry); 598 } 599 622 600 assert(tmp_dentry_length + offset == pos); 623 601 624 602 /* Add to removed entry length to predecessor's length */ 625 603 uint16_t del_entry_length = 626 ext4_directory_entry_ll_get_entry_length(result.dentry);604 ext4_directory_entry_ll_get_entry_length(result.dentry); 627 605 ext4_directory_entry_ll_set_entry_length(tmp_dentry, 628 tmp_dentry_length + del_entry_length); 629 630 } 631 606 tmp_dentry_length + del_entry_length); 607 } 608 632 609 result.block->dirty = true; 633 610 634 611 return ext4_directory_destroy_result(&result); 635 612 } … … 637 614 /** Try to insert entry to concrete data block. 638 615 * 639 * @param sb superblock 640 * @param target_block block to try to insert entry to 641 * @param child child i-node to be inserted by new entry 642 * @param name name of the new entry 643 * @param name_len length of the new entry name 644 * @return error code 616 * @param sb Superblock 617 * @param target_block Block to try to insert entry to 618 * @param child Child i-node to be inserted by new entry 619 * @param name Name of the new entry 620 * @param name_len Length of the new entry name 621 * 622 * @return Error code 623 * 645 624 */ 646 625 int ext4_directory_try_insert_entry(ext4_superblock_t *sb, 647 block_t *target_block, ext4_inode_ref_t *child,648 const char *name,uint32_t name_len)626 block_t *target_block, ext4_inode_ref_t *child, const char *name, 627 uint32_t name_len) 649 628 { 650 629 /* Compute required length entry and align it to 4 bytes */ 651 uint32_t block_size = ext4_superblock_get_block_size(sb); 652 uint16_t required_len = sizeof(ext4_fake_directory_entry_t) + name_len; 653 if ((required_len % 4) != 0) { 654 required_len += 4 - (required_len % 4); 655 } 656 657 /* Initialize pointers, stop means to upper bound */ 658 ext4_directory_entry_ll_t *dentry = target_block->data; 659 ext4_directory_entry_ll_t *stop = target_block->data + block_size; 660 661 /* Walk through the block and check for invalid entries 662 * or entries with free space for new entry 663 */ 664 while (dentry < stop) { 665 666 uint32_t inode = ext4_directory_entry_ll_get_inode(dentry); 667 uint16_t rec_len = ext4_directory_entry_ll_get_entry_length(dentry); 668 669 /* If invalid and large enough entry, use it */ 670 if ((inode == 0) && (rec_len >= required_len)) { 671 ext4_directory_write_entry(sb, dentry, rec_len, child, name, name_len); 672 target_block->dirty = true; 673 return EOK; 674 } 675 676 /* Valid entry, try to split it */ 677 if (inode != 0) { 678 uint16_t used_name_len = 679 ext4_directory_entry_ll_get_name_length(sb, dentry); 680 681 uint16_t used_space = 682 sizeof(ext4_fake_directory_entry_t) + used_name_len; 683 if ((used_name_len % 4) != 0) { 684 used_space += 4 - (used_name_len % 4); 685 } 686 uint16_t free_space = rec_len - used_space; 687 688 /* There is free space for new entry */ 689 if (free_space >= required_len) { 690 691 /* Cut tail of current entry */ 692 ext4_directory_entry_ll_set_entry_length(dentry, used_space); 693 ext4_directory_entry_ll_t *new_entry = 694 (void *)dentry + used_space; 695 ext4_directory_write_entry(sb, new_entry, 696 free_space, child, name, name_len); 697 698 target_block->dirty = true; 630 uint32_t block_size = ext4_superblock_get_block_size(sb); 631 uint16_t required_len = sizeof(ext4_fake_directory_entry_t) + name_len; 632 633 if ((required_len % 4) != 0) 634 required_len += 4 - (required_len % 4); 635 636 /* Initialize pointers, stop means to upper bound */ 637 ext4_directory_entry_ll_t *dentry = target_block->data; 638 ext4_directory_entry_ll_t *stop = target_block->data + block_size; 639 640 /* 641 * Walk through the block and check for invalid entries 642 * or entries with free space for new entry 643 */ 644 while (dentry < stop) { 645 uint32_t inode = ext4_directory_entry_ll_get_inode(dentry); 646 uint16_t rec_len = ext4_directory_entry_ll_get_entry_length(dentry); 647 648 /* If invalid and large enough entry, use it */ 649 if ((inode == 0) && (rec_len >= required_len)) { 650 ext4_directory_write_entry(sb, dentry, rec_len, child, 651 name, name_len); 652 target_block->dirty = true; 653 654 return EOK; 655 } 656 657 /* Valid entry, try to split it */ 658 if (inode != 0) { 659 uint16_t used_name_len = 660 ext4_directory_entry_ll_get_name_length(sb, dentry); 661 662 uint16_t used_space = 663 sizeof(ext4_fake_directory_entry_t) + used_name_len; 664 665 if ((used_name_len % 4) != 0) 666 used_space += 4 - (used_name_len % 4); 667 668 uint16_t free_space = rec_len - used_space; 669 670 /* There is free space for new entry */ 671 if (free_space >= required_len) { 672 /* Cut tail of current entry */ 673 ext4_directory_entry_ll_set_entry_length(dentry, used_space); 674 ext4_directory_entry_ll_t *new_entry = 675 (void *) dentry + used_space; 676 ext4_directory_write_entry(sb, new_entry, 677 free_space, child, name, name_len); 678 679 target_block->dirty = true; 680 699 681 return EOK; 700 } 701 } 702 703 /* Jump to the next entry */ 704 dentry = (void *)dentry + rec_len; 705 } 706 707 /* No free space found for new entry */ 708 709 return ENOSPC; 682 } 683 } 684 685 /* Jump to the next entry */ 686 dentry = (void *) dentry + rec_len; 687 } 688 689 /* No free space found for new entry */ 690 return ENOSPC; 710 691 } 711 692 712 693 /** Try to find entry in block by name. 713 694 * 714 * @param block block containing entries 715 * @param sb superblock 716 * @param name_len length of entry name 717 * @param name name of entry to be found 718 * @param res_entry output pointer to found entry, NULL if not found 719 * @return error code 720 */ 721 int ext4_directory_find_in_block(block_t *block, 722 ext4_superblock_t *sb, size_t name_len, const char *name, 723 ext4_directory_entry_ll_t **res_entry) 695 * @param block Block containing entries 696 * @param sb Superblock 697 * @param name_len Length of entry name 698 * @param name Name of entry to be found 699 * @param res_entry Output pointer to found entry, NULL if not found 700 * 701 * @return Error code 702 * 703 */ 704 int ext4_directory_find_in_block(block_t *block, ext4_superblock_t *sb, 705 size_t name_len, const char *name, ext4_directory_entry_ll_t **res_entry) 724 706 { 725 707 /* Start from the first entry in block */ 726 ext4_directory_entry_ll_t *dentry = (ext4_directory_entry_ll_t *)block->data; 727 /*Set upper bound for cycling */ 708 ext4_directory_entry_ll_t *dentry = 709 (ext4_directory_entry_ll_t *) block->data; 710 711 /* Set upper bound for cycling */ 728 712 uint8_t *addr_limit = block->data + ext4_superblock_get_block_size(sb); 729 713 730 714 /* Walk through the block and check entries */ 731 while ((uint8_t *)dentry < addr_limit) { 732 715 while ((uint8_t *) dentry < addr_limit) { 733 716 /* Termination condition */ 734 if ((uint8_t *) dentry + name_len > addr_limit) {717 if ((uint8_t *) dentry + name_len > addr_limit) 735 718 break; 736 } 737 719 738 720 /* Valid entry - check it */ 739 721 if (dentry->inode != 0) { 740 741 722 /* For more effectivity compare firstly only lengths */ 742 if (name_len == ext4_directory_entry_ll_get_name_length(sb, dentry)) { 723 if (ext4_directory_entry_ll_get_name_length(sb, dentry) == 724 name_len) { 743 725 /* Compare names */ 744 if (bcmp((uint8_t *) name, dentry->name, name_len) == 0) {726 if (bcmp((uint8_t *) name, dentry->name, name_len) == 0) { 745 727 *res_entry = dentry; 746 728 return EOK; … … 748 730 } 749 731 } 750 751 uint16_t dentry_len = ext4_directory_entry_ll_get_entry_length(dentry); 752 732 733 uint16_t dentry_len = 734 ext4_directory_entry_ll_get_entry_length(dentry); 735 753 736 /* Corrupted entry */ 754 if (dentry_len == 0) {737 if (dentry_len == 0) 755 738 return EINVAL; 756 } 757 739 758 740 /* Jump to next entry */ 759 dentry = (ext4_directory_entry_ll_t *) ((uint8_t *)dentry + dentry_len);760 } 761 741 dentry = (ext4_directory_entry_ll_t *) ((uint8_t *) dentry + dentry_len); 742 } 743 762 744 /* Entry not found */ 763 745 return ENOENT; … … 766 748 /** Simple function to release allocated data from result. 767 749 * 768 * @param result search result to destroy 769 * @return error code 750 * @param result Search result to destroy 751 * 752 * @return Error code 753 * 770 754 */ 771 755 int ext4_directory_destroy_result(ext4_directory_search_result_t *result) 772 756 { 773 if (result->block) {757 if (result->block) 774 758 return block_put(result->block); 775 } 776 759 777 760 return EOK; 778 761 } -
uspace/lib/ext4/libext4_directory.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_DIRECTORY_H_ … … 36 36 #include "libext4_types.h" 37 37 38 extern uint32_t ext4_directory_entry_ll_get_inode(ext4_directory_entry_ll_t *);38 extern uint32_t ext4_directory_entry_ll_get_inode(ext4_directory_entry_ll_t *); 39 39 extern void ext4_directory_entry_ll_set_inode(ext4_directory_entry_ll_t *, 40 uint32_t);41 extern uint16_t ext4_directory_entry_ll_get_entry_length(40 uint32_t); 41 extern uint16_t ext4_directory_entry_ll_get_entry_length( 42 42 ext4_directory_entry_ll_t *); 43 extern void ext4_directory_entry_ll_set_entry_length( 44 ext4_directory_entry_ll_t *,uint16_t);45 extern uint16_t ext4_directory_entry_ll_get_name_length(46 ext4_ superblock_t *, ext4_directory_entry_ll_t *);43 extern void ext4_directory_entry_ll_set_entry_length(ext4_directory_entry_ll_t *, 44 uint16_t); 45 extern uint16_t ext4_directory_entry_ll_get_name_length(ext4_superblock_t *, 46 ext4_directory_entry_ll_t *); 47 47 extern void ext4_directory_entry_ll_set_name_length(ext4_superblock_t *, 48 ext4_directory_entry_ll_t *, uint16_t);48 ext4_directory_entry_ll_t *, uint16_t); 49 49 extern uint8_t ext4_directory_entry_ll_get_inode_type(ext4_superblock_t *, 50 ext4_directory_entry_ll_t *);50 ext4_directory_entry_ll_t *); 51 51 extern void ext4_directory_entry_ll_set_inode_type(ext4_superblock_t *, 52 ext4_directory_entry_ll_t *, uint8_t);52 ext4_directory_entry_ll_t *, uint8_t); 53 53 54 54 extern int ext4_directory_iterator_init(ext4_directory_iterator_t *, 55 ext4_inode_ref_t *, aoff64_t);55 ext4_inode_ref_t *, aoff64_t); 56 56 extern int ext4_directory_iterator_next(ext4_directory_iterator_t *); 57 57 extern int ext4_directory_iterator_fini(ext4_directory_iterator_t *); 58 58 59 59 extern void ext4_directory_write_entry(ext4_superblock_t *, 60 ext4_directory_entry_ll_t *, uint16_t, ext4_inode_ref_t *,61 const char *, size_t);62 extern int ext4_directory_add_entry(ext4_inode_ref_t *, 63 const char *,ext4_inode_ref_t *);60 ext4_directory_entry_ll_t *, uint16_t, ext4_inode_ref_t *, 61 const char *, size_t); 62 extern int ext4_directory_add_entry(ext4_inode_ref_t *, const char *, 63 ext4_inode_ref_t *); 64 64 extern int ext4_directory_find_entry(ext4_directory_search_result_t *, 65 ext4_inode_ref_t *, const char *);65 ext4_inode_ref_t *, const char *); 66 66 extern int ext4_directory_remove_entry(ext4_inode_ref_t *, const char *); 67 67 68 extern int ext4_directory_try_insert_entry(ext4_superblock_t *, 69 block_t *,ext4_inode_ref_t *, const char *, uint32_t);68 extern int ext4_directory_try_insert_entry(ext4_superblock_t *, block_t *, 69 ext4_inode_ref_t *, const char *, uint32_t); 70 70 71 extern int ext4_directory_find_in_block(block_t *, 72 ext4_superblock_t *, size_t, const char *, 73 ext4_directory_entry_ll_t **); 71 extern int ext4_directory_find_in_block(block_t *, ext4_superblock_t *, size_t, 72 const char *, ext4_directory_entry_ll_t **); 74 73 75 74 extern int ext4_directory_destroy_result(ext4_directory_search_result_t *); 75 76 76 #endif 77 77 -
uspace/lib/ext4/libext4_directory_index.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_directory_index.c35 * @brief Ext4 directory index operations.33 * @file libext4_directory_index.c 34 * @brief Ext4 directory index operations. 36 35 */ 37 36 … … 40 39 #include <malloc.h> 41 40 #include <sort.h> 42 #include <string.h>43 41 #include "libext4.h" 44 42 … … 52 50 } ext4_dx_sort_entry_t; 53 51 54 55 52 /** Get hash version used in directory index. 56 53 * 57 * @param root_info pointer to root info structure of index 58 * @return hash algorithm version 54 * @param root_info Pointer to root info structure of index 55 * 56 * @return Hash algorithm version 57 * 59 58 */ 60 59 uint8_t ext4_directory_dx_root_info_get_hash_version( 61 ext4_directory_dx_root_info_t *root_info)60 ext4_directory_dx_root_info_t *root_info) 62 61 { 63 62 return root_info->hash_version; … … 66 65 /** Set hash version, that will be used in directory index. 67 66 * 68 * @param root_info pointer to root info structure of index 69 * @param version hash algorithm version 67 * @param root_info Pointer to root info structure of index 68 * @param version Hash algorithm version 69 * 70 70 */ 71 71 void ext4_directory_dx_root_info_set_hash_version( 72 ext4_directory_dx_root_info_t *root_info, uint8_t version)72 ext4_directory_dx_root_info_t *root_info, uint8_t version) 73 73 { 74 74 root_info->hash_version = version; … … 77 77 /** Get length of root_info structure in bytes. 78 78 * 79 * @param root_info pointer to root info structure of index 80 * @return length of the structure 79 * @param root_info Pointer to root info structure of index 80 * 81 * @return Length of the structure 82 * 81 83 */ 82 84 uint8_t ext4_directory_dx_root_info_get_info_length( 83 ext4_directory_dx_root_info_t *root_info)85 ext4_directory_dx_root_info_t *root_info) 84 86 { 85 87 return root_info->info_length; … … 88 90 /** Set length of root_info structure in bytes. 89 91 * 90 * @param root_info pointer to root info structure of index 91 * @param info_length length of the structure 92 * @param root_info Pointer to root info structure of index 93 * @param info_length Length of the structure 94 * 92 95 */ 93 96 void ext4_directory_dx_root_info_set_info_length( 94 ext4_directory_dx_root_info_t *root_info, uint8_t info_length)97 ext4_directory_dx_root_info_t *root_info, uint8_t info_length) 95 98 { 96 99 root_info->info_length = info_length; … … 99 102 /** Get number of indirect levels of HTree. 100 103 * 101 * @param root_info pointer to root info structure of index 102 * @return height of HTree (actually only 0 or 1) 104 * @param root_info Pointer to root info structure of index 105 * 106 * @return Height of HTree (actually only 0 or 1) 107 * 103 108 */ 104 109 uint8_t ext4_directory_dx_root_info_get_indirect_levels( 105 ext4_directory_dx_root_info_t *root_info)110 ext4_directory_dx_root_info_t *root_info) 106 111 { 107 112 return root_info->indirect_levels; … … 110 115 /** Set number of indirect levels of HTree. 111 116 * 112 * @param root_info pointer to root info structure of index 113 * @param levels height of HTree (actually only 0 or 1) 117 * @param root_info Pointer to root info structure of index 118 * @param levels Height of HTree (actually only 0 or 1) 119 * 114 120 */ 115 121 void ext4_directory_dx_root_info_set_indirect_levels( 116 ext4_directory_dx_root_info_t *root_info, uint8_t levels)122 ext4_directory_dx_root_info_t *root_info, uint8_t levels) 117 123 { 118 124 root_info->indirect_levels = levels; … … 121 127 /** Get maximum number of index node entries. 122 128 * 123 * @param countlimit pointer to counlimit structure 124 * @return maximum of entries in node 129 * @param countlimit Pointer to counlimit structure 130 * 131 * @return Maximum of entries in node 132 * 125 133 */ 126 134 uint16_t ext4_directory_dx_countlimit_get_limit( 127 ext4_directory_dx_countlimit_t *countlimit)135 ext4_directory_dx_countlimit_t *countlimit) 128 136 { 129 137 return uint16_t_le2host(countlimit->limit); … … 132 140 /** Set maximum number of index node entries. 133 141 * 134 * @param countlimit pointer to counlimit structure 135 * @param limit maximum of entries in node 142 * @param countlimit Pointer to counlimit structure 143 * @param limit Maximum of entries in node 144 * 136 145 */ 137 146 void ext4_directory_dx_countlimit_set_limit( 138 ext4_directory_dx_countlimit_t *countlimit, uint16_t limit)147 ext4_directory_dx_countlimit_t *countlimit, uint16_t limit) 139 148 { 140 149 countlimit->limit = host2uint16_t_le(limit); … … 143 152 /** Get current number of index node entries. 144 153 * 145 * @param countlimit pointer to counlimit structure 146 * @return number of entries in node 154 * @param countlimit Pointer to counlimit structure 155 * 156 * @return Number of entries in node 157 * 147 158 */ 148 159 uint16_t ext4_directory_dx_countlimit_get_count( 149 ext4_directory_dx_countlimit_t *countlimit)160 ext4_directory_dx_countlimit_t *countlimit) 150 161 { 151 162 return uint16_t_le2host(countlimit->count); … … 154 165 /** Set current number of index node entries. 155 166 * 156 * @param countlimit pointer to counlimit structure 157 * @param count number of entries in node 167 * @param countlimit Pointer to counlimit structure 168 * @param count Number of entries in node 169 * 158 170 */ 159 171 void ext4_directory_dx_countlimit_set_count( 160 ext4_directory_dx_countlimit_t *countlimit, uint16_t count)172 ext4_directory_dx_countlimit_t *countlimit, uint16_t count) 161 173 { 162 174 countlimit->count = host2uint16_t_le(count); … … 165 177 /** Get hash value of index entry. 166 178 * 167 * @param entry pointer to index entry 168 * @return hash value 179 * @param entry Pointer to index entry 180 * 181 * @return Hash value 182 * 169 183 */ 170 184 uint32_t ext4_directory_dx_entry_get_hash(ext4_directory_dx_entry_t *entry) … … 173 187 } 174 188 175 176 189 /** Set hash value of index entry. 177 190 * 178 * @param entry pointer to index entry 179 * @param hash hash value 191 * @param entry Pointer to index entry 192 * @param hash Hash value 193 * 180 194 */ 181 195 void ext4_directory_dx_entry_set_hash(ext4_directory_dx_entry_t *entry, 182 uint32_t hash)196 uint32_t hash) 183 197 { 184 198 entry->hash = host2uint32_t_le(hash); … … 187 201 /** Get block address where child node is located. 188 202 * 189 * @param entry pointer to index entry 190 * @return block address of child node 203 * @param entry Pointer to index entry 204 * 205 * @return Block address of child node 206 * 191 207 */ 192 208 uint32_t ext4_directory_dx_entry_get_block(ext4_directory_dx_entry_t *entry) … … 197 213 /** Set block address where child node is located. 198 214 * 199 * @param entry pointer to index entry 200 * @param block block address of child node 215 * @param entry Pointer to index entry 216 * @param block Block address of child node 217 * 201 218 */ 202 219 void ext4_directory_dx_entry_set_block(ext4_directory_dx_entry_t *entry, 203 uint32_t block)220 uint32_t block) 204 221 { 205 222 entry->block = host2uint32_t_le(block); 206 223 } 207 224 208 209 /**************************************************************************/210 211 225 /** Initialize index structure of new directory. 212 226 * 213 * @param dir pointer to directory i-node 214 * @return error code 227 * @param dir Pointer to directory i-node 228 * 229 * @return Error code 230 * 215 231 */ 216 232 int ext4_directory_dx_init(ext4_inode_ref_t *dir) 217 233 { 218 int rc;219 220 234 /* Load block 0, where will be index root located */ 221 235 uint32_t fblock; 222 rc = ext4_filesystem_get_inode_data_block_index(dir, 0, &fblock);223 if (rc != EOK) {224 return rc;225 }226 236 int rc = ext4_filesystem_get_inode_data_block_index(dir, 0, 237 &fblock); 238 if (rc != EOK) 239 return rc; 240 227 241 block_t *block; 228 242 rc = block_get(&block, dir->fs->device, fblock, BLOCK_FLAGS_NONE); 229 if (rc != EOK) { 230 return rc; 231 } 232 243 if (rc != EOK) 244 return rc; 245 233 246 /* Initialize pointers to data structures */ 234 247 ext4_directory_dx_root_t *root = block->data; 235 248 ext4_directory_dx_root_info_t *info = &(root->info); 236 249 237 250 /* Initialize root info structure */ 238 251 uint8_t hash_version = 239 ext4_superblock_get_default_hash_version(dir->fs->superblock);240 252 ext4_superblock_get_default_hash_version(dir->fs->superblock); 253 241 254 ext4_directory_dx_root_info_set_hash_version(info, hash_version); 242 255 ext4_directory_dx_root_info_set_indirect_levels(info, 0); 243 256 ext4_directory_dx_root_info_set_info_length(info, 8); 244 257 245 258 /* Set limit and current number of entries */ 246 259 ext4_directory_dx_countlimit_t *countlimit = 247 (ext4_directory_dx_countlimit_t *)&root->entries;260 (ext4_directory_dx_countlimit_t *) &root->entries; 248 261 ext4_directory_dx_countlimit_set_count(countlimit, 1); 249 250 uint32_t block_size = ext4_superblock_get_block_size(dir->fs->superblock); 251 uint32_t entry_space = block_size - 2 * sizeof(ext4_directory_dx_dot_entry_t) 252 - sizeof(ext4_directory_dx_root_info_t); 262 263 uint32_t block_size = 264 ext4_superblock_get_block_size(dir->fs->superblock); 265 uint32_t entry_space = 266 block_size - 2 * sizeof(ext4_directory_dx_dot_entry_t) - 267 sizeof(ext4_directory_dx_root_info_t); 253 268 uint16_t root_limit = entry_space / sizeof(ext4_directory_dx_entry_t); 254 269 ext4_directory_dx_countlimit_set_limit(countlimit, root_limit); 255 270 256 271 /* Append new block, where will be new entries inserted in the future */ 257 272 uint32_t iblock; … … 261 276 return rc; 262 277 } 263 278 264 279 block_t *new_block; 265 280 rc = block_get(&new_block, dir->fs->device, fblock, BLOCK_FLAGS_NOREAD); … … 268 283 return rc; 269 284 } 270 285 271 286 /* Fill the whole block with empty entry */ 272 287 ext4_directory_entry_ll_t *block_entry = new_block->data; 273 288 ext4_directory_entry_ll_set_entry_length(block_entry, block_size); 274 289 ext4_directory_entry_ll_set_inode(block_entry, 0); 275 290 276 291 new_block->dirty = true; 277 292 rc = block_put(new_block); … … 280 295 return rc; 281 296 } 282 297 283 298 /* Connect new block to the only entry in index */ 284 299 ext4_directory_dx_entry_t *entry = root->entries; 285 300 ext4_directory_dx_entry_set_block(entry, iblock); 286 301 287 302 block->dirty = true; 288 289 rc = block_put(block); 290 if (rc != EOK) { 291 return rc; 292 } 293 294 return EOK; 303 304 return block_put(block); 295 305 } 296 306 297 307 /** Initialize hash info structure necessary for index operations. 298 308 * 299 * @param hinfo pointer to hinfo to be initialized 300 * @param root_block root block (number 0) of index 301 * @param sb pointer to superblock 302 * @param name_len length of name to be computed hash value from 303 * @param name name to be computed hash value from 304 * @return error code 305 */ 306 static int ext4_directory_hinfo_init(ext4_hash_info_t *hinfo, block_t *root_block, 307 ext4_superblock_t *sb, size_t name_len, const char *name) 308 { 309 310 ext4_directory_dx_root_t *root = (ext4_directory_dx_root_t *)root_block->data; 311 312 if (root->info.hash_version != EXT4_HASH_VERSION_TEA && 313 root->info.hash_version != EXT4_HASH_VERSION_HALF_MD4 && 314 root->info.hash_version != EXT4_HASH_VERSION_LEGACY) { 309 * @param hinfo Pointer to hinfo to be initialized 310 * @param root_block Root block (number 0) of index 311 * @param sb Pointer to superblock 312 * @param name_len Length of name to be computed hash value from 313 * @param name Name to be computed hash value from 314 * 315 * @return Error code 316 * 317 */ 318 static int ext4_directory_hinfo_init(ext4_hash_info_t *hinfo, 319 block_t *root_block, ext4_superblock_t *sb, size_t name_len, 320 const char *name) 321 { 322 ext4_directory_dx_root_t *root = 323 (ext4_directory_dx_root_t *) root_block->data; 324 325 if ((root->info.hash_version != EXT4_HASH_VERSION_TEA) && 326 (root->info.hash_version != EXT4_HASH_VERSION_HALF_MD4) && 327 (root->info.hash_version != EXT4_HASH_VERSION_LEGACY)) 315 328 return EXT4_ERR_BAD_DX_DIR; 316 } 317 329 318 330 /* Check unused flags */ 319 if (root->info.unused_flags != 0) {331 if (root->info.unused_flags != 0) 320 332 return EXT4_ERR_BAD_DX_DIR; 321 } 322 333 323 334 /* Check indirect levels */ 324 if (root->info.indirect_levels > 1) {335 if (root->info.indirect_levels > 1) 325 336 return EXT4_ERR_BAD_DX_DIR; 326 } 327 337 328 338 /* Check if node limit is correct */ 329 339 uint32_t block_size = ext4_superblock_get_block_size(sb); … … 331 341 entry_space -= 2 * sizeof(ext4_directory_dx_dot_entry_t); 332 342 entry_space -= sizeof(ext4_directory_dx_root_info_t); 333 entry_space = entry_space / sizeof(ext4_directory_dx_entry_t); 334 335 uint16_t limit = ext4_directory_dx_countlimit_get_limit((ext4_directory_dx_countlimit_t *)&root->entries); 336 if (limit != entry_space) { 337 return EXT4_ERR_BAD_DX_DIR; 338 } 339 340 /* Check hash version and modify if necessary */ 341 hinfo->hash_version = ext4_directory_dx_root_info_get_hash_version(&root->info); 342 if ((hinfo->hash_version <= EXT4_HASH_VERSION_TEA) 343 && (ext4_superblock_has_flag(sb, EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH))) { 343 entry_space = entry_space / sizeof(ext4_directory_dx_entry_t); 344 345 uint16_t limit = ext4_directory_dx_countlimit_get_limit( 346 (ext4_directory_dx_countlimit_t *) &root->entries); 347 if (limit != entry_space) 348 return EXT4_ERR_BAD_DX_DIR; 349 350 /* Check hash version and modify if necessary */ 351 hinfo->hash_version = 352 ext4_directory_dx_root_info_get_hash_version(&root->info); 353 if ((hinfo->hash_version <= EXT4_HASH_VERSION_TEA) && 354 (ext4_superblock_has_flag(sb, EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH))) { 344 355 /* 3 is magic from ext4 linux implementation */ 345 356 hinfo->hash_version += 3; 346 357 } 347 358 348 359 /* Load hash seed from superblock */ 349 360 hinfo->seed = ext4_superblock_get_hash_seed(sb); 350 361 351 362 /* Compute hash value of name */ 352 if (name) {363 if (name) 353 364 ext4_hash_string(hinfo, name_len, name); 354 } 355 365 356 366 return EOK; 357 367 } … … 359 369 /** Walk through index tree and load leaf with corresponding hash value. 360 370 * 361 * @param hinfo initialized hash info structure 362 * @param inode_ref current i-node 363 * @param root_block root block (iblock 0), where is root node located 364 * @param dx_block pointer to leaf node in dx_blocks array 365 * @param dx_blocks array with the whole path from root to leaf 366 * @return error code 371 * @param hinfo Initialized hash info structure 372 * @param inode_ref Current i-node 373 * @param root_block Root block (iblock 0), where is root node located 374 * @param dx_block Pointer to leaf node in dx_blocks array 375 * @param dx_blocks Array with the whole path from root to leaf 376 * 377 * @return Error code 378 * 367 379 */ 368 380 static int ext4_directory_dx_get_leaf(ext4_hash_info_t *hinfo, 369 ext4_inode_ref_t *inode_ref, block_t *root_block, 370 ext4_directory_dx_block_t **dx_block, ext4_directory_dx_block_t *dx_blocks) 371 { 372 int rc; 373 381 ext4_inode_ref_t *inode_ref, block_t *root_block, 382 ext4_directory_dx_block_t **dx_block, ext4_directory_dx_block_t *dx_blocks) 383 { 374 384 ext4_directory_dx_block_t *tmp_dx_block = dx_blocks; 375 376 ext4_directory_dx_root_t *root = (ext4_directory_dx_root_t *)root_block->data; 377 ext4_directory_dx_entry_t *entries = (ext4_directory_dx_entry_t *)&root->entries; 378 379 uint16_t limit = ext4_directory_dx_countlimit_get_limit((ext4_directory_dx_countlimit_t *)entries); 380 uint8_t indirect_level = ext4_directory_dx_root_info_get_indirect_levels(&root->info); 381 385 ext4_directory_dx_root_t *root = 386 (ext4_directory_dx_root_t *) root_block->data; 387 ext4_directory_dx_entry_t *entries = 388 (ext4_directory_dx_entry_t *) &root->entries; 389 390 uint16_t limit = ext4_directory_dx_countlimit_get_limit( 391 (ext4_directory_dx_countlimit_t *) entries); 392 uint8_t indirect_level = 393 ext4_directory_dx_root_info_get_indirect_levels(&root->info); 394 382 395 block_t *tmp_block = root_block; 383 ext4_directory_dx_entry_t *p, *q, *m, *at; 384 396 ext4_directory_dx_entry_t *p; 397 ext4_directory_dx_entry_t *q; 398 ext4_directory_dx_entry_t *m; 399 ext4_directory_dx_entry_t *at; 400 385 401 /* Walk through the index tree */ 386 402 while (true) { 387 388 uint16_t count = ext4_directory_dx_countlimit_get_count((ext4_directory_dx_countlimit_t *)entries);389 if ((count == 0) || (count > limit)) {403 uint16_t count = ext4_directory_dx_countlimit_get_count( 404 (ext4_directory_dx_countlimit_t *) entries); 405 if ((count == 0) || (count > limit)) 390 406 return EXT4_ERR_BAD_DX_DIR; 391 } 392 393 407 394 408 /* Do binary search in every node */ 395 409 p = entries + 1; 396 410 q = entries + count - 1; 397 411 398 412 while (p <= q) { 399 413 m = p + (q - p) / 2; 400 if (ext4_directory_dx_entry_get_hash(m) > hinfo->hash) {414 if (ext4_directory_dx_entry_get_hash(m) > hinfo->hash) 401 415 q = m - 1; 402 } else {416 else 403 417 p = m + 1; 404 }405 418 } 406 419 407 420 at = p - 1; 408 421 409 422 /* Write results */ 410 423 tmp_dx_block->block = tmp_block; 411 424 tmp_dx_block->entries = entries; 412 425 tmp_dx_block->position = at; 413 426 414 427 /* Is algorithm in the leaf? */ 415 if (indirect_level == 0) {416 *dx_block = tmp_dx_block;417 return EOK;418 }419 420 /* Goto child node */428 if (indirect_level == 0) { 429 *dx_block = tmp_dx_block; 430 return EOK; 431 } 432 433 /* Goto child node */ 421 434 uint32_t next_block = ext4_directory_dx_entry_get_block(at); 422 423 indirect_level--; 424 425 uint32_t fblock; 426 rc = ext4_filesystem_get_inode_data_block_index( 427 inode_ref, next_block, &fblock); 428 if (rc != EOK) { 429 return rc; 430 } 431 432 rc = block_get(&tmp_block, inode_ref->fs->device, fblock, BLOCK_FLAGS_NONE); 433 if (rc != EOK) { 434 return rc; 435 } 436 435 436 indirect_level--; 437 438 uint32_t fblock; 439 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 440 next_block, &fblock); 441 if (rc != EOK) 442 return rc; 443 444 rc = block_get(&tmp_block, inode_ref->fs->device, fblock, 445 BLOCK_FLAGS_NONE); 446 if (rc != EOK) 447 return rc; 448 437 449 entries = ((ext4_directory_dx_node_t *) tmp_block->data)->entries; 438 450 limit = ext4_directory_dx_countlimit_get_limit( 439 (ext4_directory_dx_countlimit_t *)entries);440 441 uint16_t entry_space = ext4_superblock_get_block_size(inode_ref->fs->superblock) 442 - sizeof(ext4_directory_dx_dot_entry_t); 443 entry_space = entry_space / sizeof(ext4_directory_dx_entry_t);444 445 451 (ext4_directory_dx_countlimit_t *) entries); 452 453 uint16_t entry_space = 454 ext4_superblock_get_block_size(inode_ref->fs->superblock) - 455 sizeof(ext4_directory_dx_dot_entry_t); 456 entry_space = entry_space / sizeof(ext4_directory_dx_entry_t); 457 446 458 if (limit != entry_space) { 447 459 block_put(tmp_block); 448 return EXT4_ERR_BAD_DX_DIR;460 return EXT4_ERR_BAD_DX_DIR; 449 461 } 450 462 451 463 ++tmp_dx_block; 452 464 } 453 465 454 466 /* Unreachable */ 455 467 return EOK; 456 468 } 457 469 458 459 470 /** Check if the the next block would be checked during entry search. 460 471 * 461 * @param inode_ref directory i-node 462 * @param hash hash value to check 463 * @param dx_block current block 464 * @param dx_blocks aray with path from root to leaf node 465 * @return error code 466 */ 467 static int ext4_directory_dx_next_block(ext4_inode_ref_t *inode_ref, uint32_t hash, 468 ext4_directory_dx_block_t *dx_block, ext4_directory_dx_block_t *dx_blocks) 469 { 470 int rc; 471 472 uint32_t num_handles = 0; 473 ext4_directory_dx_block_t *p = dx_block; 474 475 /* Try to find data block with next bunch of entries */ 476 while (1) { 477 478 p->position++; 479 uint16_t count = ext4_directory_dx_countlimit_get_count( 480 (ext4_directory_dx_countlimit_t *)p->entries); 481 482 if (p->position < p->entries + count) { 483 break; 484 } 485 486 if (p == dx_blocks) { 487 return 0; 488 } 489 490 num_handles++; 491 p--; 492 } 493 494 /* Check hash collision (if not occured - no next block cannot be used) */ 495 uint32_t current_hash = ext4_directory_dx_entry_get_hash(p->position); 496 if ((hash & 1) == 0) { 497 if ((current_hash & ~1) != hash) { 498 return 0; 499 } 500 } 501 502 /* Fill new path */ 503 while (num_handles--) { 504 505 uint32_t block_idx = ext4_directory_dx_entry_get_block(p->position); 506 uint32_t block_addr; 507 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, block_idx, &block_addr); 508 if (rc != EOK) { 509 return rc; 510 } 511 512 block_t *block; 513 rc = block_get(&block, inode_ref->fs->device, block_addr, BLOCK_FLAGS_NONE); 514 if (rc != EOK) { 515 return rc; 516 } 517 518 p++; 519 520 /* Don't forget to put old block (prevent memory leak) */ 521 block_put(p->block); 522 523 p->block = block; 524 p->entries = ((ext4_directory_dx_node_t *) block->data)->entries; 525 p->position = p->entries; 526 } 527 528 return 1; 529 472 * @param inode_ref Directory i-node 473 * @param hash Hash value to check 474 * @param dx_block Current block 475 * @param dx_blocks Array with path from root to leaf node 476 * 477 * @return Error code 478 * 479 */ 480 static int ext4_directory_dx_next_block(ext4_inode_ref_t *inode_ref, 481 uint32_t hash, ext4_directory_dx_block_t *dx_block, 482 ext4_directory_dx_block_t *dx_blocks) 483 { 484 uint32_t num_handles = 0; 485 ext4_directory_dx_block_t *p = dx_block; 486 487 /* Try to find data block with next bunch of entries */ 488 while (true) { 489 p->position++; 490 uint16_t count = ext4_directory_dx_countlimit_get_count( 491 (ext4_directory_dx_countlimit_t *) p->entries); 492 493 if (p->position < p->entries + count) 494 break; 495 496 if (p == dx_blocks) 497 return EOK; 498 499 num_handles++; 500 p--; 501 } 502 503 /* Check hash collision (if not occured - no next block cannot be used) */ 504 uint32_t current_hash = ext4_directory_dx_entry_get_hash(p->position); 505 if ((hash & 1) == 0) { 506 if ((current_hash & ~1) != hash) 507 return 0; 508 } 509 510 /* Fill new path */ 511 while (num_handles--) { 512 uint32_t block_idx = 513 ext4_directory_dx_entry_get_block(p->position); 514 uint32_t block_addr; 515 516 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 517 block_idx, &block_addr); 518 if (rc != EOK) 519 return rc; 520 521 block_t *block; 522 rc = block_get(&block, inode_ref->fs->device, block_addr, BLOCK_FLAGS_NONE); 523 if (rc != EOK) 524 return rc; 525 526 p++; 527 528 /* Don't forget to put old block (prevent memory leak) */ 529 block_put(p->block); 530 531 p->block = block; 532 p->entries = ((ext4_directory_dx_node_t *) block->data)->entries; 533 p->position = p->entries; 534 } 535 536 return ENOENT; 530 537 } 531 538 532 539 /** Try to find directory entry using directory index. 533 540 * 534 * @param result output value - if entry will be found, 535 * than will be passed through this parameter 536 * @param inode_ref directory i-node 537 * @param name_len length of name to be found 538 * @param name name to be found 539 * @return error code 541 * @param result Output value - if entry will be found, 542 * than will be passed through this parameter 543 * @param inode_ref Directory i-node 544 * @param name_len Length of name to be found 545 * @param name Name to be found 546 * 547 * @return Error code 548 * 540 549 */ 541 550 int ext4_directory_dx_find_entry(ext4_directory_search_result_t *result, 542 ext4_inode_ref_t *inode_ref, size_t name_len, const char *name) 543 { 544 int rc; 545 551 ext4_inode_ref_t *inode_ref, size_t name_len, const char *name) 552 { 546 553 /* Load direct block 0 (index root) */ 547 554 uint32_t root_block_addr; 548 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 0, &root_block_addr);549 if (rc != EOK) {550 return rc;551 }552 555 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 0, 556 &root_block_addr); 557 if (rc != EOK) 558 return rc; 559 553 560 ext4_filesystem_t *fs = inode_ref->fs; 554 561 555 562 block_t *root_block; 556 rc = block_get(&root_block, fs->device, root_block_addr, BLOCK_FLAGS_NONE);557 if (rc != EOK) {558 return rc;559 }560 563 rc = block_get(&root_block, fs->device, root_block_addr, 564 BLOCK_FLAGS_NONE); 565 if (rc != EOK) 566 return rc; 567 561 568 /* Initialize hash info (compute hash value) */ 562 569 ext4_hash_info_t hinfo; 563 rc = ext4_directory_hinfo_init(&hinfo, root_block, fs->superblock, name_len, name); 570 rc = ext4_directory_hinfo_init(&hinfo, root_block, fs->superblock, 571 name_len, name); 564 572 if (rc != EOK) { 565 573 block_put(root_block); 566 574 return EXT4_ERR_BAD_DX_DIR; 567 575 } 568 569 /* Hardcoded number 2 means maximum height of index tree, specified in linux driver */ 576 577 /* 578 * Hardcoded number 2 means maximum height of index tree, 579 * specified in the Linux driver. 580 */ 570 581 ext4_directory_dx_block_t dx_blocks[2]; 571 ext4_directory_dx_block_t *dx_block, *tmp; 572 rc = ext4_directory_dx_get_leaf(&hinfo, inode_ref, root_block, &dx_block, dx_blocks); 582 ext4_directory_dx_block_t *dx_block; 583 ext4_directory_dx_block_t *tmp; 584 585 rc = ext4_directory_dx_get_leaf(&hinfo, inode_ref, root_block, 586 &dx_block, dx_blocks); 573 587 if (rc != EOK) { 574 588 block_put(root_block); 575 589 return EXT4_ERR_BAD_DX_DIR; 576 590 } 577 591 578 592 do { 579 593 /* Load leaf block */ 580 uint32_t leaf_block_idx = ext4_directory_dx_entry_get_block(dx_block->position); 594 uint32_t leaf_block_idx = 595 ext4_directory_dx_entry_get_block(dx_block->position); 581 596 uint32_t leaf_block_addr; 582 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, leaf_block_idx, &leaf_block_addr); 583 if (rc != EOK) { 584 goto cleanup; 585 } 586 587 block_t *leaf_block; 588 rc = block_get(&leaf_block, fs->device, leaf_block_addr, BLOCK_FLAGS_NONE); 589 if (rc != EOK) { 597 598 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 599 leaf_block_idx, &leaf_block_addr); 600 if (rc != EOK) 590 601 goto cleanup; 591 } 592 602 603 block_t *leaf_block; 604 rc = block_get(&leaf_block, fs->device, leaf_block_addr, 605 BLOCK_FLAGS_NONE); 606 if (rc != EOK) 607 goto cleanup; 608 593 609 /* Linear search inside block */ 594 610 ext4_directory_entry_ll_t *res_dentry; 595 rc = ext4_directory_find_in_block(leaf_block, fs->superblock, name_len, name, &res_dentry); 596 611 rc = ext4_directory_find_in_block(leaf_block, fs->superblock, 612 name_len, name, &res_dentry); 613 597 614 /* Found => return it */ 598 615 if (rc == EOK) { … … 601 618 goto cleanup; 602 619 } 603 620 604 621 /* Not found, leave untouched */ 605 622 block_put(leaf_block); 606 607 if (rc != ENOENT) {623 624 if (rc != ENOENT) 608 625 goto cleanup; 609 } 610 626 611 627 /* check if the next block could be checked */ 612 rc = ext4_directory_dx_next_block(inode_ref, hinfo.hash, dx_block, &dx_blocks[0]); 613 if (rc < 0) { 628 rc = ext4_directory_dx_next_block(inode_ref, hinfo.hash, 629 dx_block, &dx_blocks[0]); 630 if (rc < 0) 614 631 goto cleanup; 615 } 616 617 } while (rc == 1); 618 632 } while (rc == ENOENT); 633 619 634 /* Entry not found */ 620 635 rc = ENOENT; 621 636 622 637 cleanup: 623 624 638 /* The whole path must be released (preventing memory leak) */ 625 639 tmp = dx_blocks; 640 626 641 while (tmp <= dx_block) { 627 642 block_put(tmp->block); 628 643 ++tmp; 629 644 } 645 630 646 return rc; 631 647 } … … 635 651 * It can compare two entries by hash value. 636 652 * 637 * @param arg1 first entry 638 * @param arg2 second entry 639 * @param dummy unused parameter, can be NULL 640 * @return classic compare result (0: equal, -1: arg1 < arg2, 1: arg1 > arg2) 653 * @param arg1 First entry 654 * @param arg2 Second entry 655 * @param dummy Unused parameter, can be NULL 656 * 657 * @return Classic compare result 658 * (0: equal, -1: arg1 < arg2, 1: arg1 > arg2) 659 * 641 660 */ 642 661 static int ext4_directory_dx_entry_comparator(void *arg1, void *arg2, void *dummy) … … 644 663 ext4_dx_sort_entry_t *entry1 = arg1; 645 664 ext4_dx_sort_entry_t *entry2 = arg2; 646 647 if (entry1->hash == entry2->hash) {665 666 if (entry1->hash == entry2->hash) 648 667 return 0; 649 } 650 651 if (entry1->hash < entry2->hash) { 668 669 if (entry1->hash < entry2->hash) 652 670 return -1; 653 } else {671 else 654 672 return 1; 655 }656 657 673 } 658 674 … … 661 677 * Note that space for new entry must be checked by caller. 662 678 * 663 * @param index_block block where to insert new entry664 * @param hash hash value covered by child node665 * @param iblock logical number of child block679 * @param index_block Block where to insert new entry 680 * @param hash Hash value covered by child node 681 * @param iblock Logical number of child block 666 682 * 667 683 */ 668 684 static void ext4_directory_dx_insert_entry( 669 ext4_directory_dx_block_t *index_block, uint32_t hash, uint32_t iblock)685 ext4_directory_dx_block_t *index_block, uint32_t hash, uint32_t iblock) 670 686 { 671 687 ext4_directory_dx_entry_t *old_index_entry = index_block->position; 672 688 ext4_directory_dx_entry_t *new_index_entry = old_index_entry + 1; 673 689 674 690 ext4_directory_dx_countlimit_t *countlimit = 675 (ext4_directory_dx_countlimit_t *)index_block->entries;691 (ext4_directory_dx_countlimit_t *) index_block->entries; 676 692 uint32_t count = ext4_directory_dx_countlimit_get_count(countlimit); 677 693 678 694 ext4_directory_dx_entry_t *start_index = index_block->entries; 679 size_t bytes = (void *) (start_index + count) - (void *)(new_index_entry);680 695 size_t bytes = (void *) (start_index + count) - (void *) (new_index_entry); 696 681 697 memmove(new_index_entry + 1, new_index_entry, bytes); 682 698 683 699 ext4_directory_dx_entry_set_block(new_index_entry, iblock); 684 700 ext4_directory_dx_entry_set_hash(new_index_entry, hash); 685 701 686 702 ext4_directory_dx_countlimit_set_count(countlimit, count + 1); 687 703 688 704 index_block->block->dirty = true; 689 705 } … … 691 707 /** Split directory entries to two parts preventing node overflow. 692 708 * 693 * @param inode_ref directory i-node 694 * @param hinfo hash info 695 * @param old_data_block block with data to be split 696 * @param index_block block where index entries are located 697 * @param new_data_block output value for newly allocated data block 709 * @param inode_ref Directory i-node 710 * @param hinfo Hash info 711 * @param old_data_block Block with data to be split 712 * @param index_block Block where index entries are located 713 * @param new_data_block Output value for newly allocated data block 714 * 698 715 */ 699 716 static int ext4_directory_dx_split_data(ext4_inode_ref_t *inode_ref, 700 ext4_hash_info_t *hinfo, block_t *old_data_block,701 ext4_directory_dx_block_t *index_block, block_t **new_data_block)717 ext4_hash_info_t *hinfo, block_t *old_data_block, 718 ext4_directory_dx_block_t *index_block, block_t **new_data_block) 702 719 { 703 720 int rc = EOK; 704 721 705 722 /* Allocate buffer for directory entries */ 706 723 uint32_t block_size = 707 ext4_superblock_get_block_size(inode_ref->fs->superblock);724 ext4_superblock_get_block_size(inode_ref->fs->superblock); 708 725 void *entry_buffer = malloc(block_size); 709 if (entry_buffer == NULL) {726 if (entry_buffer == NULL) 710 727 return ENOMEM; 711 } 712 728 713 729 /* dot entry has the smallest size available */ 714 uint32_t max_entry_count = block_size / sizeof(ext4_directory_dx_dot_entry_t); 715 730 uint32_t max_entry_count = 731 block_size / sizeof(ext4_directory_dx_dot_entry_t); 732 716 733 /* Allocate sort entry */ 717 ext4_dx_sort_entry_t *sort_array = malloc(max_entry_count * sizeof(ext4_dx_sort_entry_t)); 734 ext4_dx_sort_entry_t *sort_array = 735 malloc(max_entry_count * sizeof(ext4_dx_sort_entry_t)); 718 736 if (sort_array == NULL) { 719 737 free(entry_buffer); 720 738 return ENOMEM; 721 739 } 722 740 723 741 uint32_t idx = 0; 724 742 uint32_t real_size = 0; 725 743 726 744 /* Initialize hinfo */ 727 745 ext4_hash_info_t tmp_hinfo; 728 746 memcpy(&tmp_hinfo, hinfo, sizeof(ext4_hash_info_t)); 729 747 730 748 /* Load all valid entries to the buffer */ 731 749 ext4_directory_entry_ll_t *dentry = old_data_block->data; 732 750 void *entry_buffer_ptr = entry_buffer; 733 751 while ((void *)dentry < old_data_block->data + block_size) { 734 735 752 /* Read only valid entries */ 736 753 if (ext4_directory_entry_ll_get_inode(dentry) != 0) { 737 738 754 uint8_t len = ext4_directory_entry_ll_get_name_length( 739 inode_ref->fs->superblock, dentry);740 ext4_hash_string(&tmp_hinfo, len, (char *) dentry->name);741 755 inode_ref->fs->superblock, dentry); 756 ext4_hash_string(&tmp_hinfo, len, (char *) dentry->name); 757 742 758 uint32_t rec_len = 8 + len; 743 744 if ((rec_len % 4) != 0) {759 760 if ((rec_len % 4) != 0) 745 761 rec_len += 4 - (rec_len % 4); 746 } 747 762 748 763 memcpy(entry_buffer_ptr, dentry, rec_len); 749 764 750 765 sort_array[idx].dentry = entry_buffer_ptr; 751 766 sort_array[idx].rec_len = rec_len; 752 767 sort_array[idx].hash = tmp_hinfo.hash; 753 768 754 769 entry_buffer_ptr += rec_len; 755 770 real_size += rec_len; 756 771 idx++; 757 772 } 758 759 dentry = (void *)dentry + ext4_directory_entry_ll_get_entry_length(dentry); 760 } 761 773 774 dentry = (void *) dentry + 775 ext4_directory_entry_ll_get_entry_length(dentry); 776 } 777 762 778 /* Sort all entries */ 763 779 qsort(sort_array, idx, sizeof(ext4_dx_sort_entry_t), 764 ext4_directory_dx_entry_comparator, NULL);765 780 ext4_directory_dx_entry_comparator, NULL); 781 766 782 /* Allocate new block for store the second part of entries */ 767 783 uint32_t new_fblock; 768 784 uint32_t new_iblock; 769 rc = ext4_filesystem_append_inode_block(inode_ref, &new_fblock, &new_iblock); 785 rc = ext4_filesystem_append_inode_block(inode_ref, &new_fblock, 786 &new_iblock); 770 787 if (rc != EOK) { 771 788 free(sort_array); … … 773 790 return rc; 774 791 } 775 792 776 793 /* Load new block */ 777 794 block_t *new_data_block_tmp; 778 795 rc = block_get(&new_data_block_tmp, inode_ref->fs->device, 779 new_fblock, BLOCK_FLAGS_NOREAD);796 new_fblock, BLOCK_FLAGS_NOREAD); 780 797 if (rc != EOK) { 781 798 free(sort_array); … … 783 800 return rc; 784 801 } 785 786 /* Distribute entries to two blocks (by size) 802 803 /* 804 * Distribute entries to two blocks (by size) 787 805 * - compute the half 788 806 */ … … 796 814 break; 797 815 } 798 816 799 817 current_size += sort_array[i].rec_len; 800 818 } 801 819 802 820 /* Check hash collision */ 803 821 uint32_t continued = 0; 804 if (new_hash == sort_array[mid-1].hash) {822 if (new_hash == sort_array[mid-1].hash) 805 823 continued = 1; 806 } 807 824 808 825 uint32_t offset = 0; 809 826 void *ptr; 810 827 811 828 /* First part - to the old block */ 812 829 for (uint32_t i = 0; i < mid; ++i) { 813 830 ptr = old_data_block->data + offset; 814 831 memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len); 815 832 816 833 ext4_directory_entry_ll_t *tmp = ptr; 817 if (i < (mid - 1)) { 818 ext4_directory_entry_ll_set_entry_length(tmp, sort_array[i].rec_len); 819 } else { 820 ext4_directory_entry_ll_set_entry_length(tmp, block_size - offset); 821 } 822 834 if (i < (mid - 1)) 835 ext4_directory_entry_ll_set_entry_length(tmp, 836 sort_array[i].rec_len); 837 else 838 ext4_directory_entry_ll_set_entry_length(tmp, 839 block_size - offset); 840 823 841 offset += sort_array[i].rec_len; 824 842 } 825 843 826 844 /* Second part - to the new block */ 827 845 offset = 0; … … 829 847 ptr = new_data_block_tmp->data + offset; 830 848 memcpy(ptr, sort_array[i].dentry, sort_array[i].rec_len); 831 849 832 850 ext4_directory_entry_ll_t *tmp = ptr; 833 if (i < (idx - 1)) { 834 ext4_directory_entry_ll_set_entry_length(tmp, sort_array[i].rec_len); 835 } else { 836 ext4_directory_entry_ll_set_entry_length(tmp, block_size - offset); 837 } 838 851 if (i < (idx - 1)) 852 ext4_directory_entry_ll_set_entry_length(tmp, 853 sort_array[i].rec_len); 854 else 855 ext4_directory_entry_ll_set_entry_length(tmp, 856 block_size - offset); 857 839 858 offset += sort_array[i].rec_len; 840 859 } 841 860 842 861 /* Do some steps to finish operation */ 843 862 old_data_block->dirty = true; 844 863 new_data_block_tmp->dirty = true; 845 864 846 865 free(sort_array); 847 866 free(entry_buffer); 848 849 ext4_directory_dx_insert_entry(index_block, new_hash + continued, new_iblock); 850 867 868 ext4_directory_dx_insert_entry(index_block, new_hash + continued, 869 new_iblock); 870 851 871 *new_data_block = new_data_block_tmp; 852 872 853 873 return EOK; 854 874 } … … 856 876 /** Split index node and maybe some parent nodes in the tree hierarchy. 857 877 * 858 * @param inode_ref directory i-node 859 * @param dx_blocks array with path from root to leaf node 860 * @param dx_block leaf block to be split if needed 861 * @return error code 878 * @param inode_ref Directory i-node 879 * @param dx_blocks Array with path from root to leaf node 880 * @param dx_block Leaf block to be split if needed 881 * 882 * @return Error code 883 * 862 884 */ 863 885 static int ext4_directory_dx_split_index(ext4_inode_ref_t *inode_ref, 864 886 ext4_directory_dx_block_t *dx_blocks, ext4_directory_dx_block_t *dx_block) 865 887 { 866 int rc;867 868 888 ext4_directory_dx_entry_t *entries; 869 if (dx_block == dx_blocks) { 870 entries = ((ext4_directory_dx_root_t *) dx_block->block->data)->entries; 871 } else { 872 entries = ((ext4_directory_dx_node_t *) dx_block->block->data)->entries; 873 } 874 889 if (dx_block == dx_blocks) 890 entries = 891 ((ext4_directory_dx_root_t *) dx_block->block->data)->entries; 892 else 893 entries = 894 ((ext4_directory_dx_node_t *) dx_block->block->data)->entries; 895 875 896 ext4_directory_dx_countlimit_t *countlimit = 876 (ext4_directory_dx_countlimit_t *)entries; 877 uint16_t leaf_limit = ext4_directory_dx_countlimit_get_limit(countlimit); 878 uint16_t leaf_count = ext4_directory_dx_countlimit_get_count(countlimit); 879 897 (ext4_directory_dx_countlimit_t *) entries; 898 899 uint16_t leaf_limit = 900 ext4_directory_dx_countlimit_get_limit(countlimit); 901 uint16_t leaf_count = 902 ext4_directory_dx_countlimit_get_count(countlimit); 903 880 904 /* Check if is necessary to split index block */ 881 905 if (leaf_limit == leaf_count) { 882 883 unsigned int levels = dx_block - dx_blocks; 884 906 size_t levels = dx_block - dx_blocks; 907 885 908 ext4_directory_dx_entry_t *root_entries = 886 ((ext4_directory_dx_root_t *)dx_blocks[0].block->data)->entries;887 909 ((ext4_directory_dx_root_t *) dx_blocks[0].block->data)->entries; 910 888 911 ext4_directory_dx_countlimit_t *root_countlimit = 889 (ext4_directory_dx_countlimit_t *)root_entries;912 (ext4_directory_dx_countlimit_t *) root_entries; 890 913 uint16_t root_limit = 891 ext4_directory_dx_countlimit_get_limit(root_countlimit);914 ext4_directory_dx_countlimit_get_limit(root_countlimit); 892 915 uint16_t root_count = 893 ext4_directory_dx_countlimit_get_count(root_countlimit);894 916 ext4_directory_dx_countlimit_get_count(root_countlimit); 917 895 918 /* Linux limitation */ 896 if ((levels > 0) && (root_limit == root_count)) {919 if ((levels > 0) && (root_limit == root_count)) 897 920 return ENOSPC; 898 } 899 921 900 922 /* Add new block to directory */ 901 923 uint32_t new_fblock; 902 924 uint32_t new_iblock; 903 rc = ext4_filesystem_append_inode_block(904 inode_ref,&new_fblock, &new_iblock);905 if (rc != EOK) {925 int rc = ext4_filesystem_append_inode_block(inode_ref, 926 &new_fblock, &new_iblock); 927 if (rc != EOK) 906 928 return rc; 907 } 908 929 909 930 /* load new block */ 910 block_t * new_block;931 block_t *new_block; 911 932 rc = block_get(&new_block, inode_ref->fs->device, 912 new_fblock, BLOCK_FLAGS_NOREAD);913 if (rc != EOK) {933 new_fblock, BLOCK_FLAGS_NOREAD); 934 if (rc != EOK) 914 935 return rc; 915 } 916 936 917 937 ext4_directory_dx_node_t *new_node = new_block->data; 918 938 ext4_directory_dx_entry_t *new_entries = new_node->entries; 919 920 uint32_t block_size = ext4_superblock_get_block_size(921 inode_ref->fs->superblock);922 939 940 uint32_t block_size = 941 ext4_superblock_get_block_size(inode_ref->fs->superblock); 942 923 943 /* Split leaf node */ 924 944 if (levels > 0) { 925 926 945 uint32_t count_left = leaf_count / 2; 927 946 uint32_t count_right = leaf_count - count_left; 928 947 uint32_t hash_right = 929 ext4_directory_dx_entry_get_hash(entries + count_left);930 948 ext4_directory_dx_entry_get_hash(entries + count_left); 949 931 950 /* Copy data to new node */ 932 951 memcpy((void *) new_entries, (void *) (entries + count_left), 933 count_right * sizeof(ext4_directory_dx_entry_t));934 952 count_right * sizeof(ext4_directory_dx_entry_t)); 953 935 954 /* Initialize new node */ 936 955 ext4_directory_dx_countlimit_t *left_countlimit = 937 (ext4_directory_dx_countlimit_t *)entries;956 (ext4_directory_dx_countlimit_t *) entries; 938 957 ext4_directory_dx_countlimit_t *right_countlimit = 939 (ext4_directory_dx_countlimit_t *)new_entries;940 958 (ext4_directory_dx_countlimit_t *) new_entries; 959 941 960 ext4_directory_dx_countlimit_set_count(left_countlimit, count_left); 942 961 ext4_directory_dx_countlimit_set_count(right_countlimit, count_right); 943 944 uint32_t entry_space = block_size - sizeof(ext4_fake_directory_entry_t); 945 uint32_t node_limit = entry_space / sizeof(ext4_directory_dx_entry_t); 962 963 uint32_t entry_space = 964 block_size - sizeof(ext4_fake_directory_entry_t); 965 uint32_t node_limit = 966 entry_space / sizeof(ext4_directory_dx_entry_t); 946 967 ext4_directory_dx_countlimit_set_limit(right_countlimit, node_limit); 947 968 948 969 /* Which index block is target for new entry */ 949 970 uint32_t position_index = (dx_block->position - dx_block->entries); 950 971 if (position_index >= count_left) { 951 952 972 dx_block->block->dirty = true; 953 973 954 974 block_t *block_tmp = dx_block->block; 955 975 dx_block->block = new_block; 956 dx_block->position = new_entries + position_index - count_left; 976 dx_block->position = 977 new_entries + position_index - count_left; 957 978 dx_block->entries = new_entries; 958 979 959 980 new_block = block_tmp; 960 961 981 } 962 982 963 983 /* Finally insert new entry */ 964 984 ext4_directory_dx_insert_entry(dx_blocks, hash_right, new_iblock); 965 985 966 986 return block_put(new_block); 967 968 987 } else { 969 970 988 /* Create second level index */ 971 989 972 990 /* Copy data from root to child block */ 973 991 memcpy((void *) new_entries, (void *) entries, 974 leaf_count * sizeof(ext4_directory_dx_entry_t));975 992 leaf_count * sizeof(ext4_directory_dx_entry_t)); 993 976 994 ext4_directory_dx_countlimit_t *new_countlimit = 977 (ext4_directory_dx_countlimit_t *)new_entries; 978 979 uint32_t entry_space = block_size - sizeof(ext4_fake_directory_entry_t); 980 uint32_t node_limit = entry_space / sizeof(ext4_directory_dx_entry_t); 995 (ext4_directory_dx_countlimit_t *) new_entries; 996 997 uint32_t entry_space = 998 block_size - sizeof(ext4_fake_directory_entry_t); 999 uint32_t node_limit = 1000 entry_space / sizeof(ext4_directory_dx_entry_t); 981 1001 ext4_directory_dx_countlimit_set_limit(new_countlimit, node_limit); 982 1002 983 1003 /* Set values in root node */ 984 1004 ext4_directory_dx_countlimit_t *new_root_countlimit = 985 (ext4_directory_dx_countlimit_t *)entries;986 1005 (ext4_directory_dx_countlimit_t *) entries; 1006 987 1007 ext4_directory_dx_countlimit_set_count(new_root_countlimit, 1); 988 1008 ext4_directory_dx_entry_set_block(entries, new_iblock); 989 990 ((ext4_directory_dx_root_t *)dx_blocks[0].block->data)->info.indirect_levels = 1; 991 1009 1010 ((ext4_directory_dx_root_t *) 1011 dx_blocks[0].block->data)->info.indirect_levels = 1; 1012 992 1013 /* Add new entry to the path */ 993 1014 dx_block = dx_blocks + 1; … … 996 1017 dx_block->block = new_block; 997 1018 } 998 999 } 1000 1019 } 1020 1001 1021 return EOK; 1002 1022 } … … 1004 1024 /** Add new entry to indexed directory 1005 1025 * 1006 * @param parent directory i-node 1007 * @param child i-node to be referenced from directory entry 1008 * @param name name of new directory entry 1009 * @return error code 1026 * @param parent Directory i-node 1027 * @param child I-node to be referenced from directory entry 1028 * @param name Name of new directory entry 1029 * 1030 * @return Error code 1031 * 1010 1032 */ 1011 1033 int ext4_directory_dx_add_entry(ext4_inode_ref_t *parent, 1012 ext4_inode_ref_t *child, const char *name) 1013 { 1014 int rc = EOK; 1034 ext4_inode_ref_t *child, const char *name) 1035 { 1015 1036 int rc2 = EOK; 1016 1017 /* get direct block 0 (index root) */1037 1038 /* Get direct block 0 (index root) */ 1018 1039 uint32_t root_block_addr; 1019 rc = ext4_filesystem_get_inode_data_block_index(parent, 0, &root_block_addr);1020 if (rc != EOK) {1021 return rc;1022 }1023 1040 int rc = ext4_filesystem_get_inode_data_block_index(parent, 0, 1041 &root_block_addr); 1042 if (rc != EOK) 1043 return rc; 1044 1024 1045 ext4_filesystem_t *fs = parent->fs; 1025 1046 1026 1047 block_t *root_block; 1027 rc = block_get(&root_block, fs->device, root_block_addr, BLOCK_FLAGS_NONE);1028 if (rc != EOK) {1029 return rc;1030 }1031 1048 rc = block_get(&root_block, fs->device, root_block_addr, 1049 BLOCK_FLAGS_NONE); 1050 if (rc != EOK) 1051 return rc; 1052 1032 1053 /* Initialize hinfo structure (mainly compute hash) */ 1033 uint32_t name_len = str len(name);1054 uint32_t name_len = str_size(name); 1034 1055 ext4_hash_info_t hinfo; 1035 rc = ext4_directory_hinfo_init(&hinfo, root_block, fs->superblock, name_len, name); 1056 rc = ext4_directory_hinfo_init(&hinfo, root_block, fs->superblock, 1057 name_len, name); 1036 1058 if (rc != EOK) { 1037 1059 block_put(root_block); 1038 1060 return EXT4_ERR_BAD_DX_DIR; 1039 1061 } 1040 1041 /* Hardcoded number 2 means maximum height of index tree defined in linux */ 1062 1063 /* 1064 * Hardcoded number 2 means maximum height of index 1065 * tree defined in Linux. 1066 */ 1042 1067 ext4_directory_dx_block_t dx_blocks[2]; 1043 ext4_directory_dx_block_t *dx_block, *dx_it; 1044 rc = ext4_directory_dx_get_leaf(&hinfo, parent, root_block, &dx_block, dx_blocks); 1068 ext4_directory_dx_block_t *dx_block; 1069 ext4_directory_dx_block_t *dx_it; 1070 1071 rc = ext4_directory_dx_get_leaf(&hinfo, parent, root_block, 1072 &dx_block, dx_blocks); 1045 1073 if (rc != EOK) { 1046 1074 rc = EXT4_ERR_BAD_DX_DIR; 1047 1075 goto release_index; 1048 1076 } 1049 1050 1077 1051 1078 /* Try to insert to existing data block */ 1052 uint32_t leaf_block_idx = ext4_directory_dx_entry_get_block(dx_block->position); 1079 uint32_t leaf_block_idx = 1080 ext4_directory_dx_entry_get_block(dx_block->position); 1053 1081 uint32_t leaf_block_addr; 1054 rc = ext4_filesystem_get_inode_data_block_index(parent, leaf_block_idx, &leaf_block_addr); 1055 if (rc != EOK) { 1056 goto release_index; 1057 } 1058 1059 1060 block_t *target_block; 1061 rc = block_get(&target_block, fs->device, leaf_block_addr,BLOCK_FLAGS_NONE);1062 if (rc != EOK) { 1063 goto release_index;1064 } 1065 1066 /* Check if insert operation passed */ 1067 rc = ext4_directory_try_insert_entry(fs->superblock, target_block, child,name, name_len);1068 if (rc == EOK) { 1069 goto release_target_index;1070 } 1071 1072 /* Check if there is needed to split index node1073 * (and recursively also parent nodes)1074 */1082 rc = ext4_filesystem_get_inode_data_block_index(parent, leaf_block_idx, 1083 &leaf_block_addr); 1084 if (rc != EOK) 1085 goto release_index; 1086 1087 block_t *target_block; 1088 rc = block_get(&target_block, fs->device, leaf_block_addr, 1089 BLOCK_FLAGS_NONE); 1090 if (rc != EOK) 1091 goto release_index; 1092 1093 /* Check if insert operation passed */ 1094 rc = ext4_directory_try_insert_entry(fs->superblock, target_block, child, 1095 name, name_len); 1096 if (rc == EOK) 1097 goto release_target_index; 1098 1099 /* 1100 * Check if there is needed to split index node 1101 * (and recursively also parent nodes) 1102 */ 1075 1103 rc = ext4_directory_dx_split_index(parent, dx_blocks, dx_block); 1076 if (rc != EOK) {1104 if (rc != EOK) 1077 1105 goto release_target_index; 1078 } 1079 1106 1080 1107 /* Split entries to two blocks (includes sorting by hash value) */ 1081 1108 block_t *new_block = NULL; 1082 rc = ext4_directory_dx_split_data(parent, &hinfo, target_block, dx_block, &new_block); 1109 rc = ext4_directory_dx_split_data(parent, &hinfo, target_block, 1110 dx_block, &new_block); 1083 1111 if (rc != EOK) { 1084 1112 rc2 = rc; 1085 1113 goto release_target_index; 1086 1114 } 1087 1115 1088 1116 /* Where to save new entry */ 1089 uint32_t new_block_hash = ext4_directory_dx_entry_get_hash(dx_block->position + 1); 1090 if (hinfo.hash >= new_block_hash) { 1091 rc = ext4_directory_try_insert_entry(fs->superblock, new_block, child, name, name_len); 1092 } else { 1093 rc = ext4_directory_try_insert_entry(fs->superblock, target_block, child, name, name_len); 1094 } 1095 1117 uint32_t new_block_hash = 1118 ext4_directory_dx_entry_get_hash(dx_block->position + 1); 1119 if (hinfo.hash >= new_block_hash) 1120 rc = ext4_directory_try_insert_entry(fs->superblock, new_block, 1121 child, name, name_len); 1122 else 1123 rc = ext4_directory_try_insert_entry(fs->superblock, target_block, 1124 child, name, name_len); 1125 1096 1126 /* Cleanup */ 1097 1127 rc = block_put(new_block); 1098 if (rc != EOK) { 1099 return rc; 1100 } 1101 1128 if (rc != EOK) 1129 return rc; 1130 1102 1131 /* Cleanup operations */ 1103 1132 1104 1133 release_target_index: 1105 1106 1134 rc2 = rc; 1107 1135 1108 1136 rc = block_put(target_block); 1109 if (rc != EOK) { 1110 return rc; 1111 } 1112 1137 if (rc != EOK) 1138 return rc; 1139 1113 1140 release_index: 1114 1115 if (rc != EOK) { 1141 if (rc != EOK) 1116 1142 rc2 = rc; 1117 } 1118 1143 1119 1144 dx_it = dx_blocks; 1120 1145 1121 1146 while (dx_it <= dx_block) { 1122 1147 rc = block_put(dx_it->block); 1123 if (rc != EOK) {1148 if (rc != EOK) 1124 1149 return rc; 1125 }1150 1126 1151 dx_it++; 1127 1152 } 1128 1153 1129 1154 return rc2; 1130 1155 } 1131 1132 1156 1133 1157 /** 1134 1158 * @} 1135 */ 1159 */ -
uspace/lib/ext4/libext4_directory_index.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_DIRECTORY_INDEX_H_ … … 37 37 38 38 extern uint8_t ext4_directory_dx_root_info_get_hash_version( 39 ext4_directory_dx_root_info_t *);39 ext4_directory_dx_root_info_t *); 40 40 extern void ext4_directory_dx_root_info_set_hash_version( 41 ext4_directory_dx_root_info_t *, uint8_t);41 ext4_directory_dx_root_info_t *, uint8_t); 42 42 extern uint8_t ext4_directory_dx_root_info_get_info_length( 43 ext4_directory_dx_root_info_t *);43 ext4_directory_dx_root_info_t *); 44 44 extern void ext4_directory_dx_root_info_set_info_length( 45 ext4_directory_dx_root_info_t *, uint8_t);45 ext4_directory_dx_root_info_t *, uint8_t); 46 46 extern uint8_t ext4_directory_dx_root_info_get_indirect_levels( 47 ext4_directory_dx_root_info_t *);47 ext4_directory_dx_root_info_t *); 48 48 extern void ext4_directory_dx_root_info_set_indirect_levels( 49 ext4_directory_dx_root_info_t *, uint8_t);49 ext4_directory_dx_root_info_t *, uint8_t); 50 50 51 51 extern uint16_t ext4_directory_dx_countlimit_get_limit( 52 ext4_directory_dx_countlimit_t *);52 ext4_directory_dx_countlimit_t *); 53 53 extern void ext4_directory_dx_countlimit_set_limit( 54 ext4_directory_dx_countlimit_t *, uint16_t);54 ext4_directory_dx_countlimit_t *, uint16_t); 55 55 extern uint16_t ext4_directory_dx_countlimit_get_count( 56 ext4_directory_dx_countlimit_t *);56 ext4_directory_dx_countlimit_t *); 57 57 extern void ext4_directory_dx_countlimit_set_count( 58 ext4_directory_dx_countlimit_t *, uint16_t);58 ext4_directory_dx_countlimit_t *, uint16_t); 59 59 60 60 extern uint32_t ext4_directory_dx_entry_get_hash(ext4_directory_dx_entry_t *); 61 61 extern void ext4_directory_dx_entry_set_hash(ext4_directory_dx_entry_t *, 62 uint32_t);62 uint32_t); 63 63 extern uint32_t ext4_directory_dx_entry_get_block(ext4_directory_dx_entry_t *); 64 void ext4_directory_dx_entry_set_block(ext4_directory_dx_entry_t *, uint32_t); 65 66 /*********************************************************************************/ 64 extern void ext4_directory_dx_entry_set_block(ext4_directory_dx_entry_t *, 65 uint32_t); 67 66 68 67 extern int ext4_directory_dx_init(ext4_inode_ref_t *); 69 68 extern int ext4_directory_dx_find_entry(ext4_directory_search_result_t *, 70 ext4_inode_ref_t *, size_t, const char *);71 extern int ext4_directory_dx_add_entry( 72 ext4_inode_ref_t *, ext4_inode_ref_t *,const char *);69 ext4_inode_ref_t *, size_t, const char *); 70 extern int ext4_directory_dx_add_entry(ext4_inode_ref_t *, ext4_inode_ref_t *, 71 const char *); 73 72 74 73 #endif -
uspace/lib/ext4/libext4_extent.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_extent.c35 * @brief Ext4 extent structures operations.33 * @file libext4_extent.c 34 * @brief Ext4 extent structures operations. 36 35 */ 37 36 … … 43 42 /** Get logical number of the block covered by extent. 44 43 * 45 * @param extent extent to load number from 46 * @return logical number of the first block covered by extent 44 * @param extent Extent to load number from 45 * 46 * @return Logical number of the first block covered by extent 47 * 47 48 */ 48 49 uint32_t ext4_extent_get_first_block(ext4_extent_t *extent) … … 53 54 /** Set logical number of the first block covered by extent. 54 55 * 55 * @param extent extent to set number to 56 * @param iblock logical number of the first block covered by extent 56 * @param extent Extent to set number to 57 * @param iblock Logical number of the first block covered by extent 58 * 57 59 */ 58 60 void ext4_extent_set_first_block(ext4_extent_t *extent, uint32_t iblock) … … 63 65 /** Get number of blocks covered by extent. 64 66 * 65 * @param extent extent to load count from 66 * @return number of blocks covered by extent 67 * @param extent Extent to load count from 68 * 69 * @return Number of blocks covered by extent 70 * 67 71 */ 68 72 uint16_t ext4_extent_get_block_count(ext4_extent_t *extent) … … 73 77 /** Set number of blocks covered by extent. 74 78 * 75 * @param extent extent to load count from 76 * @param count number of blocks covered by extent 79 * @param extent Extent to load count from 80 * @param count Number of blocks covered by extent 81 * 77 82 */ 78 83 void ext4_extent_set_block_count(ext4_extent_t *extent, uint16_t count) … … 83 88 /** Get physical number of the first block covered by extent. 84 89 * 85 * @param extent extent to load number 86 * @return physical number of the first block covered by extent 90 * @param extent Extent to load number 91 * 92 * @return Physical number of the first block covered by extent 93 * 87 94 */ 88 95 uint64_t ext4_extent_get_start(ext4_extent_t *extent) 89 96 { 90 97 return ((uint64_t)uint16_t_le2host(extent->start_hi)) << 32 | 91 ((uint64_t)uint32_t_le2host(extent->start_lo));98 ((uint64_t)uint32_t_le2host(extent->start_lo)); 92 99 } 93 100 94 101 /** Set physical number of the first block covered by extent. 95 102 * 96 * @param extent extent to load number 97 * @param fblock physical number of the first block covered by extent 103 * @param extent Extent to load number 104 * @param fblock Physical number of the first block covered by extent 105 * 98 106 */ 99 107 void ext4_extent_set_start(ext4_extent_t *extent, uint64_t fblock) … … 105 113 /** Get logical number of the block covered by extent index. 106 114 * 107 * @param index extent index to load number from 108 * @return logical number of the first block covered by extent index 115 * @param index Extent index to load number from 116 * 117 * @return Logical number of the first block covered by extent index 118 * 109 119 */ 110 120 uint32_t ext4_extent_index_get_first_block(ext4_extent_index_t *index) … … 115 125 /** Set logical number of the block covered by extent index. 116 126 * 117 * @param index extent index to set number to 118 * @param iblock logical number of the first block covered by extent index 127 * @param index Extent index to set number to 128 * @param iblock Logical number of the first block covered by extent index 129 * 119 130 */ 120 131 void ext4_extent_index_set_first_block(ext4_extent_index_t *index, 121 uint32_t iblock)132 uint32_t iblock) 122 133 { 123 134 index->first_block = host2uint32_t_le(iblock); … … 126 137 /** Get physical number of block where the child node is located. 127 138 * 128 * @param index extent index to load number from 129 * @return physical number of the block with child node 139 * @param index Extent index to load number from 140 * 141 * @return Physical number of the block with child node 142 * 130 143 */ 131 144 uint64_t ext4_extent_index_get_leaf(ext4_extent_index_t *index) 132 145 { 133 return ((uint64_t) uint16_t_le2host(index->leaf_hi)) << 32 |134 ((uint64_t)uint32_t_le2host(index->leaf_lo));146 return ((uint64_t) uint16_t_le2host(index->leaf_hi)) << 32 | 147 ((uint64_t)uint32_t_le2host(index->leaf_lo)); 135 148 } 136 149 137 150 /** Set physical number of block where the child node is located. 138 151 * 139 * @param index extent index to set number to 140 * @param fblock physical number of the block with child node 152 * @param index Extent index to set number to 153 * @param fblock Ohysical number of the block with child node 154 * 141 155 */ 142 156 void ext4_extent_index_set_leaf(ext4_extent_index_t *index, uint64_t fblock) 143 157 { 144 158 index->leaf_lo = host2uint32_t_le((fblock << 32) >> 32); 145 index->leaf_hi = host2uint16_t_le((uint16_t) (fblock >> 32));159 index->leaf_hi = host2uint16_t_le((uint16_t) (fblock >> 32)); 146 160 } 147 161 148 162 /** Get magic value from extent header. 149 163 * 150 * @param header extent header to load value from 151 * @return magic value of extent header 164 * @param header Extent header to load value from 165 * 166 * @return Magic value of extent header 167 * 152 168 */ 153 169 uint16_t ext4_extent_header_get_magic(ext4_extent_header_t *header) … … 158 174 /** Set magic value to extent header. 159 175 * 160 * @param header extent header to set value to 161 * @param magic magic value of extent header 176 * @param header Extent header to set value to 177 * @param magic Magic value of extent header 178 * 162 179 */ 163 180 void ext4_extent_header_set_magic(ext4_extent_header_t *header, uint16_t magic) … … 168 185 /** Get number of entries from extent header 169 186 * 170 * @param header extent header to get value from 171 * @return number of entries covered by extent header 187 * @param header Extent header to get value from 188 * 189 * @return Number of entries covered by extent header 190 * 172 191 */ 173 192 uint16_t ext4_extent_header_get_entries_count(ext4_extent_header_t *header) … … 178 197 /** Set number of entries to extent header 179 198 * 180 * @param header extent header to set value to 181 * @param count number of entries covered by extent header 199 * @param header Extent header to set value to 200 * @param count Number of entries covered by extent header 201 * 182 202 */ 183 203 void ext4_extent_header_set_entries_count(ext4_extent_header_t *header, 184 uint16_t count)204 uint16_t count) 185 205 { 186 206 header->entries_count = host2uint16_t_le(count); … … 189 209 /** Get maximum number of entries from extent header 190 210 * 191 * @param header extent header to get value from 192 * @return maximum number of entries covered by extent header 211 * @param header Extent header to get value from 212 * 213 * @return Maximum number of entries covered by extent header 214 * 193 215 */ 194 216 uint16_t ext4_extent_header_get_max_entries_count(ext4_extent_header_t *header) … … 199 221 /** Set maximum number of entries to extent header 200 222 * 201 * @param header extent header to set value to 202 * @param max_count maximum number of entries covered by extent header 223 * @param header Extent header to set value to 224 * @param max_count Maximum number of entries covered by extent header 225 * 203 226 */ 204 227 void ext4_extent_header_set_max_entries_count(ext4_extent_header_t *header, 205 uint16_t max_count)228 uint16_t max_count) 206 229 { 207 230 header->max_entries_count = host2uint16_t_le(max_count); … … 210 233 /** Get depth of extent subtree. 211 234 * 212 * @param header extent header to get value from 213 * @return depth of extent subtree 235 * @param header Extent header to get value from 236 * 237 * @return Depth of extent subtree 238 * 214 239 */ 215 240 uint16_t ext4_extent_header_get_depth(ext4_extent_header_t *header) … … 220 245 /** Set depth of extent subtree. 221 246 * 222 * @param header extent header to set value to 223 * @param depth depth of extent subtree 247 * @param header Extent header to set value to 248 * @param depth Depth of extent subtree 249 * 224 250 */ 225 251 void ext4_extent_header_set_depth(ext4_extent_header_t *header, uint16_t depth) … … 230 256 /** Get generation from extent header 231 257 * 232 * @param header extent header to get value from 233 * @return generation 258 * @param header Extent header to get value from 259 * 260 * @return Generation 261 * 234 262 */ 235 263 uint32_t ext4_extent_header_get_generation(ext4_extent_header_t *header) … … 240 268 /** Set generation to extent header 241 269 * 242 * @param header extent header to set value to 243 * @param generation generation 270 * @param header Extent header to set value to 271 * @param generation Generation 272 * 244 273 */ 245 274 void ext4_extent_header_set_generation(ext4_extent_header_t *header, 246 uint32_t generation)275 uint32_t generation) 247 276 { 248 277 header->generation = host2uint32_t_le(generation); … … 251 280 /** Binary search in extent index node. 252 281 * 253 * @param header extent header of index node 254 * @param index output value - found index will be set here 255 * @param iblock logical block number to find in index node 282 * @param header Extent header of index node 283 * @param index Output value - found index will be set here 284 * @param iblock Logical block number to find in index node 285 * 256 286 */ 257 287 static void ext4_extent_binsearch_idx(ext4_extent_header_t *header, 258 ext4_extent_index_t **index, uint32_t iblock) 259 { 260 ext4_extent_index_t *r, *l, *m; 261 262 uint16_t entries_count = ext4_extent_header_get_entries_count(header); 263 288 ext4_extent_index_t **index, uint32_t iblock) 289 { 290 ext4_extent_index_t *r; 291 ext4_extent_index_t *l; 292 ext4_extent_index_t *m; 293 294 uint16_t entries_count = 295 ext4_extent_header_get_entries_count(header); 296 264 297 /* Initialize bounds */ 265 298 l = EXT4_EXTENT_FIRST_INDEX(header) + 1; 266 299 r = EXT4_EXTENT_FIRST_INDEX(header) + entries_count - 1; 267 300 268 301 /* Do binary search */ 269 302 while (l <= r) { 270 303 m = l + (r - l) / 2; 271 304 uint32_t first_block = ext4_extent_index_get_first_block(m); 272 if (iblock < first_block) {273 r = m - 1;274 } else {275 l = m + 1;276 }277 } 278 305 306 if (iblock < first_block) 307 r = m - 1; 308 else 309 l = m + 1; 310 } 311 279 312 /* Set output value */ 280 313 *index = l - 1; … … 282 315 283 316 /** Binary search in extent leaf node. 284 * @param header extent header of leaf node 285 * @param extent output value - found extent will be set here, 286 * or NULL if node is empty 287 * @param iblock logical block number to find in leaf node 317 * 318 * @param header Extent header of leaf node 319 * @param extent Output value - found extent will be set here, 320 * or NULL if node is empty 321 * @param iblock Logical block number to find in leaf node 288 322 * 289 323 */ 290 324 static void ext4_extent_binsearch(ext4_extent_header_t *header, 291 ext4_extent_t **extent, uint32_t iblock) 292 { 293 ext4_extent_t *r, *l, *m; 294 295 uint16_t entries_count = ext4_extent_header_get_entries_count(header); 296 325 ext4_extent_t **extent, uint32_t iblock) 326 { 327 ext4_extent_t *r; 328 ext4_extent_t *l; 329 ext4_extent_t *m; 330 331 uint16_t entries_count = 332 ext4_extent_header_get_entries_count(header); 333 297 334 if (entries_count == 0) { 298 335 /* this leaf is empty */ … … 300 337 return; 301 338 } 302 339 303 340 /* Initialize bounds */ 304 341 l = EXT4_EXTENT_FIRST(header) + 1; 305 342 r = EXT4_EXTENT_FIRST(header) + entries_count - 1; 306 343 307 344 /* Do binary search */ 308 345 while (l <= r) { 309 346 m = l + (r - l) / 2; 310 347 uint32_t first_block = ext4_extent_get_first_block(m); 311 if (iblock < first_block) {312 r = m - 1;313 } else {314 l = m + 1;315 }316 } 317 348 349 if (iblock < first_block) 350 r = m - 1; 351 else 352 l = m + 1; 353 } 354 318 355 /* Set output value */ 319 356 *extent = l - 1; … … 324 361 * There is no need to save path in the tree during this algorithm. 325 362 * 326 * @param inode_ref i-node to load block from327 * @param iblock logical block number to find328 * @param fblock output value for physical block number329 * @return error code330 * /331 int ext4_extent_find_block(ext4_inode_ref_t *inode_ref, 332 uint32_t iblock, uint32_t *fblock) 333 { 334 int rc; 335 363 * @param inode_ref I-node to load block from 364 * @param iblock Logical block number to find 365 * @param fblock Output value for physical block number 366 * 367 * @return Error code 368 * 369 */ 370 int ext4_extent_find_block(ext4_inode_ref_t *inode_ref, uint32_t iblock, 371 uint32_t *fblock) 372 { 336 373 /* Compute bound defined by i-node size */ 337 uint64_t inode_size = ext4_inode_get_size(338 inode_ref->fs->superblock, inode_ref->inode);339 340 uint32_t block_size = ext4_superblock_get_block_size(341 inode_ref->fs->superblock);342 374 uint64_t inode_size = 375 ext4_inode_get_size(inode_ref->fs->superblock, inode_ref->inode); 376 377 uint32_t block_size = 378 ext4_superblock_get_block_size(inode_ref->fs->superblock); 379 343 380 uint32_t last_idx = (inode_size - 1) / block_size; 344 381 345 382 /* Check if requested iblock is not over size of i-node */ 346 383 if (iblock > last_idx) { … … 348 385 return EOK; 349 386 } 350 351 block_t *block = NULL;352 387 388 block_t *block = NULL; 389 353 390 /* Walk through extent tree */ 354 ext4_extent_header_t *header = ext4_inode_get_extent_header(inode_ref->inode); 355 391 ext4_extent_header_t *header = 392 ext4_inode_get_extent_header(inode_ref->inode); 393 356 394 while (ext4_extent_header_get_depth(header) != 0) { 357 358 395 /* Search index in node */ 359 396 ext4_extent_index_t *index; 360 397 ext4_extent_binsearch_idx(header, &index, iblock); 361 398 362 399 /* Load child node and set values for the next iteration */ 363 400 uint64_t child = ext4_extent_index_get_leaf(index); 364 365 if (block != NULL) {401 402 if (block != NULL) 366 403 block_put(block); 367 }368 369 rc = block_get(&block, inode_ref->fs->device, child,BLOCK_FLAGS_NONE);370 if (rc != EOK) {404 405 int rc = block_get(&block, inode_ref->fs->device, child, 406 BLOCK_FLAGS_NONE); 407 if (rc != EOK) 371 408 return rc; 372 } 373 409 374 410 header = (ext4_extent_header_t *)block->data; 375 411 } 376 412 377 413 /* Search extent in the leaf block */ 378 414 ext4_extent_t* extent = NULL; 379 415 ext4_extent_binsearch(header, &extent, iblock); 380 416 381 417 /* Prevent empty leaf */ 382 418 if (extent == NULL) { 383 419 *fblock = 0; 384 420 } else { 385 386 421 /* Compute requested physical block address */ 387 422 uint32_t phys_block; 388 423 uint32_t first = ext4_extent_get_first_block(extent); 389 424 phys_block = ext4_extent_get_start(extent) + iblock - first; 390 425 391 426 *fblock = phys_block; 392 427 } 393 428 394 429 /* Cleanup */ 395 if (block != NULL) {430 if (block != NULL) 396 431 block_put(block); 397 } 398 432 399 433 return EOK; 400 434 } 401 402 435 403 436 /** Find extent for specified iblock. … … 406 439 * saving the path through the tree for possible future modifications. 407 440 * 408 * @param inode_ref i-node to read extent tree from409 * @param iblock iblock to find extent for410 * @param ret_path output value for loaded path from extent tree411 * @return error code412 * /413 static int ext4_extent_find_extent(ext4_inode_ref_t *inode_ref, 414 uint32_t iblock, ext4_extent_path_t **ret_path) 415 { 416 int rc; 417 441 * @param inode_ref I-node to read extent tree from 442 * @param iblock Iblock to find extent for 443 * @param ret_path Output value for loaded path from extent tree 444 * 445 * @return Error code 446 * 447 */ 448 static int ext4_extent_find_extent(ext4_inode_ref_t *inode_ref, uint32_t iblock, 449 ext4_extent_path_t **ret_path) 450 { 418 451 ext4_extent_header_t *eh = 419 ext4_inode_get_extent_header(inode_ref->inode);420 452 ext4_inode_get_extent_header(inode_ref->inode); 453 421 454 uint16_t depth = ext4_extent_header_get_depth(eh); 422 455 423 456 ext4_extent_path_t *tmp_path; 424 457 425 458 /* Added 2 for possible tree growing */ 426 459 tmp_path = malloc(sizeof(ext4_extent_path_t) * (depth + 2)); 427 if (tmp_path == NULL) {460 if (tmp_path == NULL) 428 461 return ENOMEM; 429 } 430 462 431 463 /* Initialize structure for algorithm start */ 432 464 tmp_path[0].block = inode_ref->block; 433 465 tmp_path[0].header = eh; 434 466 435 467 /* Walk through the extent tree */ 436 468 uint16_t pos = 0; 469 int rc; 437 470 while (ext4_extent_header_get_depth(eh) != 0) { 438 439 471 /* Search index in index node by iblock */ 440 ext4_extent_binsearch_idx(tmp_path[pos].header, &tmp_path[pos].index, iblock); 441 472 ext4_extent_binsearch_idx(tmp_path[pos].header, 473 &tmp_path[pos].index, iblock); 474 442 475 tmp_path[pos].depth = depth; 443 476 tmp_path[pos].extent = NULL; 444 477 445 478 assert(tmp_path[pos].index != NULL); 446 479 447 480 /* Load information for the next iteration */ 448 481 uint64_t fblock = ext4_extent_index_get_leaf(tmp_path[pos].index); 449 482 450 483 block_t *block; 451 rc = block_get(&block, inode_ref->fs->device, fblock, BLOCK_FLAGS_NONE); 452 if (rc != EOK) { 484 rc = block_get(&block, inode_ref->fs->device, fblock, 485 BLOCK_FLAGS_NONE); 486 if (rc != EOK) 453 487 goto cleanup; 454 } 455 488 456 489 pos++; 457 490 458 491 eh = (ext4_extent_header_t *)block->data; 459 492 tmp_path[pos].block = block; 460 493 tmp_path[pos].header = eh; 461 462 } 463 494 } 495 464 496 tmp_path[pos].depth = 0; 465 497 tmp_path[pos].extent = NULL; 466 498 tmp_path[pos].index = NULL; 467 468 /* Find extent in the leaf node */499 500 /* Find extent in the leaf node */ 469 501 ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent, iblock); 470 471 502 *ret_path = tmp_path; 472 503 473 504 return EOK; 474 505 475 506 cleanup: 476 /* Put loaded blocks 507 /* 508 * Put loaded blocks 477 509 * From 1: 0 is a block with inode data 478 510 */ 479 511 for (uint16_t i = 1; i < tmp_path->depth; ++i) { 480 if (tmp_path[i].block) {512 if (tmp_path[i].block) 481 513 block_put(tmp_path[i].block); 482 } 483 } 484 514 } 515 485 516 /* Destroy temporary data structure */ 486 517 free(tmp_path); 487 518 488 519 return rc; 489 520 } … … 491 522 /** Release extent and all data blocks covered by the extent. 492 523 * 493 * @param inode_ref i-node to release extent and block from494 * @param extent extent to release495 * @return error code496 * /497 static int ext4_extent_release( 498 ext4_inode_ref_t *inode_ref, ext4_extent_t *extent) 499 { 500 int rc; 501 524 * @param inode_ref I-node to release extent and block from 525 * @param extent Extent to release 526 * 527 * @return Error code 528 * 529 */ 530 static int ext4_extent_release(ext4_inode_ref_t *inode_ref, 531 ext4_extent_t *extent) 532 { 502 533 /* Compute number of the first physical block to release */ 503 534 uint64_t start = ext4_extent_get_start(extent); 504 535 uint16_t block_count = ext4_extent_get_block_count(extent); 505 506 rc = ext4_balloc_free_blocks(inode_ref, start, block_count); 507 if (rc != EOK) { 508 return rc; 509 } 510 511 return EOK; 536 537 return ext4_balloc_free_blocks(inode_ref, start, block_count); 512 538 } 513 539 … … 517 543 * the node. In the leaf node all extents will be released. 518 544 * 519 * @param inode_ref i-node where the branch is released 520 * @param index index in the non-leaf node to be released 521 * with the whole subtree 522 * @return error code 545 * @param inode_ref I-node where the branch is released 546 * @param index Index in the non-leaf node to be released 547 * with the whole subtree 548 * 549 * @return Error code 550 * 523 551 */ 524 552 static int ext4_extent_release_branch(ext4_inode_ref_t *inode_ref, 525 553 ext4_extent_index_t *index) 526 554 { 527 int rc;528 555 uint32_t fblock = ext4_extent_index_get_leaf(index); 556 529 557 block_t* block; 530 531 uint32_t fblock = ext4_extent_index_get_leaf(index); 532 533 rc = block_get(&block, inode_ref->fs->device, fblock, BLOCK_FLAGS_NONE); 534 if (rc != EOK) { 558 int rc = block_get(&block, inode_ref->fs->device, fblock, BLOCK_FLAGS_NONE); 559 if (rc != EOK) 535 560 return rc; 536 } 537 561 538 562 ext4_extent_header_t *header = block->data; 539 563 540 564 if (ext4_extent_header_get_depth(header)) { 541 542 565 /* The node is non-leaf, do recursion */ 543 544 566 ext4_extent_index_t *idx = EXT4_EXTENT_FIRST_INDEX(header); 545 567 546 568 /* Release all subbranches */ 547 for (uint32_t i = 0; i < ext4_extent_header_get_entries_count(header); ++i, ++idx) { 569 for (uint32_t i = 0; 570 i < ext4_extent_header_get_entries_count(header); 571 ++i, ++idx) { 548 572 rc = ext4_extent_release_branch(inode_ref, idx); 549 if (rc != EOK) {573 if (rc != EOK) 550 574 return rc; 551 }552 575 } 553 576 } else { 554 555 577 /* Leaf node reached */ 556 578 ext4_extent_t *ext = EXT4_EXTENT_FIRST(header); 557 579 558 580 /* Release all extents and stop recursion */ 559 560 for (uint32_t i = 0; i < ext4_extent_header_get_entries_count(header); ++i, ++ext) { 581 for (uint32_t i = 0; 582 i < ext4_extent_header_get_entries_count(header); 583 ++i, ++ext) { 561 584 rc = ext4_extent_release(inode_ref, ext); 562 if (rc != EOK) {585 if (rc != EOK) 563 586 return rc; 564 }565 587 } 566 588 } 567 589 568 590 /* Release data block where the node was stored */ 569 591 570 592 rc = block_put(block); 571 if (rc != EOK) {593 if (rc != EOK) 572 594 return rc; 573 } 574 595 575 596 ext4_balloc_free_block(inode_ref, fblock); 576 597 577 598 return EOK; 578 599 } … … 580 601 /** Release all data blocks starting from specified logical block. 581 602 * 582 * @param inode_ref i-node to release blocks from 583 * @param iblock_from first logical block to release 603 * @param inode_ref I-node to release blocks from 604 * @param iblock_from First logical block to release 605 * 584 606 */ 585 607 int ext4_extent_release_blocks_from(ext4_inode_ref_t *inode_ref, 586 uint32_t iblock_from) 587 { 588 int rc = EOK; 589 608 uint32_t iblock_from) 609 { 590 610 /* Find the first extent to modify */ 591 611 ext4_extent_path_t *path; 592 rc = ext4_extent_find_extent(inode_ref, iblock_from, &path);593 if (rc != EOK) {612 int rc = ext4_extent_find_extent(inode_ref, iblock_from, &path); 613 if (rc != EOK) 594 614 return rc; 595 } 596 615 597 616 /* Jump to last item of the path (extent) */ 598 617 ext4_extent_path_t *path_ptr = path; 599 while (path_ptr->depth != 0) {618 while (path_ptr->depth != 0) 600 619 path_ptr++; 601 } 602 620 603 621 assert(path_ptr->extent != NULL); 604 622 605 623 /* First extent maybe released partially */ 606 uint32_t first_iblock = ext4_extent_get_first_block(path_ptr->extent); 607 uint32_t first_fblock = ext4_extent_get_start(path_ptr->extent) + iblock_from - first_iblock; 608 609 624 uint32_t first_iblock = 625 ext4_extent_get_first_block(path_ptr->extent); 626 uint32_t first_fblock = 627 ext4_extent_get_start(path_ptr->extent) + iblock_from - first_iblock; 628 610 629 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent); 611 612 uint16_t delete_count = block_count - (613 ext4_extent_get_start(path_ptr->extent) - first_fblock);614 630 631 uint16_t delete_count = block_count - 632 (ext4_extent_get_start(path_ptr->extent) - first_fblock); 633 615 634 /* Release all blocks */ 616 635 rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count); 617 if (rc != EOK) {636 if (rc != EOK) 618 637 goto cleanup; 619 } 620 638 621 639 /* Correct counter */ 622 640 block_count -= delete_count; 623 641 ext4_extent_set_block_count(path_ptr->extent, block_count); 624 642 625 643 /* Initialize the following loop */ 626 uint16_t entries = ext4_extent_header_get_entries_count(path_ptr->header); 644 uint16_t entries = 645 ext4_extent_header_get_entries_count(path_ptr->header); 627 646 ext4_extent_t *tmp_ext = path_ptr->extent + 1; 628 647 ext4_extent_t *stop_ext = EXT4_EXTENT_FIRST(path_ptr->header) + entries; 629 648 630 649 /* If first extent empty, release it */ 631 if (block_count == 0) {650 if (block_count == 0) 632 651 entries--; 633 } 634 652 635 653 /* Release all successors of the first extent in the same node */ 636 654 while (tmp_ext < stop_ext) { 637 655 first_fblock = ext4_extent_get_start(tmp_ext); 638 656 delete_count = ext4_extent_get_block_count(tmp_ext); 639 657 640 658 rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count); 641 if (rc != EOK) {659 if (rc != EOK) 642 660 goto cleanup; 643 } 644 661 645 662 entries--; 646 663 tmp_ext++; 647 664 } 648 665 649 666 ext4_extent_header_set_entries_count(path_ptr->header, entries); 650 667 path_ptr->block->dirty = true; 651 668 652 669 /* If leaf node is empty, parent entry must be modified */ 653 670 bool remove_parent_record = false; 654 671 655 672 /* Don't release root block (including inode data) !!! */ 656 673 if ((path_ptr != path) && (entries == 0)) { 657 674 rc = ext4_balloc_free_block(inode_ref, path_ptr->block->lba); 658 if (rc != EOK) {675 if (rc != EOK) 659 676 goto cleanup; 660 }677 661 678 remove_parent_record = true; 662 679 } 663 680 664 681 /* Jump to the parent */ 665 682 --path_ptr; 666 683 667 684 /* Release all successors in all tree levels */ 668 685 while (path_ptr >= path) { … … 670 687 ext4_extent_index_t *index = path_ptr->index + 1; 671 688 ext4_extent_index_t *stop = 672 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;673 689 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries; 690 674 691 /* Correct entries count because of changes in the previous iteration */ 675 if (remove_parent_record) {692 if (remove_parent_record) 676 693 entries--; 677 } 678 694 679 695 /* Iterate over all entries and release the whole subtrees */ 680 696 while (index < stop) { 681 697 rc = ext4_extent_release_branch(inode_ref, index); 682 if (rc != EOK) {698 if (rc != EOK) 683 699 goto cleanup; 684 }700 685 701 ++index; 686 702 --entries; 687 703 } 688 704 689 705 ext4_extent_header_set_entries_count(path_ptr->header, entries); 690 706 path_ptr->block->dirty = true; 691 707 692 708 /* Free the node if it is empty */ 693 709 if ((entries == 0) && (path_ptr != path)) { 694 710 rc = ext4_balloc_free_block(inode_ref, path_ptr->block->lba); 695 if (rc != EOK) {711 if (rc != EOK) 696 712 goto cleanup; 697 } 698 713 699 714 /* Mark parent to be checked */ 700 715 remove_parent_record = true; 701 } else {716 } else 702 717 remove_parent_record = false; 703 } 704 718 705 719 --path_ptr; 706 720 } 707 708 721 709 722 cleanup: 710 /* Put loaded blocks 723 /* 724 * Put loaded blocks 711 725 * starting from 1: 0 is a block with inode data 712 726 */ 713 727 for (uint16_t i = 1; i <= path->depth; ++i) { 714 if (path[i].block) {728 if (path[i].block) 715 729 block_put(path[i].block); 716 } 717 } 718 730 } 731 719 732 /* Destroy temporary data structure */ 720 733 free(path); 721 734 722 735 return rc; 723 736 } 724 737 725 726 738 /** Append new extent to the i-node and do some splitting if necessary. 727 739 * 728 * @param inode_ref i-node to append extent to 729 * @param path path in the extent tree for possible splitting 730 * @param last_path_item input/output parameter for pointer to the last 731 * valid item in the extent tree path 732 * @param iblock logical index of block to append extent for 733 * @return error code 740 * @param inode_ref I-node to append extent to 741 * @param path Path in the extent tree for possible splitting 742 * @param last_path_item Input/output parameter for pointer to the last 743 * valid item in the extent tree path 744 * @param iblock Logical index of block to append extent for 745 * 746 * @return Error code 747 * 734 748 */ 735 749 static int ext4_extent_append_extent(ext4_inode_ref_t *inode_ref, 736 ext4_extent_path_t *path, uint32_t iblock) 737 { 738 int rc; 739 750 ext4_extent_path_t *path, uint32_t iblock) 751 { 740 752 ext4_extent_path_t *path_ptr = path + path->depth; 741 753 742 754 uint32_t block_size = 743 ext4_superblock_get_block_size(inode_ref->fs->superblock);744 755 ext4_superblock_get_block_size(inode_ref->fs->superblock); 756 745 757 /* Start splitting */ 746 758 while (path_ptr > path) { 747 748 uint16_t entries = ext4_extent_header_get_entries_count(path_ptr->header); 749 uint16_t limit = ext4_extent_header_get_max_entries_count(path_ptr->header); 750 759 uint16_t entries = 760 ext4_extent_header_get_entries_count(path_ptr->header); 761 uint16_t limit = 762 ext4_extent_header_get_max_entries_count(path_ptr->header); 763 751 764 if (entries == limit) { 752 753 765 /* Full node - allocate block for new one */ 754 766 uint32_t fblock; 755 rc = ext4_balloc_alloc_block(inode_ref, &fblock);756 if (rc != EOK) {767 int rc = ext4_balloc_alloc_block(inode_ref, &fblock); 768 if (rc != EOK) 757 769 return rc; 758 } 759 770 760 771 block_t *block; 761 rc = block_get(&block, inode_ref->fs->device, fblock, BLOCK_FLAGS_NOREAD); 772 rc = block_get(&block, inode_ref->fs->device, fblock, 773 BLOCK_FLAGS_NOREAD); 762 774 if (rc != EOK) { 763 775 ext4_balloc_free_block(inode_ref, fblock); 764 776 return rc; 765 777 } 766 778 767 779 /* Put back not modified old block */ 768 780 block_put(path_ptr->block); 769 781 770 782 /* Initialize newly allocated block and remember it */ 771 783 memset(block->data, 0, block_size); 772 784 path_ptr->block = block; 773 785 774 786 /* Update pointers in extent path structure */ 775 787 path_ptr->header = block->data; … … 779 791 ext4_extent_index_set_leaf(path_ptr->index, (path_ptr + 1)->block->lba); 780 792 limit = (block_size - sizeof(ext4_extent_header_t)) / 781 sizeof(ext4_extent_index_t);793 sizeof(ext4_extent_index_t); 782 794 } else { 783 795 path_ptr->extent = EXT4_EXTENT_FIRST(path_ptr->header); 784 796 ext4_extent_set_first_block(path_ptr->extent, iblock); 785 797 limit = (block_size - sizeof(ext4_extent_header_t)) / 786 sizeof(ext4_extent_t);798 sizeof(ext4_extent_t); 787 799 } 788 800 789 801 /* Initialize on-disk structure (header) */ 790 802 ext4_extent_header_set_entries_count(path_ptr->header, 1); … … 793 805 ext4_extent_header_set_depth(path_ptr->header, path_ptr->depth); 794 806 ext4_extent_header_set_generation(path_ptr->header, 0); 795 807 796 808 path_ptr->block->dirty = true; 797 809 798 810 /* Jump to the preceeding item */ 799 811 path_ptr--; 800 801 812 } else { 802 803 813 /* Node with free space */ 804 814 if (path_ptr->depth) { … … 810 820 ext4_extent_set_first_block(path_ptr->extent, iblock); 811 821 } 812 822 813 823 ext4_extent_header_set_entries_count(path_ptr->header, entries + 1); 814 824 path_ptr->block->dirty = true; 815 825 816 826 /* No more splitting needed */ 817 827 return EOK; 818 828 } 819 820 } 821 829 } 830 822 831 assert(path_ptr == path); 823 832 824 833 /* Should be the root split too? */ 825 834 826 835 uint16_t entries = ext4_extent_header_get_entries_count(path->header); 827 836 uint16_t limit = ext4_extent_header_get_max_entries_count(path->header); 828 837 829 838 if (entries == limit) { 830 831 839 uint32_t new_fblock; 832 rc = ext4_balloc_alloc_block(inode_ref, &new_fblock);833 if (rc != EOK) {840 int rc = ext4_balloc_alloc_block(inode_ref, &new_fblock); 841 if (rc != EOK) 834 842 return rc; 835 } 836 843 837 844 block_t *block; 838 rc = block_get(&block, inode_ref->fs->device, 839 new_fblock,BLOCK_FLAGS_NOREAD);840 if (rc != EOK) {845 rc = block_get(&block, inode_ref->fs->device, new_fblock, 846 BLOCK_FLAGS_NOREAD); 847 if (rc != EOK) 841 848 return rc; 842 } 843 849 844 850 /* Initialize newly allocated block */ 845 851 memset(block->data, 0, block_size); 846 852 847 853 /* Move data from root to the new block */ 848 854 memcpy(block->data, inode_ref->inode->blocks, 849 EXT4_INODE_BLOCKS * sizeof(uint32_t));850 851 / / Data block initialized !!!852 855 EXT4_INODE_BLOCKS * sizeof(uint32_t)); 856 857 /* Data block is initialized */ 858 853 859 block_t *root_block = path->block; 854 860 uint16_t root_depth = path->depth; 855 861 ext4_extent_header_t *root_header = path->header; 856 862 857 863 /* Make space for tree growing */ 858 864 ext4_extent_path_t *new_root = path; 859 865 ext4_extent_path_t *old_root = path + 1; 860 866 861 867 size_t nbytes = sizeof(ext4_extent_path_t) * (path->depth + 1); 862 868 memmove(old_root, new_root, nbytes); 863 869 memset(new_root, 0, sizeof(ext4_extent_path_t)); 864 870 865 871 /* Update old root structure */ 866 872 old_root->block = block; 867 873 old_root->header = (ext4_extent_header_t *)block->data; 868 874 869 875 /* Add new entry and update limit for entries */ 870 876 if (old_root->depth) { 871 877 limit = (block_size - sizeof(ext4_extent_header_t)) / 872 sizeof(ext4_extent_index_t);878 sizeof(ext4_extent_index_t); 873 879 old_root->index = EXT4_EXTENT_FIRST_INDEX(old_root->header) + entries; 874 880 ext4_extent_index_set_first_block(old_root->index, iblock); … … 877 883 } else { 878 884 limit = (block_size - sizeof(ext4_extent_header_t)) / 879 sizeof(ext4_extent_t);885 sizeof(ext4_extent_t); 880 886 old_root->extent = EXT4_EXTENT_FIRST(old_root->header) + entries; 881 887 ext4_extent_set_first_block(old_root->extent, iblock); 882 888 old_root->index = NULL; 883 889 } 890 884 891 ext4_extent_header_set_entries_count(old_root->header, entries + 1); 885 892 ext4_extent_header_set_max_entries_count(old_root->header, limit); 886 893 887 894 old_root->block->dirty = true; 888 895 889 896 /* Re-initialize new root metadata */ 890 897 new_root->depth = root_depth + 1; … … 893 900 new_root->extent = NULL; 894 901 new_root->index = EXT4_EXTENT_FIRST_INDEX(new_root->header); 895 902 896 903 ext4_extent_header_set_depth(new_root->header, new_root->depth); 897 904 898 905 /* Create new entry in root */ 899 906 ext4_extent_header_set_entries_count(new_root->header, 1); 900 907 ext4_extent_index_set_first_block(new_root->index, 0); 901 908 ext4_extent_index_set_leaf(new_root->index, new_fblock); 902 909 903 910 new_root->block->dirty = true; 904 905 911 } else { 906 907 912 if (path->depth) { 908 913 path->index = EXT4_EXTENT_FIRST_INDEX(path->header) + entries; … … 913 918 ext4_extent_set_first_block(path->extent, iblock); 914 919 } 915 920 916 921 ext4_extent_header_set_entries_count(path->header, entries + 1); 917 922 path->block->dirty = true; 918 923 } 919 924 920 925 return EOK; 921 926 } … … 927 932 * It includes possible extent tree modifications (splitting). 928 933 *< 929 * @param inode_ref i-node to append block to930 * @param iblock output logical number of newly allocated block931 * @param fblock output physical block address of newly allocated block932 * @return error code933 * /934 int ext4_extent_append_block(ext4_inode_ref_t *inode_ref, 935 uint32_t *iblock, uint32_t *fblock, bool update_size) 936 { 937 int rc = EOK; 938 934 * @param inode_ref I-node to append block to 935 * @param iblock Output logical number of newly allocated block 936 * @param fblock Output physical block address of newly allocated block 937 * 938 * @return Error code 939 * 940 */ 941 int ext4_extent_append_block(ext4_inode_ref_t *inode_ref, uint32_t *iblock, 942 uint32_t *fblock, bool update_size) 943 { 939 944 ext4_superblock_t *sb = inode_ref->fs->superblock; 940 945 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode); 941 946 uint32_t block_size = ext4_superblock_get_block_size(sb); 942 947 943 948 /* Calculate number of new logical block */ 944 949 uint32_t new_block_idx = 0; 945 950 if (inode_size > 0) { 946 if ((inode_size % block_size) != 0) {951 if ((inode_size % block_size) != 0) 947 952 inode_size += block_size - (inode_size % block_size); 948 }953 949 954 new_block_idx = inode_size / block_size; 950 955 } 951 956 952 957 /* Load the nearest leaf (with extent) */ 953 958 ext4_extent_path_t *path; 954 rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path);955 if (rc != EOK) {959 int rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path); 960 if (rc != EOK) 956 961 return rc; 957 } 958 962 959 963 /* Jump to last item of the path (extent) */ 960 964 ext4_extent_path_t *path_ptr = path; 961 while (path_ptr->depth != 0) {965 while (path_ptr->depth != 0) 962 966 path_ptr++; 963 } 964 967 965 968 /* Add new extent to the node if not present */ 966 if (path_ptr->extent == NULL) {969 if (path_ptr->extent == NULL) 967 970 goto append_extent; 968 } 969 971 970 972 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent); 971 973 uint16_t block_limit = (1 << 15); 972 974 973 975 uint32_t phys_block = 0; 974 976 if (block_count < block_limit) { 975 976 977 /* There is space for new block in the extent */ 977 978 978 if (block_count == 0) { 979 980 979 /* Existing extent is empty */ 981 982 980 rc = ext4_balloc_alloc_block(inode_ref, &phys_block); 983 if (rc != EOK) {981 if (rc != EOK) 984 982 goto finish; 985 } 986 983 987 984 /* Initialize extent */ 988 985 ext4_extent_set_first_block(path_ptr->extent, new_block_idx); 989 986 ext4_extent_set_start(path_ptr->extent, phys_block); 990 987 ext4_extent_set_block_count(path_ptr->extent, 1); 991 988 992 989 /* Update i-node */ 993 990 if (update_size) { … … 995 992 inode_ref->dirty = true; 996 993 } 997 994 998 995 path_ptr->block->dirty = true; 999 996 1000 997 goto finish; 1001 998 } else { 1002 1003 999 /* Existing extent contains some blocks */ 1004 1005 1000 phys_block = ext4_extent_get_start(path_ptr->extent); 1006 1001 phys_block += ext4_extent_get_block_count(path_ptr->extent); 1007 1002 1008 1003 /* Check if the following block is free for allocation */ 1009 1004 bool free; 1010 1005 rc = ext4_balloc_try_alloc_block(inode_ref, phys_block, &free); 1011 if (rc != EOK) {1006 if (rc != EOK) 1012 1007 goto finish; 1013 } 1014 1015 if (! free) { 1016 /* target is not free, new block must be appended to new extent */ 1008 1009 if (!free) { 1010 /* Target is not free, new block must be appended to new extent */ 1017 1011 goto append_extent; 1018 1012 } 1019 1020 1013 1021 1014 /* Update extent */ 1022 1015 ext4_extent_set_block_count(path_ptr->extent, block_count + 1); 1023 1016 1024 1017 /* Update i-node */ 1025 1018 if (update_size) { … … 1027 1020 inode_ref->dirty = true; 1028 1021 } 1029 1022 1030 1023 path_ptr->block->dirty = true; 1031 1024 1032 1025 goto finish; 1033 1026 } 1034 1027 } 1035 1036 /* Append new extent to the tree */ 1028 1029 1037 1030 append_extent: 1038 1031 /* Append new extent to the tree */ 1039 1032 phys_block = 0; 1040 1033 1041 1034 /* Allocate new data block */ 1042 1035 rc = ext4_balloc_alloc_block(inode_ref, &phys_block); 1043 if (rc != EOK) {1036 if (rc != EOK) 1044 1037 goto finish; 1045 } 1046 1038 1047 1039 /* Append extent for new block (includes tree splitting if needed) */ 1048 1040 rc = ext4_extent_append_extent(inode_ref, path, new_block_idx); … … 1051 1043 goto finish; 1052 1044 } 1053 1045 1054 1046 uint32_t tree_depth = ext4_extent_header_get_depth(path->header); 1055 1047 path_ptr = path + tree_depth; 1056 1048 1057 1049 /* Initialize newly created extent */ 1058 1050 ext4_extent_set_block_count(path_ptr->extent, 1); 1059 1051 ext4_extent_set_first_block(path_ptr->extent, new_block_idx); 1060 1052 ext4_extent_set_start(path_ptr->extent, phys_block); 1061 1053 1062 1054 /* Update i-node */ 1063 1055 if (update_size) { … … 1065 1057 inode_ref->dirty = true; 1066 1058 } 1067 1059 1068 1060 path_ptr->block->dirty = true; 1069 1070 1061 1071 1062 finish: 1072 1063 /* Set return values */ 1073 1064 *iblock = new_block_idx; 1074 1065 *fblock = phys_block; 1075 1076 /* Put loaded blocks 1066 1067 /* 1068 * Put loaded blocks 1077 1069 * starting from 1: 0 is a block with inode data 1078 1070 */ 1079 1071 for (uint16_t i = 1; i <= path->depth; ++i) { 1080 if (path[i].block) {1072 if (path[i].block) 1081 1073 block_put(path[i].block); 1082 } 1083 } 1084 1074 } 1075 1085 1076 /* Destroy temporary data structure */ 1086 1077 free(path); 1087 1078 1088 1079 return rc; 1089 1080 } … … 1091 1082 /** 1092 1083 * @} 1093 */ 1084 */ -
uspace/lib/ext4/libext4_extent.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_EXTENT_H_ … … 52 52 extern uint16_t ext4_extent_header_get_entries_count(ext4_extent_header_t *); 53 53 extern void ext4_extent_header_set_entries_count(ext4_extent_header_t *, 54 uint16_t);54 uint16_t); 55 55 extern uint16_t ext4_extent_header_get_max_entries_count(ext4_extent_header_t *); 56 56 extern void ext4_extent_header_set_max_entries_count(ext4_extent_header_t *, 57 uint16_t);57 uint16_t); 58 58 extern uint16_t ext4_extent_header_get_depth(ext4_extent_header_t *); 59 59 extern void ext4_extent_header_set_depth(ext4_extent_header_t *, uint16_t); … … 64 64 extern int ext4_extent_release_blocks_from(ext4_inode_ref_t *, uint32_t); 65 65 66 extern int ext4_extent_append_block(ext4_inode_ref_t *, uint32_t *, uint32_t *, bool); 66 extern int ext4_extent_append_block(ext4_inode_ref_t *, uint32_t *, uint32_t *, 67 bool); 67 68 68 69 #endif -
uspace/lib/ext4/libext4_filesystem.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_filesystem.c35 * @brief More complex filesystem operations.33 * @file libext4_filesystem.c 34 * @brief More complex filesystem operations. 36 35 */ 37 36 … … 43 42 /** Initialize filesystem and read all needed data. 44 43 * 45 * @param fs filesystem instance to be initialized 46 * @param service_id identifier if device with the filesystem 47 * @return error code 44 * @param fs Filesystem instance to be initialized 45 * @param service_id Identifier if device with the filesystem 46 * 47 * @return Error code 48 * 48 49 */ 49 50 int ext4_filesystem_init(ext4_filesystem_t *fs, service_id_t service_id, 50 enum cache_mode cmode) 51 { 52 int rc; 53 51 enum cache_mode cmode) 52 { 54 53 fs->device = service_id; 55 54 56 55 /* Initialize block library (4096 is size of communication channel) */ 57 rc = block_init(EXCHANGE_SERIALIZE, fs->device, 4096);58 if (rc != EOK) {56 int rc = block_init(EXCHANGE_SERIALIZE, fs->device, 4096); 57 if (rc != EOK) 59 58 return rc; 60 } 61 59 62 60 /* Read superblock from device to memory */ 63 61 ext4_superblock_t *temp_superblock; … … 67 65 return rc; 68 66 } 69 67 70 68 /* Read block size from superblock and check */ 71 69 uint32_t block_size = ext4_superblock_get_block_size(temp_superblock); … … 74 72 return ENOTSUP; 75 73 } 76 74 77 75 /* Initialize block caching by libblock */ 78 76 rc = block_cache_init(service_id, block_size, 0, cmode); … … 81 79 return rc; 82 80 } 83 81 84 82 /* Compute limits for indirect block levels */ 85 83 uint32_t block_ids_per_block = block_size / sizeof(uint32_t); 86 84 fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT; 87 85 fs->inode_blocks_per_level[0] = 1; 88 for ( int i = 1; i < 4; i++) {89 fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i -1] *86 for (unsigned int i = 1; i < 4; i++) { 87 fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i - 1] * 90 88 block_ids_per_block; 91 fs->inode_block_limits[i] = fs->inode_block_limits[i -1] +92 fs->inode_blocks_per_level[i];93 } 94 89 fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] + 90 fs->inode_blocks_per_level[i]; 91 } 92 95 93 /* Return loaded superblock */ 96 94 fs->superblock = temp_superblock; 97 95 98 96 uint16_t state = ext4_superblock_get_state(fs->superblock); 99 97 100 98 if (state != EXT4_SUPERBLOCK_STATE_VALID_FS) { 101 99 block_cache_fini(fs->device); … … 103 101 return ENOTSUP; 104 102 } 105 103 106 104 /* Mark system as mounted */ 107 105 ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_ERROR_FS); … … 112 110 return rc; 113 111 } 114 112 115 113 uint16_t mnt_count = ext4_superblock_get_mount_count(fs->superblock); 116 114 ext4_superblock_set_mount_count(fs->superblock, mnt_count + 1); 117 115 118 116 return EOK; 119 117 } … … 121 119 /** Destroy filesystem instance (used by unmount operation). 122 120 * 123 * @param fs filesystem to be destroyed 124 * @param write_sb flag if superblock should be written to device 125 * @return error code 121 * @param fs Filesystem to be destroyed 122 * 123 * @return Error code 124 * 126 125 */ 127 126 int ext4_filesystem_fini(ext4_filesystem_t *fs) 128 127 { 129 int rc = EOK;130 131 128 /* Write the superblock to the device */ 132 129 ext4_superblock_set_state(fs->superblock, EXT4_SUPERBLOCK_STATE_VALID_FS); 133 rc = ext4_superblock_write_direct(fs->device, fs->superblock);134 130 int rc = ext4_superblock_write_direct(fs->device, fs->superblock); 131 135 132 /* Release memory space for superblock */ 136 133 free(fs->superblock); 137 134 138 135 /* Finish work with block library */ 139 136 block_cache_fini(fs->device); 140 137 block_fini(fs->device); 141 138 142 139 return rc; 143 140 } … … 147 144 * Main is the check of the superblock structure. 148 145 * 149 * @param fs filesystem to be checked 150 * @return error code 146 * @param fs Filesystem to be checked 147 * 148 * @return Error code 149 * 151 150 */ 152 151 int ext4_filesystem_check_sanity(ext4_filesystem_t *fs) 153 152 { 154 int rc;155 156 153 /* Check superblock */ 157 rc = ext4_superblock_check_sanity(fs->superblock); 158 if (rc != EOK) { 159 return rc; 160 } 161 162 return EOK; 154 return ext4_superblock_check_sanity(fs->superblock); 163 155 } 164 156 … … 169 161 * during some write operations. 170 162 * 171 * @param fs filesystem to be checked 172 * @param read_only flag if filesystem should be mounted only for reading 173 * @return error code 163 * @param fs Filesystem to be checked 164 * @param read_only Flag if filesystem should be mounted only for reading 165 * 166 * @return Error code 167 * 174 168 */ 175 169 int ext4_filesystem_check_features(ext4_filesystem_t *fs, bool *read_only) … … 180 174 return EOK; 181 175 } 182 183 /* Check incompatible features - if filesystem has some, 176 177 /* 178 * Check incompatible features - if filesystem has some, 184 179 * volume can't be mounted 185 180 */ 186 181 uint32_t incompatible_features; 187 incompatible_features = ext4_superblock_get_features_incompatible(fs->superblock); 182 incompatible_features = 183 ext4_superblock_get_features_incompatible(fs->superblock); 188 184 incompatible_features &= ~EXT4_FEATURE_INCOMPAT_SUPP; 189 if (incompatible_features > 0) {185 if (incompatible_features > 0) 190 186 return ENOTSUP; 191 }192 193 /* Check read-only features, if filesystem has some,187 188 /* 189 * Check read-only features, if filesystem has some, 194 190 * volume can be mount only in read-only mode 195 191 */ 196 192 uint32_t compatible_read_only; 197 compatible_read_only = ext4_superblock_get_features_read_only(fs->superblock); 193 compatible_read_only = 194 ext4_superblock_get_features_read_only(fs->superblock); 198 195 compatible_read_only &= ~EXT4_FEATURE_RO_COMPAT_SUPP; 199 196 if (compatible_read_only > 0) { … … 201 198 return EOK; 202 199 } 203 200 204 201 return EOK; 205 202 } … … 208 205 /** Convert block address to relative index in block group. 209 206 * 210 * @param sb superblock pointer 211 * @param block_addr block number to convert 212 * @return relative number of block 207 * @param sb Superblock pointer 208 * @param block_addr Block number to convert 209 * 210 * @return Relative number of block 211 * 213 212 */ 214 213 uint32_t ext4_filesystem_blockaddr2_index_in_group(ext4_superblock_t *sb, 215 uint32_t block_addr)214 uint32_t block_addr) 216 215 { 217 216 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb); 218 217 uint32_t first_block = ext4_superblock_get_first_data_block(sb); 219 218 220 219 /* First block == 0 or 1 */ 221 if (first_block == 0) {220 if (first_block == 0) 222 221 return block_addr % blocks_per_group; 223 } else {222 else 224 223 return (block_addr - 1) % blocks_per_group; 225 }226 224 } 227 225 … … 229 227 /** Convert relative block address in group to absolute address. 230 228 * 231 * @param sb superblock pointer 232 * @param block_addr block number to convert 233 * @return absolute block address 229 * @param sb Superblock pointer 230 * 231 * @return Absolute block address 232 * 234 233 */ 235 234 uint32_t ext4_filesystem_index_in_group2blockaddr(ext4_superblock_t *sb, 236 uint32_t index, uint32_t bgid)235 uint32_t index, uint32_t bgid) 237 236 { 238 237 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb); 239 240 if (ext4_superblock_get_first_data_block(sb) == 0) {238 239 if (ext4_superblock_get_first_data_block(sb) == 0) 241 240 return bgid * blocks_per_group + index; 242 } else {241 else 243 242 return bgid * blocks_per_group + index + 1; 244 }245 246 243 } 247 244 248 245 /** Initialize block bitmap in block group. 249 * 250 * @param bg_ref reference to block group 251 * @return error code 246 * 247 * @param bg_ref Reference to block group 248 * 249 * @return Error code 250 * 252 251 */ 253 252 static int ext4_filesystem_init_block_bitmap(ext4_block_group_ref_t *bg_ref) 254 253 { 255 int rc;256 257 254 /* Load bitmap */ 258 255 uint32_t bitmap_block_addr = ext4_block_group_get_block_bitmap( 259 bg_ref->block_group, bg_ref->fs->superblock); 256 bg_ref->block_group, bg_ref->fs->superblock); 257 260 258 block_t *bitmap_block; 261 262 rc = block_get(&bitmap_block, bg_ref->fs->device, 263 bitmap_block_addr, BLOCK_FLAGS_NOREAD); 264 if (rc != EOK) { 259 int rc = block_get(&bitmap_block, bg_ref->fs->device, 260 bitmap_block_addr, BLOCK_FLAGS_NOREAD); 261 if (rc != EOK) 265 262 return rc; 266 } 267 263 268 264 uint8_t *bitmap = bitmap_block->data; 269 265 270 266 /* Initialize all bitmap bits to zero */ 271 267 uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock); 272 268 memset(bitmap, 0, block_size); 273 269 274 270 /* Determine first block and first data block in group */ 275 271 uint32_t first_idx = 0; 276 272 277 273 uint32_t first_data = ext4_balloc_get_first_data_block_in_group( 278 bg_ref->fs->superblock, bg_ref);274 bg_ref->fs->superblock, bg_ref); 279 275 uint32_t first_data_idx = ext4_filesystem_blockaddr2_index_in_group( 280 bg_ref->fs->superblock, first_data);281 276 bg_ref->fs->superblock, first_data); 277 282 278 /* Set bits from to first block to first data block - 1 to one (allocated) */ 283 for (uint32_t block = first_idx; block < first_data_idx; ++block) {279 for (uint32_t block = first_idx; block < first_data_idx; ++block) 284 280 ext4_bitmap_set_bit(bitmap, block); 285 } 286 281 287 282 bitmap_block->dirty = true; 288 283 289 284 /* Save bitmap */ 290 rc = block_put(bitmap_block); 291 if (rc != EOK) { 292 return rc; 293 } 294 295 return EOK; 285 return block_put(bitmap_block); 296 286 } 297 287 298 288 /** Initialize i-node bitmap in block group. 299 * 300 * @param bg_ref reference to block group 301 * @return error code 289 * 290 * @param bg_ref Reference to block group 291 * 292 * @return Error code 293 * 302 294 */ 303 295 static int ext4_filesystem_init_inode_bitmap(ext4_block_group_ref_t *bg_ref) 304 296 { 305 int rc;306 307 297 /* Load bitmap */ 308 298 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap( 309 bg_ref->block_group, bg_ref->fs->superblock);299 bg_ref->block_group, bg_ref->fs->superblock); 310 300 block_t *bitmap_block; 311 312 rc = block_get(&bitmap_block, bg_ref->fs->device,313 bitmap_block_addr, BLOCK_FLAGS_NOREAD);314 if (rc != EOK) {301 302 int rc = block_get(&bitmap_block, bg_ref->fs->device, 303 bitmap_block_addr, BLOCK_FLAGS_NOREAD); 304 if (rc != EOK) 315 305 return rc; 316 } 317 306 318 307 uint8_t *bitmap = bitmap_block->data; 319 308 320 309 /* Initialize all bitmap bits to zero */ 321 310 uint32_t block_size = ext4_superblock_get_block_size(bg_ref->fs->superblock); 322 311 uint32_t inodes_per_group = 323 ext4_superblock_get_inodes_per_group(bg_ref->fs->superblock);312 ext4_superblock_get_inodes_per_group(bg_ref->fs->superblock); 324 313 memset(bitmap, 0, (inodes_per_group + 7) / 8); 325 314 326 315 uint32_t start_bit = inodes_per_group; 327 316 uint32_t end_bit = block_size * 8; 328 317 329 318 uint32_t i; 330 for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) {319 for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) 331 320 ext4_bitmap_set_bit(bitmap, i); 332 } 333 334 if (i < end_bit) { 321 322 if (i < end_bit) 335 323 memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); 336 } 337 324 338 325 bitmap_block->dirty = true; 339 326 340 327 /* Save bitmap */ 341 rc = block_put(bitmap_block); 342 if (rc != EOK) { 343 return rc; 344 } 345 346 return EOK; 328 return block_put(bitmap_block); 347 329 } 348 330 349 331 /** Initialize i-node table in block group. 350 * 351 * @param bg_ref reference to block group 352 * @return error code 332 * 333 * @param bg_ref Reference to block group 334 * 335 * @return Error code 336 * 353 337 */ 354 338 static int ext4_filesystem_init_inode_table(ext4_block_group_ref_t *bg_ref) 355 339 { 356 int rc;357 358 340 ext4_superblock_t *sb = bg_ref->fs->superblock; 359 341 360 342 uint32_t inode_size = ext4_superblock_get_inode_size(sb); 361 343 uint32_t block_size = ext4_superblock_get_block_size(sb); 362 344 uint32_t inodes_per_block = block_size / inode_size; 363 345 364 346 uint32_t inodes_in_group = 365 ext4_superblock_get_inodes_in_group(sb, bg_ref->index);366 347 ext4_superblock_get_inodes_in_group(sb, bg_ref->index); 348 367 349 uint32_t table_blocks = inodes_in_group / inodes_per_block; 368 369 if (inodes_in_group % inodes_per_block) {350 351 if (inodes_in_group % inodes_per_block) 370 352 table_blocks++; 371 } 372 353 373 354 /* Compute initialization bounds */ 374 355 uint32_t first_block = ext4_block_group_get_inode_table_first_block( 375 bg_ref->block_group, sb);376 356 bg_ref->block_group, sb); 357 377 358 uint32_t last_block = first_block + table_blocks - 1; 378 359 379 360 /* Initialization of all itable blocks */ 380 361 for (uint32_t fblock = first_block; fblock <= last_block; ++fblock) { 381 362 block_t *block; 382 rc = block_get(&block, bg_ref->fs->device, fblock, BLOCK_FLAGS_NOREAD);383 if (rc != EOK) {384 return rc;385 }386 363 int rc = block_get(&block, bg_ref->fs->device, fblock, 364 BLOCK_FLAGS_NOREAD); 365 if (rc != EOK) 366 return rc; 367 387 368 memset(block->data, 0, block_size); 388 369 block->dirty = true; 389 370 390 371 rc = block_put(block); 391 if (rc != EOK) { 392 return rc; 393 } 394 } 395 372 if (rc != EOK) 373 return rc; 374 } 375 396 376 return EOK; 397 377 } … … 399 379 /** Get reference to block group specified by index. 400 380 * 401 * @param fs filesystem to find block group on 402 * @param bgid index of block group to load 403 * @param ref output pointer for reference 404 * @return error code 381 * @param fs Filesystem to find block group on 382 * @param bgid Index of block group to load 383 * @param ref Output pointer for reference 384 * 385 * @return Error code 386 * 405 387 */ 406 388 int ext4_filesystem_get_block_group_ref(ext4_filesystem_t *fs, uint32_t bgid, 407 389 ext4_block_group_ref_t **ref) 408 390 { 409 int rc;410 411 391 /* Allocate memory for new structure */ 412 ext4_block_group_ref_t *newref = malloc(sizeof(ext4_block_group_ref_t)); 413 if (newref == NULL) { 392 ext4_block_group_ref_t *newref = 393 malloc(sizeof(ext4_block_group_ref_t)); 394 if (newref == NULL) 414 395 return ENOMEM; 415 } 416 396 417 397 /* Compute number of descriptors, that fits in one data block */ 418 uint32_t descriptors_per_block = ext4_superblock_get_block_size(fs->superblock) 419 / ext4_superblock_get_desc_size(fs->superblock); 420 398 uint32_t descriptors_per_block = 399 ext4_superblock_get_block_size(fs->superblock) / 400 ext4_superblock_get_desc_size(fs->superblock); 401 421 402 /* Block group descriptor table starts at the next block after superblock */ 422 aoff64_t block_id = ext4_superblock_get_first_data_block(fs->superblock) + 1; 423 403 aoff64_t block_id = 404 ext4_superblock_get_first_data_block(fs->superblock) + 1; 405 424 406 /* Find the block containing the descriptor we are looking for */ 425 407 block_id += bgid / descriptors_per_block; 426 uint32_t offset = (bgid % descriptors_per_block) * ext4_superblock_get_desc_size(fs->superblock); 427 408 uint32_t offset = (bgid % descriptors_per_block) * 409 ext4_superblock_get_desc_size(fs->superblock); 410 428 411 /* Load block with descriptors */ 429 rc = block_get(&newref->block, fs->device, block_id, 0);412 int rc = block_get(&newref->block, fs->device, block_id, 0); 430 413 if (rc != EOK) { 431 414 free(newref); 432 415 return rc; 433 416 } 434 417 435 418 /* Inititialize in-memory representation */ 436 419 newref->block_group = newref->block->data + offset; … … 438 421 newref->index = bgid; 439 422 newref->dirty = false; 440 423 441 424 *ref = newref; 442 425 443 426 if (ext4_block_group_has_flag(newref->block_group, 444 EXT4_BLOCK_GROUP_BLOCK_UNINIT)) { 445 427 EXT4_BLOCK_GROUP_BLOCK_UNINIT)) { 446 428 rc = ext4_filesystem_init_block_bitmap(newref); 447 429 if (rc != EOK) { … … 450 432 return rc; 451 433 } 434 452 435 ext4_block_group_clear_flag(newref->block_group, 453 EXT4_BLOCK_GROUP_BLOCK_UNINIT);454 436 EXT4_BLOCK_GROUP_BLOCK_UNINIT); 437 455 438 newref->dirty = true; 456 439 } 457 440 458 441 if (ext4_block_group_has_flag(newref->block_group, 459 EXT4_BLOCK_GROUP_INODE_UNINIT)) { 460 442 EXT4_BLOCK_GROUP_INODE_UNINIT)) { 461 443 rc = ext4_filesystem_init_inode_bitmap(newref); 462 444 if (rc != EOK) { … … 465 447 return rc; 466 448 } 467 449 468 450 ext4_block_group_clear_flag(newref->block_group, 469 EXT4_BLOCK_GROUP_INODE_UNINIT); 470 471 if (! ext4_block_group_has_flag(newref->block_group, 472 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) { 473 451 EXT4_BLOCK_GROUP_INODE_UNINIT); 452 453 if (!ext4_block_group_has_flag(newref->block_group, 454 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) { 474 455 rc = ext4_filesystem_init_inode_table(newref); 475 if (rc != EOK) {456 if (rc != EOK) 476 457 return rc; 477 } 478 458 479 459 ext4_block_group_set_flag(newref->block_group, 480 EXT4_BLOCK_GROUP_ITABLE_ZEROED); 481 460 EXT4_BLOCK_GROUP_ITABLE_ZEROED); 482 461 } 462 483 463 newref->dirty = true; 484 485 } 486 464 } 465 487 466 return EOK; 488 467 } … … 492 471 * It uses crc functions from Linux kernel implementation. 493 472 * 494 * @param sb superblock 495 * @param bgid index of block group in the filesystem 496 * @param bg block group to compute checksum for 497 * @return checksum value 473 * @param sb Superblock 474 * @param bgid Index of block group in the filesystem 475 * @param bg Block group to compute checksum for 476 * 477 * @return Checksum value 478 * 498 479 */ 499 480 static uint16_t ext4_filesystem_bg_checksum(ext4_superblock_t *sb, uint32_t bgid, 500 ext4_block_group_t *bg)481 ext4_block_group_t *bg) 501 482 { 502 483 /* If checksum not supported, 0 will be returned */ 503 484 uint16_t crc = 0; 504 485 505 486 /* Compute the checksum only if the filesystem supports it */ 506 if (ext4_superblock_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {507 487 if (ext4_superblock_has_feature_read_only(sb, 488 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { 508 489 void *base = bg; 509 490 void *checksum = &bg->checksum; 510 511 uint32_t offset = (uint32_t) (checksum - base);512 491 492 uint32_t offset = (uint32_t) (checksum - base); 493 513 494 /* Convert block group index to little endian */ 514 495 uint32_t le_group = host2uint32_t_le(bgid); 515 496 516 497 /* Initialization */ 517 498 crc = crc16(~0, sb->uuid, sizeof(sb->uuid)); 518 499 519 500 /* Include index of block group */ 520 crc = crc16(crc, (uint8_t *) &le_group, sizeof(le_group));521 501 crc = crc16(crc, (uint8_t *) &le_group, sizeof(le_group)); 502 522 503 /* Compute crc from the first part (stop before checksum field) */ 523 crc = crc16(crc, (uint8_t *) bg, offset);524 504 crc = crc16(crc, (uint8_t *) bg, offset); 505 525 506 /* Skip checksum */ 526 507 offset += sizeof(bg->checksum); 527 508 528 509 /* Checksum of the rest of block group descriptor */ 529 if ((ext4_superblock_has_feature_incompatible(sb, EXT4_FEATURE_INCOMPAT_64BIT)) &&530 offset < ext4_superblock_get_desc_size(sb)) {531 532 crc = crc16(crc, ((uint8_t *) bg) + offset, ext4_superblock_get_desc_size(sb) - offset);533 }534 } 535 510 if ((ext4_superblock_has_feature_incompatible(sb, 511 EXT4_FEATURE_INCOMPAT_64BIT)) && 512 (offset < ext4_superblock_get_desc_size(sb))) 513 crc = crc16(crc, ((uint8_t *) bg) + offset, 514 ext4_superblock_get_desc_size(sb) - offset); 515 } 516 536 517 return crc; 537 538 518 } 539 519 540 520 /** Put reference to block group. 541 521 * 542 * @oaram ref pointer for reference to be put back 543 * @return error code 522 * @oaram ref Pointer for reference to be put back 523 * 524 * @return Error code 525 * 544 526 */ 545 527 int ext4_filesystem_put_block_group_ref(ext4_block_group_ref_t *ref) 546 528 { 547 int rc;548 549 529 /* Check if reference modified */ 550 530 if (ref->dirty) { 551 552 531 /* Compute new checksum of block group */ 553 uint16_t checksum = ext4_filesystem_bg_checksum( 554 ref->fs->superblock, ref->index, ref->block_group); 532 uint16_t checksum = 533 ext4_filesystem_bg_checksum(ref->fs->superblock, ref->index, 534 ref->block_group); 555 535 ext4_block_group_set_checksum(ref->block_group, checksum); 556 536 557 537 /* Mark block dirty for writing changes to physical device */ 558 538 ref->block->dirty = true; 559 539 } 560 540 561 541 /* Put back block, that contains block group descriptor */ 562 rc = block_put(ref->block);542 int rc = block_put(ref->block); 563 543 free(ref); 564 544 565 545 return rc; 566 546 } … … 568 548 /** Get reference to i-node specified by index. 569 549 * 570 * @param fs filesystem to find i-node on 571 * @param index index of i-node to load 572 * @oaram ref output pointer for reference 573 * @return error code 550 * @param fs Filesystem to find i-node on 551 * @param index Index of i-node to load 552 * @oaram ref Output pointer for reference 553 * 554 * @return Error code 555 * 574 556 */ 575 557 int ext4_filesystem_get_inode_ref(ext4_filesystem_t *fs, uint32_t index, 576 558 ext4_inode_ref_t **ref) 577 559 { 578 int rc;579 580 560 /* Allocate memory for new structure */ 581 ext4_inode_ref_t *newref = malloc(sizeof(ext4_inode_ref_t)); 582 if (newref == NULL) { 561 ext4_inode_ref_t *newref = 562 malloc(sizeof(ext4_inode_ref_t)); 563 if (newref == NULL) 583 564 return ENOMEM; 584 } 585 565 586 566 /* Compute number of i-nodes, that fits in one data block */ 587 567 uint32_t inodes_per_group = 588 ext4_superblock_get_inodes_per_group(fs->superblock); 589 590 /* Inode numbers are 1-based, but it is simpler to work with 0-based 568 ext4_superblock_get_inodes_per_group(fs->superblock); 569 570 /* 571 * Inode numbers are 1-based, but it is simpler to work with 0-based 591 572 * when computing indices 592 573 */ … … 594 575 uint32_t block_group = index / inodes_per_group; 595 576 uint32_t offset_in_group = index % inodes_per_group; 596 577 597 578 /* Load block group, where i-node is located */ 598 579 ext4_block_group_ref_t *bg_ref; 599 rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref);580 int rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref); 600 581 if (rc != EOK) { 601 582 free(newref); 602 583 return rc; 603 584 } 604 585 605 586 /* Load block address, where i-node table is located */ 606 uint32_t inode_table_start = ext4_block_group_get_inode_table_first_block( 607 bg_ref->block_group, fs->superblock); 608 587 uint32_t inode_table_start = 588 ext4_block_group_get_inode_table_first_block(bg_ref->block_group, 589 fs->superblock); 590 609 591 /* Put back block group reference (not needed more) */ 610 592 rc = ext4_filesystem_put_block_group_ref(bg_ref); … … 613 595 return rc; 614 596 } 615 597 616 598 /* Compute position of i-node in the block group */ 617 599 uint16_t inode_size = ext4_superblock_get_inode_size(fs->superblock); 618 600 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 619 601 uint32_t byte_offset_in_group = offset_in_group * inode_size; 620 602 621 603 /* Compute block address */ 622 604 aoff64_t block_id = inode_table_start + (byte_offset_in_group / block_size); … … 626 608 return rc; 627 609 } 628 610 629 611 /* Compute position of i-node in the data block */ 630 612 uint32_t offset_in_block = byte_offset_in_group % block_size; 631 613 newref->inode = newref->block->data + offset_in_block; 632 614 633 615 /* We need to store the original value of index in the reference */ 634 616 newref->index = index + 1; 635 617 newref->fs = fs; 636 618 newref->dirty = false; 637 619 638 620 *ref = newref; 639 621 640 622 return EOK; 641 623 } … … 643 625 /** Put reference to i-node. 644 626 * 645 * @param ref pointer for reference to be put back 646 * @return error code 627 * @param ref Pointer for reference to be put back 628 * 629 * @return Error code 630 * 647 631 */ 648 632 int ext4_filesystem_put_inode_ref(ext4_inode_ref_t *ref) 649 633 { 650 int rc;651 652 634 /* Check if reference modified */ 653 635 if (ref->dirty) { 654 655 636 /* Mark block dirty for writing changes to physical device */ 656 637 ref->block->dirty = true; 657 638 } 658 639 659 640 /* Put back block, that contains i-node */ 660 rc = block_put(ref->block);641 int rc = block_put(ref->block); 661 642 free(ref); 662 643 663 644 return rc; 664 645 } … … 666 647 /** Allocate new i-node in the filesystem. 667 648 * 668 * @param fs filesystem to allocated i-node on 669 * @param inode_ref output pointer to return reference to allocated i-node 670 * @param flags flags to be set for newly created i-node 671 * @return error code 649 * @param fs Filesystem to allocated i-node on 650 * @param inode_ref Output pointer to return reference to allocated i-node 651 * @param flags Flags to be set for newly created i-node 652 * 653 * @return Error code 654 * 672 655 */ 673 656 int ext4_filesystem_alloc_inode(ext4_filesystem_t *fs, 674 ext4_inode_ref_t **inode_ref, int flags) 675 { 676 int rc; 677 657 ext4_inode_ref_t **inode_ref, int flags) 658 { 678 659 /* Check if newly allocated i-node will be a directory */ 679 660 bool is_dir = false; 680 if (flags & L_DIRECTORY) {661 if (flags & L_DIRECTORY) 681 662 is_dir = true; 682 } 683 663 684 664 /* Allocate inode by allocation algorithm */ 685 665 uint32_t index; 686 rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);687 if (rc != EOK) {666 int rc = ext4_ialloc_alloc_inode(fs, &index, is_dir); 667 if (rc != EOK) 688 668 return rc; 689 } 690 669 691 670 /* Load i-node from on-disk i-node table */ 692 671 rc = ext4_filesystem_get_inode_ref(fs, index, inode_ref); … … 695 674 return rc; 696 675 } 697 676 698 677 /* Initialize i-node */ 699 678 ext4_inode_t *inode = (*inode_ref)->inode; 700 679 701 680 uint16_t mode; 702 681 if (is_dir) { … … 705 684 * 0777 (octal) == rwxrwxrwx 706 685 */ 686 707 687 mode = 0777; 708 688 mode |= EXT4_INODE_MODE_DIRECTORY; 709 689 ext4_inode_set_mode(fs->superblock, inode, mode); 710 ext4_inode_set_links_count(inode, 1); /* '.' entry */690 ext4_inode_set_links_count(inode, 1); /* '.' entry */ 711 691 } else { 712 692 /* … … 714 694 * 0666 (octal) == rw-rw-rw- 715 695 */ 716 696 717 697 mode = 0666; 718 698 mode |= EXT4_INODE_MODE_FILE; … … 720 700 ext4_inode_set_links_count(inode, 0); 721 701 } 722 702 723 703 ext4_inode_set_uid(inode, 0); 724 704 ext4_inode_set_gid(inode, 0); … … 731 711 ext4_inode_set_flags(inode, 0); 732 712 ext4_inode_set_generation(inode, 0); 733 713 734 714 /* Reset blocks array */ 735 for (uint32_t i = 0; i < EXT4_INODE_BLOCKS; i++) {715 for (uint32_t i = 0; i < EXT4_INODE_BLOCKS; i++) 736 716 inode->blocks[i] = 0; 737 } 738 717 739 718 /* Initialize extents if needed */ 740 719 if (ext4_superblock_has_feature_incompatible( 741 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS)) { 742 720 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS)) { 743 721 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS); 744 722 745 723 /* Initialize extent root header */ 746 724 ext4_extent_header_t *header = ext4_inode_get_extent_header(inode); … … 749 727 ext4_extent_header_set_generation(header, 0); 750 728 ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC); 751 752 uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof (uint32_t) - sizeof(ext4_extent_header_t))753 / sizeof(ext4_extent_t);754 729 730 uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) - 731 sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t); 732 755 733 ext4_extent_header_set_max_entries_count(header, max_entries); 756 734 } 757 735 758 736 (*inode_ref)->dirty = true; 759 737 760 738 return EOK; 761 739 } … … 763 741 /** Release i-node and mark it as free. 764 742 * 765 * @param inode_ref i-node to be released 766 * @return error code 743 * @param inode_ref I-node to be released 744 * 745 * @return Error code 746 * 767 747 */ 768 748 int ext4_filesystem_free_inode(ext4_inode_ref_t *inode_ref) 769 749 { 770 int rc;771 772 750 ext4_filesystem_t *fs = inode_ref->fs; 773 751 774 752 /* For extents must be data block destroyed by other way */ 775 if (ext4_superblock_has_feature_incompatible( 776 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 777 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 778 753 if ((ext4_superblock_has_feature_incompatible(fs->superblock, 754 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 755 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 779 756 /* Data structures are released during truncate operation... */ 780 757 goto finish; 781 758 } 782 759 783 760 /* Release all indirect (no data) blocks */ 784 761 785 762 /* 1) Single indirect */ 786 763 uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0); 787 764 if (fblock != 0) { 788 rc = ext4_balloc_free_block(inode_ref, fblock); 789 if (rc != EOK) { 790 return rc; 791 } 792 765 int rc = ext4_balloc_free_block(inode_ref, fblock); 766 if (rc != EOK) 767 return rc; 768 793 769 ext4_inode_set_indirect_block(inode_ref->inode, 0, 0); 794 770 } 795 771 796 772 block_t *block; 797 773 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 798 774 uint32_t count = block_size / sizeof(uint32_t); 799 775 800 776 /* 2) Double indirect */ 801 777 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1); 802 778 if (fblock != 0) { 803 rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE); 804 if (rc != EOK) { 805 return rc; 806 } 807 779 int rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE); 780 if (rc != EOK) 781 return rc; 782 808 783 uint32_t ind_block; 809 784 for (uint32_t offset = 0; offset < count; ++offset) { 810 ind_block = uint32_t_le2host(((uint32_t *)block->data)[offset]);811 785 ind_block = uint32_t_le2host(((uint32_t *) block->data)[offset]); 786 812 787 if (ind_block != 0) { 813 788 rc = ext4_balloc_free_block(inode_ref, ind_block); … … 818 793 } 819 794 } 820 795 821 796 block_put(block); 822 797 rc = ext4_balloc_free_block(inode_ref, fblock); 823 if (rc != EOK) { 824 return rc; 825 } 826 798 if (rc != EOK) 799 return rc; 800 827 801 ext4_inode_set_indirect_block(inode_ref->inode, 1, 0); 828 802 } 829 830 803 831 804 /* 3) Tripple indirect */ 832 805 block_t *subblock; 833 806 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2); 834 807 if (fblock != 0) { 835 rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE); 836 if (rc != EOK) { 837 return rc; 838 } 839 808 int rc = block_get(&block, fs->device, fblock, BLOCK_FLAGS_NONE); 809 if (rc != EOK) 810 return rc; 811 840 812 uint32_t ind_block; 841 813 for (uint32_t offset = 0; offset < count; ++offset) { 842 ind_block = uint32_t_le2host(((uint32_t *)block->data)[offset]);843 814 ind_block = uint32_t_le2host(((uint32_t *) block->data)[offset]); 815 844 816 if (ind_block != 0) { 845 rc = block_get(&subblock, fs->device, ind_block, BLOCK_FLAGS_NONE); 817 rc = block_get(&subblock, fs->device, ind_block, 818 BLOCK_FLAGS_NONE); 846 819 if (rc != EOK) { 847 820 block_put(block); 848 821 return rc; 849 822 } 850 823 851 824 uint32_t ind_subblock; 852 for (uint32_t suboffset = 0; suboffset < count; ++suboffset) { 853 ind_subblock = uint32_t_le2host(((uint32_t*)subblock->data)[suboffset]); 854 825 for (uint32_t suboffset = 0; suboffset < count; 826 ++suboffset) { 827 ind_subblock = uint32_t_le2host(((uint32_t *) 828 subblock->data)[suboffset]); 829 855 830 if (ind_subblock != 0) { 856 831 rc = ext4_balloc_free_block(inode_ref, ind_subblock); … … 861 836 } 862 837 } 863 864 838 } 839 865 840 block_put(subblock); 866 867 841 } 868 842 869 843 rc = ext4_balloc_free_block(inode_ref, ind_block); 870 844 if (rc != EOK) { … … 872 846 return rc; 873 847 } 874 875 876 848 } 877 849 878 850 block_put(block); 879 851 rc = ext4_balloc_free_block(inode_ref, fblock); 880 if (rc != EOK) { 881 return rc; 882 } 883 852 if (rc != EOK) 853 return rc; 854 884 855 ext4_inode_set_indirect_block(inode_ref->inode, 2, 0); 885 856 } 886 857 887 858 finish: 888 889 859 /* Mark inode dirty for writing to the physical device */ 890 860 inode_ref->dirty = true; 891 861 892 862 /* Free block with extended attributes if present */ 893 863 uint32_t xattr_block = ext4_inode_get_file_acl( 894 inode_ref->inode, fs->superblock);864 inode_ref->inode, fs->superblock); 895 865 if (xattr_block) { 896 rc = ext4_balloc_free_block(inode_ref, xattr_block); 897 if (rc != EOK) { 898 return rc; 899 } 900 866 int rc = ext4_balloc_free_block(inode_ref, xattr_block); 867 if (rc != EOK) 868 return rc; 869 901 870 ext4_inode_set_file_acl(inode_ref->inode, fs->superblock, 0); 902 871 } 903 872 904 873 /* Free inode by allocator */ 874 int rc; 905 875 if (ext4_inode_is_type(fs->superblock, inode_ref->inode, 906 EXT4_INODE_MODE_DIRECTORY)) {876 EXT4_INODE_MODE_DIRECTORY)) 907 877 rc = ext4_ialloc_free_inode(fs, inode_ref->index, true); 908 } else {878 else 909 879 rc = ext4_ialloc_free_inode(fs, inode_ref->index, false); 910 } 911 if (rc != EOK) { 912 return rc; 913 } 914 915 return EOK; 880 881 return rc; 916 882 } 917 883 918 884 /** Truncate i-node data blocks. 919 885 * 920 * @param inode_ref i-node to be truncated921 * @param new_size new size of inode (must be < current size)922 * @return error code923 * /924 int ext4_filesystem_truncate_inode( 925 ext4_inode_ref_t *inode_ref, aoff64_t new_size) 926 { 927 int rc; 928 886 * @param inode_ref I-node to be truncated 887 * @param new_size New size of inode (must be < current size) 888 * 889 * @return Error code 890 * 891 */ 892 int ext4_filesystem_truncate_inode(ext4_inode_ref_t *inode_ref, 893 aoff64_t new_size) 894 { 929 895 ext4_superblock_t *sb = inode_ref->fs->superblock; 930 896 931 897 /* Check flags, if i-node can be truncated */ 932 if (! ext4_inode_can_truncate(sb, inode_ref->inode)) {898 if (!ext4_inode_can_truncate(sb, inode_ref->inode)) 933 899 return EINVAL; 934 } 935 900 936 901 /* If sizes are equal, nothing has to be done. */ 937 902 aoff64_t old_size = ext4_inode_get_size(sb, inode_ref->inode); 938 if (old_size == new_size) {903 if (old_size == new_size) 939 904 return EOK; 940 } 941 905 942 906 /* It's not suppported to make the larger file by truncate operation */ 943 if (old_size < new_size) {907 if (old_size < new_size) 944 908 return EINVAL; 945 } 946 909 947 910 /* Compute how many blocks will be released */ 948 911 aoff64_t size_diff = old_size - new_size; 949 912 uint32_t block_size = ext4_superblock_get_block_size(sb); 950 913 uint32_t diff_blocks_count = size_diff / block_size; 951 if (size_diff % block_size != 0) {914 if (size_diff % block_size != 0) 952 915 diff_blocks_count++; 953 } 954 916 955 917 uint32_t old_blocks_count = old_size / block_size; 956 if (old_size % block_size != 0) {918 if (old_size % block_size != 0) 957 919 old_blocks_count++; 958 } 959 960 if (ext4_superblock_has_feature_incompatible( 961 inode_ref->fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 962 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 963 920 921 if ((ext4_superblock_has_feature_incompatible(inode_ref->fs->superblock, 922 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 923 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 964 924 /* Extents require special operation */ 965 966 rc = ext4_extent_release_blocks_from(inode_ref, 967 old_blocks_count - diff_blocks_count); 968 if (rc != EOK) { 969 return rc; 970 } 925 int rc = ext4_extent_release_blocks_from(inode_ref, 926 old_blocks_count - diff_blocks_count); 927 if (rc != EOK) 928 return rc; 971 929 } else { 972 973 930 /* Release data blocks from the end of file */ 974 931 975 932 /* Starting from 1 because of logical blocks are numbered from 0 */ 976 933 for (uint32_t i = 1; i <= diff_blocks_count; ++i) { 977 rc = ext4_filesystem_release_inode_block(inode_ref, old_blocks_count - i); 978 if (rc != EOK) { 934 int rc = ext4_filesystem_release_inode_block(inode_ref, 935 old_blocks_count - i); 936 if (rc != EOK) 979 937 return rc; 980 }981 938 } 982 939 } 983 940 984 941 /* Update i-node */ 985 942 ext4_inode_set_size(inode_ref->inode, new_size); 986 943 inode_ref->dirty = true; 987 944 988 945 return EOK; 989 946 } … … 991 948 /** Get physical block address by logical index of the block. 992 949 * 993 * @param inode_ref i-node to read block address from 994 * @param iblock logical index of block 995 * @param fblock output pointer for return physical block address 996 * @return error code 950 * @param inode_ref I-node to read block address from 951 * @param iblock Logical index of block 952 * @param fblock Output pointer for return physical block address 953 * 954 * @return Error code 955 * 997 956 */ 998 957 int ext4_filesystem_get_inode_data_block_index(ext4_inode_ref_t *inode_ref, 999 aoff64_t iblock, uint32_t *fblock) 1000 { 1001 int rc; 1002 958 aoff64_t iblock, uint32_t *fblock) 959 { 1003 960 ext4_filesystem_t *fs = inode_ref->fs; 1004 961 1005 962 /* For empty file is situation simple */ 1006 963 if (ext4_inode_get_size(fs->superblock, inode_ref->inode) == 0) { … … 1008 965 return EOK; 1009 966 } 1010 967 1011 968 uint32_t current_block; 1012 969 1013 970 /* Handle i-node using extents */ 1014 if (ext4_superblock_has_feature_incompatible(fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 1015 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 1016 1017 rc = ext4_extent_find_block(inode_ref, iblock, ¤t_block); 1018 1019 if (rc != EOK) { 1020 return rc; 1021 } 1022 971 if ((ext4_superblock_has_feature_incompatible(fs->superblock, 972 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 973 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 974 int rc = ext4_extent_find_block(inode_ref, iblock, ¤t_block); 975 if (rc != EOK) 976 return rc; 977 1023 978 *fblock = current_block; 1024 979 return EOK; 1025 1026 } 1027 980 } 981 1028 982 ext4_inode_t *inode = inode_ref->inode; 1029 983 1030 984 /* Direct block are read directly from array in i-node structure */ 1031 985 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) { 1032 current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock);986 current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock); 1033 987 *fblock = current_block; 1034 988 return EOK; 1035 989 } 1036 990 1037 991 /* Determine indirection level of the target block */ 1038 int level = -1;1039 for ( int i = 1; i < 4; i++) {992 unsigned int level = 0; 993 for (unsigned int i = 1; i < 4; i++) { 1040 994 if (iblock < fs->inode_block_limits[i]) { 1041 995 level = i; … … 1043 997 } 1044 998 } 1045 1046 if (level == -1) {999 1000 if (level == 0) 1047 1001 return EIO; 1048 } 1049 1002 1050 1003 /* Compute offsets for the topmost level */ 1051 aoff64_t block_offset_in_level = iblock - fs->inode_block_limits[level-1]; 1052 current_block = ext4_inode_get_indirect_block(inode, level-1); 1053 uint32_t offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1054 1004 aoff64_t block_offset_in_level = 1005 iblock - fs->inode_block_limits[level - 1]; 1006 current_block = ext4_inode_get_indirect_block(inode, level - 1); 1007 uint32_t offset_in_block = 1008 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1009 1055 1010 /* Sparse file */ 1056 1011 if (current_block == 0) { … … 1058 1013 return EOK; 1059 1014 } 1060 1015 1061 1016 block_t *block; 1062 1063 /* Navigate through other levels, until we find the block number 1017 1018 /* 1019 * Navigate through other levels, until we find the block number 1064 1020 * or find null reference meaning we are dealing with sparse file 1065 1021 */ 1066 1022 while (level > 0) { 1067 1068 1023 /* Load indirect block */ 1069 rc = block_get(&block, fs->device, current_block, 0); 1070 if (rc != EOK) { 1071 return rc; 1072 } 1073 1024 int rc = block_get(&block, fs->device, current_block, 0); 1025 if (rc != EOK) 1026 return rc; 1027 1074 1028 /* Read block address from indirect block */ 1075 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]); 1076 1029 current_block = 1030 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]); 1031 1077 1032 /* Put back indirect block untouched */ 1078 1033 rc = block_put(block); 1079 if (rc != EOK) { 1080 return rc; 1081 } 1082 1034 if (rc != EOK) 1035 return rc; 1036 1083 1037 /* Check for sparse file */ 1084 1038 if (current_block == 0) { … … 1086 1040 return EOK; 1087 1041 } 1088 1042 1089 1043 /* Jump to the next level */ 1090 level -= 1;1091 1044 level--; 1045 1092 1046 /* Termination condition - we have address of data block loaded */ 1093 if (level == 0) {1047 if (level == 0) 1094 1048 break; 1095 } 1096 1049 1097 1050 /* Visit the next level */ 1098 1051 block_offset_in_level %= fs->inode_blocks_per_level[level]; 1099 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1100 } 1101 1052 offset_in_block = 1053 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1054 } 1055 1102 1056 *fblock = current_block; 1103 1057 1104 1058 return EOK; 1105 1059 } … … 1107 1061 /** Set physical block address for the block logical address into the i-node. 1108 1062 * 1109 * @param inode_ref i-node to set block address to 1110 * @param iblock logical index of block 1111 * @param fblock physical block address 1112 * @return error code 1063 * @param inode_ref I-node to set block address to 1064 * @param iblock Logical index of block 1065 * @param fblock Physical block address 1066 * 1067 * @return Error code 1068 * 1113 1069 */ 1114 1070 int ext4_filesystem_set_inode_data_block_index(ext4_inode_ref_t *inode_ref, 1115 aoff64_t iblock, uint32_t fblock) 1116 { 1117 int rc; 1118 1071 aoff64_t iblock, uint32_t fblock) 1072 { 1119 1073 ext4_filesystem_t *fs = inode_ref->fs; 1120 1074 1121 1075 /* Handle inode using extents */ 1122 if (ext4_superblock_has_feature_compatible(fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 1123 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 1124 /* not reachable !!! */ 1076 if ((ext4_superblock_has_feature_compatible(fs->superblock, 1077 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 1078 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 1079 /* Not reachable */ 1125 1080 return ENOTSUP; 1126 1081 } 1127 1082 1128 1083 /* Handle simple case when we are dealing with direct reference */ 1129 1084 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) { 1130 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock, fblock);1085 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock, fblock); 1131 1086 inode_ref->dirty = true; 1087 1132 1088 return EOK; 1133 1089 } 1134 1090 1135 1091 /* Determine the indirection level needed to get the desired block */ 1136 int level = -1;1137 for ( int i = 1; i < 4; i++) {1092 unsigned int level = 0; 1093 for (unsigned int i = 1; i < 4; i++) { 1138 1094 if (iblock < fs->inode_block_limits[i]) { 1139 1095 level = i; … … 1141 1097 } 1142 1098 } 1143 1144 if (level == -1) {1099 1100 if (level == 0) 1145 1101 return EIO; 1146 } 1147 1102 1148 1103 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 1149 1104 1150 1105 /* Compute offsets for the topmost level */ 1151 aoff64_t block_offset_in_level = iblock - fs->inode_block_limits[level-1]; 1152 uint32_t current_block = ext4_inode_get_indirect_block(inode_ref->inode, level-1); 1153 uint32_t offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1154 1106 aoff64_t block_offset_in_level = 1107 iblock - fs->inode_block_limits[level - 1]; 1108 uint32_t current_block = 1109 ext4_inode_get_indirect_block(inode_ref->inode, level - 1); 1110 uint32_t offset_in_block = 1111 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1112 1155 1113 uint32_t new_block_addr; 1156 block_t *block, *new_block; 1157 1114 block_t *block; 1115 block_t *new_block; 1116 1158 1117 /* Is needed to allocate indirect block on the i-node level */ 1159 1118 if (current_block == 0) { 1160 1161 1119 /* Allocate new indirect block */ 1162 rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr); 1163 if (rc != EOK) { 1164 return rc; 1165 } 1166 1120 int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr); 1121 if (rc != EOK) 1122 return rc; 1123 1167 1124 /* Update i-node */ 1168 ext4_inode_set_indirect_block(inode_ref->inode, level - 1, new_block_addr); 1125 ext4_inode_set_indirect_block(inode_ref->inode, level - 1, 1126 new_block_addr); 1169 1127 inode_ref->dirty = true; 1170 1128 1171 1129 /* Load newly allocated block */ 1172 rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD); 1130 rc = block_get(&new_block, fs->device, new_block_addr, 1131 BLOCK_FLAGS_NOREAD); 1173 1132 if (rc != EOK) { 1174 1133 ext4_balloc_free_block(inode_ref, new_block_addr); 1175 1134 return rc; 1176 1135 } 1177 1136 1178 1137 /* Initialize new block */ 1179 1138 memset(new_block->data, 0, block_size); 1180 1139 new_block->dirty = true; 1181 1140 1182 1141 /* Put back the allocated block */ 1183 1142 rc = block_put(new_block); 1184 if (rc != EOK) { 1185 return rc; 1186 } 1187 1143 if (rc != EOK) 1144 return rc; 1145 1188 1146 current_block = new_block_addr; 1189 1147 } 1190 1191 /* Navigate through other levels, until we find the block number 1148 1149 /* 1150 * Navigate through other levels, until we find the block number 1192 1151 * or find null reference meaning we are dealing with sparse file 1193 1152 */ 1194 1153 while (level > 0) { 1195 1196 rc = block_get(&block, fs->device, current_block, 0); 1197 if (rc != EOK) { 1198 return rc; 1199 } 1200 1201 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]); 1202 1154 int rc = block_get(&block, fs->device, current_block, 0); 1155 if (rc != EOK) 1156 return rc; 1157 1158 current_block = 1159 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]); 1160 1203 1161 if ((level > 1) && (current_block == 0)) { 1204 1205 1162 /* Allocate new block */ 1206 1163 rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr); … … 1209 1166 return rc; 1210 1167 } 1211 1168 1212 1169 /* Load newly allocated block */ 1213 rc = block_get(&new_block, fs->device, new_block_addr, BLOCK_FLAGS_NOREAD); 1170 rc = block_get(&new_block, fs->device, new_block_addr, 1171 BLOCK_FLAGS_NOREAD); 1214 1172 if (rc != EOK) { 1215 1173 block_put(block); 1216 1174 return rc; 1217 1175 } 1218 1176 1219 1177 /* Initialize allocated block */ 1220 1178 memset(new_block->data, 0, block_size); 1221 1179 new_block->dirty = true; 1222 1180 1223 1181 rc = block_put(new_block); 1224 1182 if (rc != EOK) { … … 1226 1184 return rc; 1227 1185 } 1228 1186 1229 1187 /* Write block address to the parent */ 1230 ((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(new_block_addr); 1188 ((uint32_t *) block->data)[offset_in_block] = 1189 host2uint32_t_le(new_block_addr); 1231 1190 block->dirty = true; 1232 1191 current_block = new_block_addr; 1233 1192 } 1234 1193 1235 1194 /* Will be finished, write the fblock address */ 1236 1195 if (level == 1) { 1237 ((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(fblock); 1196 ((uint32_t *) block->data)[offset_in_block] = 1197 host2uint32_t_le(fblock); 1238 1198 block->dirty = true; 1239 1199 } 1240 1200 1241 1201 rc = block_put(block); 1242 if (rc != EOK) {1243 return rc; 1244 }1245 1246 level -= 1;1247 1248 /* If we are on the last level, break here as1202 if (rc != EOK) 1203 return rc; 1204 1205 level--; 1206 1207 /* 1208 * If we are on the last level, break here as 1249 1209 * there is no next level to visit 1250 1210 */ 1251 if (level == 0) {1211 if (level == 0) 1252 1212 break; 1253 } 1254 1213 1255 1214 /* Visit the next level */ 1256 1215 block_offset_in_level %= fs->inode_blocks_per_level[level]; 1257 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1258 } 1259 1216 offset_in_block = 1217 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1218 } 1219 1260 1220 return EOK; 1261 1221 } … … 1263 1223 /** Release data block from i-node 1264 1224 * 1265 * @param inode_ref i-node to release block from1266 * @param iblock logical block to be released1267 * @return error code1268 * /1269 int ext4_filesystem_release_inode_block( 1270 ext4_inode_ref_t *inode_ref, uint32_t iblock) 1271 { 1272 int rc; 1273 1225 * @param inode_ref I-node to release block from 1226 * @param iblock Logical block to be released 1227 * 1228 * @return Error code 1229 * 1230 */ 1231 int ext4_filesystem_release_inode_block(ext4_inode_ref_t *inode_ref, 1232 uint32_t iblock) 1233 { 1274 1234 uint32_t fblock; 1275 1235 1276 1236 ext4_filesystem_t *fs = inode_ref->fs; 1277 1278 /* E XTENTSare handled otherwise = there is not support in this function */1279 assert(! (ext4_superblock_has_feature_incompatible(fs->superblock,1280 EXT4_FEATURE_INCOMPAT_EXTENTS) &&1281 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)));1282 1237 1238 /* Extents are handled otherwise = there is not support in this function */ 1239 assert(!(ext4_superblock_has_feature_incompatible(fs->superblock, 1240 EXT4_FEATURE_INCOMPAT_EXTENTS) && 1241 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)))); 1242 1283 1243 ext4_inode_t *inode = inode_ref->inode; 1284 1244 1285 1245 /* Handle simple case when we are dealing with direct reference */ 1286 1246 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) { 1287 1247 fblock = ext4_inode_get_direct_block(inode, iblock); 1248 1288 1249 /* Sparse file */ 1289 if (fblock == 0) {1250 if (fblock == 0) 1290 1251 return EOK; 1291 } 1292 1252 1293 1253 ext4_inode_set_direct_block(inode, iblock, 0); 1294 1254 return ext4_balloc_free_block(inode_ref, fblock); 1295 1255 } 1296 1297 1256 1298 1257 /* Determine the indirection level needed to get the desired block */ 1299 int level = -1;1300 for ( int i = 1; i < 4; i++) {1258 unsigned int level = 0; 1259 for (unsigned int i = 1; i < 4; i++) { 1301 1260 if (iblock < fs->inode_block_limits[i]) { 1302 1261 level = i; … … 1304 1263 } 1305 1264 } 1306 1307 if (level == -1) {1265 1266 if (level == 0) 1308 1267 return EIO; 1309 } 1310 1268 1311 1269 /* Compute offsets for the topmost level */ 1312 aoff64_t block_offset_in_level = iblock - fs->inode_block_limits[level-1]; 1313 uint32_t current_block = ext4_inode_get_indirect_block(inode, level-1); 1314 uint32_t offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1315 1316 /* Navigate through other levels, until we find the block number 1270 aoff64_t block_offset_in_level = 1271 iblock - fs->inode_block_limits[level - 1]; 1272 uint32_t current_block = 1273 ext4_inode_get_indirect_block(inode, level - 1); 1274 uint32_t offset_in_block = 1275 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1276 1277 /* 1278 * Navigate through other levels, until we find the block number 1317 1279 * or find null reference meaning we are dealing with sparse file 1318 1280 */ 1319 1281 block_t *block; 1320 1282 while (level > 0) { 1321 rc = block_get(&block, fs->device, current_block, 0);1322 if (rc != EOK) {1323 return rc; 1324 }1325 1326 current_block = uint32_t_le2host(((uint32_t*)block->data)[offset_in_block]);1327 1283 int rc = block_get(&block, fs->device, current_block, 0); 1284 if (rc != EOK) 1285 return rc; 1286 1287 current_block = 1288 uint32_t_le2host(((uint32_t *) block->data)[offset_in_block]); 1289 1328 1290 /* Set zero if physical data block address found */ 1329 1291 if (level == 1) { 1330 ((uint32_t*)block->data)[offset_in_block] = host2uint32_t_le(0); 1292 ((uint32_t *) block->data)[offset_in_block] = 1293 host2uint32_t_le(0); 1331 1294 block->dirty = true; 1332 1295 } 1333 1296 1334 1297 rc = block_put(block); 1335 if (rc != EOK) {1336 return rc; 1337 }1338 1339 level -= 1;1340 1341 /* If we are on the last level, break here as1298 if (rc != EOK) 1299 return rc; 1300 1301 level--; 1302 1303 /* 1304 * If we are on the last level, break here as 1342 1305 * there is no next level to visit 1343 1306 */ 1344 if (level == 0) {1307 if (level == 0) 1345 1308 break; 1346 } 1347 1309 1348 1310 /* Visit the next level */ 1349 1311 block_offset_in_level %= fs->inode_blocks_per_level[level]; 1350 offset_in_block = block_offset_in_level / fs->inode_blocks_per_level[level-1]; 1351 } 1352 1312 offset_in_block = 1313 block_offset_in_level / fs->inode_blocks_per_level[level - 1]; 1314 } 1315 1353 1316 fblock = current_block; 1354 1355 if (fblock == 0) { 1317 if (fblock == 0) 1356 1318 return EOK; 1357 } 1358 1319 1359 1320 /* Physical block is not referenced, it can be released */ 1360 1361 1321 return ext4_balloc_free_block(inode_ref, fblock); 1362 1363 1322 } 1364 1323 1365 1324 /** Append following logical block to the i-node. 1366 1325 * 1367 * @param inode_ref i-node to append block to 1368 * @param fblock output physical block address of newly allocated block 1369 * @param iblock output logical number of newly allocated block 1370 * @return error code 1326 * @param inode_ref I-node to append block to 1327 * @param fblock Output physical block address of newly allocated block 1328 * @param iblock Output logical number of newly allocated block 1329 * 1330 * @return Error code 1331 * 1371 1332 */ 1372 1333 int ext4_filesystem_append_inode_block(ext4_inode_ref_t *inode_ref, 1373 uint32_t *fblock, uint32_t *iblock) 1374 { 1375 int rc; 1376 1334 uint32_t *fblock, uint32_t *iblock) 1335 { 1377 1336 /* Handle extents separately */ 1378 if (ext4_superblock_has_feature_incompatible( 1379 inode_ref->fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 1380 ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS)) { 1381 1337 if ((ext4_superblock_has_feature_incompatible(inode_ref->fs->superblock, 1338 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 1339 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) 1382 1340 return ext4_extent_append_block(inode_ref, iblock, fblock, true); 1383 1384 } 1385 1341 1386 1342 ext4_superblock_t *sb = inode_ref->fs->superblock; 1387 1343 1388 1344 /* Compute next block index and allocate data block */ 1389 1345 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode); 1390 1346 uint32_t block_size = ext4_superblock_get_block_size(sb); 1391 1347 1392 1348 /* Align size i-node size */ 1393 if ((inode_size % block_size) != 0) {1349 if ((inode_size % block_size) != 0) 1394 1350 inode_size += block_size - (inode_size % block_size); 1395 } 1396 1351 1397 1352 /* Logical blocks are numbered from 0 */ 1398 1353 uint32_t new_block_idx = inode_size / block_size; 1399 1354 1400 1355 /* Allocate new physical block */ 1401 1356 uint32_t phys_block; 1402 rc =ext4_balloc_alloc_block(inode_ref, &phys_block);1403 if (rc != EOK) {1357 int rc = ext4_balloc_alloc_block(inode_ref, &phys_block); 1358 if (rc != EOK) 1404 1359 return rc; 1405 } 1406 1360 1407 1361 /* Add physical block address to the i-node */ 1408 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, new_block_idx, phys_block); 1362 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, 1363 new_block_idx, phys_block); 1409 1364 if (rc != EOK) { 1410 1365 ext4_balloc_free_block(inode_ref, phys_block); 1411 1366 return rc; 1412 1367 } 1413 1368 1414 1369 /* Update i-node */ 1415 1370 ext4_inode_set_size(inode_ref->inode, inode_size + block_size); 1416 1371 inode_ref->dirty = true; 1417 1372 1418 1373 *fblock = phys_block; 1419 1374 *iblock = new_block_idx; 1420 1375 1421 1376 return EOK; 1422 1377 } … … 1424 1379 /** 1425 1380 * @} 1426 */ 1381 */ -
uspace/lib/ext4/libext4_filesystem.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_FILESYSTEM_H_ … … 37 37 #include "libext4_types.h" 38 38 39 extern int ext4_filesystem_init(ext4_filesystem_t *, 40 service_id_t,enum cache_mode);41 extern int ext4_filesystem_fini(ext4_filesystem_t * fs);42 extern int ext4_filesystem_check_sanity(ext4_filesystem_t * fs);39 extern int ext4_filesystem_init(ext4_filesystem_t *, service_id_t, 40 enum cache_mode); 41 extern int ext4_filesystem_fini(ext4_filesystem_t *); 42 extern int ext4_filesystem_check_sanity(ext4_filesystem_t *); 43 43 extern int ext4_filesystem_check_features(ext4_filesystem_t *, bool *); 44 44 extern uint32_t ext4_filesystem_blockaddr2_index_in_group(ext4_superblock_t *, 45 uint32_t);45 uint32_t); 46 46 extern uint32_t ext4_filesystem_index_in_group2blockaddr(ext4_superblock_t *, 47 uint32_t, uint32_t);47 uint32_t, uint32_t); 48 48 extern int ext4_filesystem_get_block_group_ref(ext4_filesystem_t *, uint32_t, 49 49 ext4_block_group_ref_t **); 50 50 extern int ext4_filesystem_put_block_group_ref(ext4_block_group_ref_t *); 51 51 extern int ext4_filesystem_get_inode_ref(ext4_filesystem_t *, uint32_t, 52 ext4_inode_ref_t **);52 ext4_inode_ref_t **); 53 53 extern int ext4_filesystem_put_inode_ref(ext4_inode_ref_t *); 54 extern int ext4_filesystem_alloc_inode(ext4_filesystem_t *, 55 ext4_inode_ref_t **,int);54 extern int ext4_filesystem_alloc_inode(ext4_filesystem_t *, ext4_inode_ref_t **, 55 int); 56 56 extern int ext4_filesystem_free_inode(ext4_inode_ref_t *); 57 57 extern int ext4_filesystem_truncate_inode(ext4_inode_ref_t *, aoff64_t); 58 58 extern int ext4_filesystem_get_inode_data_block_index(ext4_inode_ref_t *, 59 aoff64_t iblock, uint32_t *);59 aoff64_t iblock, uint32_t *); 60 60 extern int ext4_filesystem_set_inode_data_block_index(ext4_inode_ref_t *, 61 aoff64_t, uint32_t); 62 extern int ext4_filesystem_release_inode_block( 63 ext4_inode_ref_t *, uint32_t); 64 extern int ext4_filesystem_append_inode_block(ext4_inode_ref_t *, 65 uint32_t *, uint32_t *); 61 aoff64_t, uint32_t); 62 extern int ext4_filesystem_release_inode_block(ext4_inode_ref_t *, uint32_t); 63 extern int ext4_filesystem_append_inode_block(ext4_inode_ref_t *, uint32_t *, 64 uint32_t *); 66 65 67 66 #endif -
uspace/lib/ext4/libext4_hash.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_hash.c35 * @brief Hashing algorithms for ext4 HTree.33 * @file libext4_hash.c 34 * @brief Hashing algorithms for ext4 HTree. 36 35 */ 37 36 38 37 #include <errno.h> 39 38 #include <mem.h> 40 41 39 #include "libext4.h" 42 40 43 #define TEA_DELTA 0x9E3779B9 44 41 #define TEA_DELTA 0x9E3779B9 45 42 46 43 /* F, G and H are basic MD4 functions: selection, majority, parity */ 47 #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) 48 #define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) 49 #define H(x, y, z) ((x) ^ (y) ^ (z)) 50 44 #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) 45 #define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) 46 #define H(x, y, z) ((x) ^ (y) ^ (z)) 51 47 52 48 /* … … 56 52 * Rotation is separate from addition to prevent recomputation 57 53 */ 58 #define ROUND(f, a, b, c, d, x, s) \59 (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))60 #define K1 0 61 #define K 2 013240474631UL62 #define K 3 015666365641UL63 54 #define ROUND(f, a, b, c, d, x, s) \ 55 (a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s))) 56 57 #define K1 0 58 #define K2 013240474631UL 59 #define K3 015666365641UL 64 60 65 61 static void tea_transform(uint32_t buf[4], uint32_t const in[]) 66 62 { 67 63 uint32_t sum = 0; 68 uint32_t b0 = buf[0], b1 = buf[1]; 69 uint32_t a = in[0], b = in[1], c = in[2], d = in[3]; 64 uint32_t b0 = buf[0]; 65 uint32_t b1 = buf[1]; 66 uint32_t a = in[0]; 67 uint32_t b = in[1]; 68 uint32_t c = in[2]; 69 uint32_t d = in[3]; 70 70 71 int n = 16; 71 72 72 73 do { 73 74 sum += TEA_DELTA; 74 b0 += ((b1 << 4) +a) ^ (b1+sum) ^ ((b1 >> 5)+b);75 b1 += ((b0 << 4) +c) ^ (b0+sum) ^ ((b0 >> 5)+d);75 b0 += ((b1 << 4) + a) ^ (b1 + sum) ^ ((b1 >> 5) + b); 76 b1 += ((b0 << 4) + c) ^ (b0 + sum) ^ ((b0 >> 5) + d); 76 77 } while (--n); 77 78 78 79 buf[0] += b0; 79 80 buf[1] += b1; … … 84 85 { 85 86 uint32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3]; 86 87 87 88 /* Round 1 */ 88 89 ROUND(F, a, b, c, d, in[0] + K1, 3); … … 94 95 ROUND(F, c, d, a, b, in[6] + K1, 11); 95 96 ROUND(F, b, c, d, a, in[7] + K1, 19); 96 97 97 98 /* Round 2 */ 98 99 ROUND(G, a, b, c, d, in[1] + K2, 3); … … 104 105 ROUND(G, c, d, a, b, in[4] + K2, 9); 105 106 ROUND(G, b, c, d, a, in[6] + K2, 13); 106 107 107 108 /* Round 3 */ 108 109 ROUND(H, a, b, c, d, in[3] + K3, 3); … … 114 115 ROUND(H, c, d, a, b, in[0] + K3, 11); 115 116 ROUND(H, b, c, d, a, in[4] + K3, 15); 116 117 117 118 buf[0] += a; 118 119 buf[1] += b; 119 120 buf[2] += c; 120 121 buf[3] += d; 121 122 122 } 123 123 124 124 static uint32_t hash_unsigned(const char *name, int len) 125 125 { 126 uint32_t hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; 126 uint32_t hash; 127 uint32_t hash0 = 0x12a3fe2d; 128 uint32_t hash1 = 0x37abe8f9; 127 129 const unsigned char *ucp = (const unsigned char *) name; 128 130 129 131 while (len--) { 130 132 hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373)); 131 132 if (hash & 0x80000000) {133 134 if (hash & 0x80000000) 133 135 hash -= 0x7fffffff; 134 }136 135 137 hash1 = hash0; 136 138 hash0 = hash; 137 139 } 140 138 141 return hash0 << 1; 139 142 } … … 141 144 static uint32_t hash_signed(const char *name, int len) 142 145 { 143 uint32_t hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; 146 uint32_t hash; 147 uint32_t hash0 = 0x12a3fe2d; 148 uint32_t hash1 = 0x37abe8f9; 144 149 const signed char *scp = (const signed char *) name; 145 150 146 151 while (len--) { 147 152 hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373)); 148 149 if (hash & 0x80000000) {153 154 if (hash & 0x80000000) 150 155 hash -= 0x7fffffff; 151 }156 152 157 hash1 = hash0; 153 158 hash0 = hash; 154 159 } 160 155 161 return hash0 << 1; 156 162 } … … 161 167 int i; 162 168 const signed char *scp = (const signed char *) msg; 163 164 pad = (uint32_t) len | ((uint32_t)len << 8);169 170 pad = (uint32_t) len | ((uint32_t) len << 8); 165 171 pad |= pad << 16; 166 172 167 173 val = pad; 168 if (len > num *4) {174 if (len > num * 4) 169 175 len = num * 4; 170 } 171 176 172 177 for (i = 0; i < len; i++) { 173 if ((i % 4) == 0) {178 if ((i % 4) == 0) 174 179 val = pad; 175 }180 176 181 val = ((int) scp[i]) + (val << 8); 177 182 if ((i % 4) == 3) { … … 181 186 } 182 187 } 183 184 if (--num >= 0) {188 189 if (--num >= 0) 185 190 *buf++ = val; 186 } 187 188 while (--num >= 0) { 191 192 while (--num >= 0) 189 193 *buf++ = pad; 190 } 191 } 192 193 194 static void str2hashbuf_unsigned(const char *msg, int len, uint32_t *buf, int num) 194 } 195 196 static void str2hashbuf_unsigned(const char *msg, int len, uint32_t *buf, 197 int num) 195 198 { 196 199 uint32_t pad, val; 197 200 int i; 198 201 const unsigned char *ucp = (const unsigned char *) msg; 199 200 pad = (uint32_t) len | ((uint32_t)len << 8);202 203 pad = (uint32_t) len | ((uint32_t) len << 8); 201 204 pad |= pad << 16; 202 205 203 206 val = pad; 204 if (len > num*4) { 205 len = num * 4; 206 } 207 207 if (len > num * 4) 208 len = num * 4; 209 208 210 for (i = 0; i < len; i++) { 209 if ((i % 4) == 0) {211 if ((i % 4) == 0) 210 212 val = pad; 211 }213 212 214 val = ((int) ucp[i]) + (val << 8); 213 215 if ((i % 4) == 3) { … … 217 219 } 218 220 } 219 220 if (--num >= 0) {221 222 if (--num >= 0) 221 223 *buf++ = val; 222 } 223 224 while (--num >= 0) { 224 225 while (--num >= 0) 225 226 *buf++ = pad; 226 } 227 } 228 227 } 229 228 230 229 /** Compute hash value of the string. 231 230 * 232 * @param hinfo hash info structure with information about 233 * the algorithm, hash seed and with the place 234 * for the output hash value 235 * @param len length of the name 236 * @param name name to be hashed 237 * @return error code 231 * @param hinfo Hash info structure with information about 232 * the algorithm, hash seed and with the place 233 * for the output hash value 234 * @param len Length of the name 235 * @param name Name to be hashed 236 * 237 * @return Error code 238 * 238 239 */ 239 240 int ext4_hash_string(ext4_hash_info_t *hinfo, int len, const char *name) … … 242 243 uint32_t minor_hash = 0; 243 244 const char *p; 244 int i; 245 uint32_t in[8], buf[4]; 246 void (*str2hashbuf)(const char *, int, uint32_t *, int) = str2hashbuf_signed; 247 248 /* Initialize the default seed for the hash checksum functions */ 245 int i; 246 uint32_t in[8], buf[4]; 247 void (*str2hashbuf)(const char *, int, uint32_t *, int) = 248 str2hashbuf_signed; 249 250 /* Initialize the default seed for the hash checksum functions */ 249 251 buf[0] = 0x67452301; 250 252 buf[1] = 0xefcdab89; 251 253 buf[2] = 0x98badcfe; 252 254 buf[3] = 0x10325476; 253 254 /* Check if the seed is all zero's */255 256 /* Check if the seed is all zero's */ 255 257 if (hinfo->seed) { 256 258 for (i = 0; i < 4; i++) { 257 if (hinfo->seed[i] != 0) { 258 break; 259 } 260 } 261 if (i < 4) { 259 if (hinfo->seed[i] != 0) 260 break; 261 262 } 263 264 if (i < 4) 262 265 memcpy(buf, hinfo->seed, sizeof(buf)); 263 } 264 } 265 266 } 267 266 268 switch (hinfo->hash_version) { 267 case EXT4_HASH_VERSION_LEGACY_UNSIGNED: 268 hash = hash_unsigned(name, len); 269 break; 270 271 case EXT4_HASH_VERSION_LEGACY: 272 hash = hash_signed(name, len); 273 break; 274 275 276 case EXT4_HASH_VERSION_HALF_MD4_UNSIGNED: 277 str2hashbuf = str2hashbuf_unsigned; 278 279 case EXT4_HASH_VERSION_HALF_MD4: 280 p = name; 281 while (len > 0) { 282 (*str2hashbuf)(p, len, in, 8); 283 half_md4_transform(buf, in); 284 len -= 32; 285 p += 32; 286 } 287 minor_hash = buf[2]; 288 hash = buf[1]; 289 break; 290 291 292 case EXT4_HASH_VERSION_TEA_UNSIGNED: 293 str2hashbuf = str2hashbuf_unsigned; 294 295 case EXT4_HASH_VERSION_TEA: 296 p = name; 297 while (len > 0) { 298 (*str2hashbuf)(p, len, in, 4); 299 tea_transform(buf, in); 300 len -= 16; 301 p += 16; 302 } 303 hash = buf[0]; 304 minor_hash = buf[1]; 305 break; 306 307 default: 308 hinfo->hash = 0; 309 return EINVAL; 310 } 311 269 case EXT4_HASH_VERSION_LEGACY_UNSIGNED: 270 hash = hash_unsigned(name, len); 271 break; 272 case EXT4_HASH_VERSION_LEGACY: 273 hash = hash_signed(name, len); 274 break; 275 case EXT4_HASH_VERSION_HALF_MD4_UNSIGNED: 276 str2hashbuf = str2hashbuf_unsigned; 277 case EXT4_HASH_VERSION_HALF_MD4: 278 p = name; 279 280 while (len > 0) { 281 (*str2hashbuf)(p, len, in, 8); 282 half_md4_transform(buf, in); 283 len -= 32; 284 p += 32; 285 } 286 287 minor_hash = buf[2]; 288 hash = buf[1]; 289 break; 290 case EXT4_HASH_VERSION_TEA_UNSIGNED: 291 str2hashbuf = str2hashbuf_unsigned; 292 case EXT4_HASH_VERSION_TEA: 293 p = name; 294 295 while (len > 0) { 296 (*str2hashbuf)(p, len, in, 4); 297 tea_transform(buf, in); 298 len -= 16; 299 p += 16; 300 } 301 302 hash = buf[0]; 303 minor_hash = buf[1]; 304 break; 305 default: 306 hinfo->hash = 0; 307 return EINVAL; 308 } 309 312 310 hash = hash & ~1; 313 if (hash == (EXT4_DIRECTORY_HTREE_EOF << 1)) { 314 hash = (EXT4_DIRECTORY_HTREE_EOF-1) << 1; 315 } 316 311 if (hash == (EXT4_DIRECTORY_HTREE_EOF << 1)) 312 hash = (EXT4_DIRECTORY_HTREE_EOF - 1) << 1; 313 317 314 hinfo->hash = hash; 318 315 hinfo->minor_hash = minor_hash; 319 316 320 317 return EOK; 321 318 } … … 323 320 /** 324 321 * @} 325 */ 322 */ -
uspace/lib/ext4/libext4_hash.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_HASH_H_ -
uspace/lib/ext4/libext4_ialloc.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_ialloc.c35 * @brief Inode (de)allocation operations.33 * @file libext4_ialloc.c 34 * @brief I-node (de)allocation operations. 36 35 */ 37 36 … … 43 42 /** Convert i-node number to relative index in block group. 44 43 * 45 * @param sb superblock 46 * @param inode i-node number to be converted 47 * @return index of the i-node in the block group 44 * @param sb Superblock 45 * @param inode I-node number to be converted 46 * 47 * @return Index of the i-node in the block group 48 * 48 49 */ 49 50 static uint32_t ext4_ialloc_inode2index_in_group(ext4_superblock_t *sb, 50 uint32_t inode)51 uint32_t inode) 51 52 { 52 53 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb); … … 56 57 /** Convert relative index of i-node to absolute i-node number. 57 58 * 58 * @param sb superblock 59 * @param inode index to be converted 60 * @return absolute number of the i-node 59 * @param sb Superblock 60 * @param inode Index to be converted 61 * 62 * @return Absolute number of the i-node 63 * 61 64 */ 62 65 static uint32_t ext4_ialloc_index_in_group2inode(ext4_superblock_t *sb, 63 uint32_t index, uint32_t bgid)66 uint32_t index, uint32_t bgid) 64 67 { 65 68 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb); … … 69 72 /** Compute block group number from the i-node number. 70 73 * 71 * @param sb superblock 72 * @param inode i-node number to be found the block group for 73 * @return block group number computed from i-node number 74 * @param sb Superblock 75 * @param inode I-node number to be found the block group for 76 * 77 * @return Block group number computed from i-node number 78 * 74 79 */ 75 80 static uint32_t ext4_ialloc_get_bgid_of_inode(ext4_superblock_t *sb, 76 uint32_t inode)81 uint32_t inode) 77 82 { 78 83 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb); 79 84 return (inode - 1) / inodes_per_group; 80 81 85 } 82 86 … … 84 88 /** Free i-node number and modify filesystem data structers. 85 89 * 86 * @param fs filesystem, where the i-node is located 87 * @param index index of i-node to be release 88 * @param is_dir flag us for information whether i-node is directory or not 90 * @param fs Filesystem, where the i-node is located 91 * @param index Index of i-node to be release 92 * @param is_dir Flag us for information whether i-node is directory or not 93 * 89 94 */ 90 95 int ext4_ialloc_free_inode(ext4_filesystem_t *fs, uint32_t index, bool is_dir) 91 96 { 92 int rc;93 94 97 ext4_superblock_t *sb = fs->superblock; 95 98 96 99 /* Compute index of block group and load it */ 97 100 uint32_t block_group = ext4_ialloc_get_bgid_of_inode(sb, index); 98 101 99 102 ext4_block_group_ref_t *bg_ref; 100 rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref); 101 if (rc != EOK) { 102 return rc; 103 } 104 103 int rc = ext4_filesystem_get_block_group_ref(fs, block_group, &bg_ref); 104 if (rc != EOK) 105 return rc; 106 105 107 /* Load i-node bitmap */ 106 108 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap( 107 bg_ref->block_group, sb);109 bg_ref->block_group, sb); 108 110 block_t *bitmap_block; 109 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, BLOCK_FLAGS_NONE);110 if (rc != EOK) {111 return rc;112 }113 111 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 112 BLOCK_FLAGS_NONE); 113 if (rc != EOK) 114 return rc; 115 114 116 /* Free i-node in the bitmap */ 115 117 uint32_t index_in_group = ext4_ialloc_inode2index_in_group(sb, index); 116 118 ext4_bitmap_free_bit(bitmap_block->data, index_in_group); 117 119 bitmap_block->dirty = true; 118 120 119 121 /* Put back the block with bitmap */ 120 122 rc = block_put(bitmap_block); … … 124 126 return rc; 125 127 } 126 128 127 129 /* If released i-node is a directory, decrement used directories count */ 128 130 if (is_dir) { 129 131 uint32_t bg_used_dirs = ext4_block_group_get_used_dirs_count( 130 bg_ref->block_group, sb);132 bg_ref->block_group, sb); 131 133 bg_used_dirs--; 132 ext4_block_group_set_used_dirs_count( 133 bg_ref->block_group, sb,bg_used_dirs);134 ext4_block_group_set_used_dirs_count(bg_ref->block_group, sb, 135 bg_used_dirs); 134 136 } 135 137 136 138 /* Update block group free inodes count */ 137 139 uint32_t free_inodes = ext4_block_group_get_free_inodes_count( 138 bg_ref->block_group, sb);140 bg_ref->block_group, sb); 139 141 free_inodes++; 140 ext4_block_group_set_free_inodes_count(bg_ref->block_group, 141 sb,free_inodes);142 142 ext4_block_group_set_free_inodes_count(bg_ref->block_group, sb, 143 free_inodes); 144 143 145 bg_ref->dirty = true; 144 146 145 147 /* Put back the modified block group */ 146 148 rc = ext4_filesystem_put_block_group_ref(bg_ref); 147 if (rc != EOK) { 148 return rc; 149 } 150 149 if (rc != EOK) 150 return rc; 151 151 152 /* Update superblock free inodes count */ 152 uint32_t sb_free_inodes = ext4_superblock_get_free_inodes_count(sb); 153 uint32_t sb_free_inodes = 154 ext4_superblock_get_free_inodes_count(sb); 153 155 sb_free_inodes++; 154 156 ext4_superblock_set_free_inodes_count(sb, sb_free_inodes); 155 157 156 158 return EOK; 157 159 } … … 159 161 /** I-node allocation algorithm. 160 162 * 161 * This is more simple algorithm, than Orlov allocator used in the Linux kernel 162 * 163 * @param fs filesystem to allocate i-node on 164 * @param index output value - allocated i-node number 165 * @param is_dir flag if allocated i-node will be file or directory 166 * @return error code 163 * This is more simple algorithm, than Orlov allocator used 164 * in the Linux kernel. 165 * 166 * @param fs Filesystem to allocate i-node on 167 * @param index Output value - allocated i-node number 168 * @param is_dir Flag if allocated i-node will be file or directory 169 * 170 * @return Error code 171 * 167 172 */ 168 173 int ext4_ialloc_alloc_inode(ext4_filesystem_t *fs, uint32_t *index, bool is_dir) 169 174 { 170 int rc;171 172 175 ext4_superblock_t *sb = fs->superblock; 173 176 174 177 uint32_t bgid = 0; 175 178 uint32_t bg_count = ext4_superblock_get_block_group_count(sb); 176 179 uint32_t sb_free_inodes = ext4_superblock_get_free_inodes_count(sb); 177 180 uint32_t avg_free_inodes = sb_free_inodes / bg_count; 178 181 179 182 /* Try to find free i-node in all block groups */ 180 183 while (bgid < bg_count) { 181 182 184 /* Load block group to check */ 183 185 ext4_block_group_ref_t *bg_ref; 184 rc = ext4_filesystem_get_block_group_ref(fs, bgid, &bg_ref);185 if (rc != EOK) {186 int rc = ext4_filesystem_get_block_group_ref(fs, bgid, &bg_ref); 187 if (rc != EOK) 186 188 return rc; 187 } 188 189 189 190 ext4_block_group_t *bg = bg_ref->block_group; 190 191 191 192 /* Read necessary values for algorithm */ 192 193 uint32_t free_blocks = ext4_block_group_get_free_blocks_count(bg, sb); 193 194 uint32_t free_inodes = ext4_block_group_get_free_inodes_count(bg, sb); 194 195 uint32_t used_dirs = ext4_block_group_get_used_dirs_count(bg, sb); 195 196 196 197 /* Check if this block group is good candidate for allocation */ 197 198 if ((free_inodes >= avg_free_inodes) && (free_blocks > 0)) { 198 199 199 /* Load block with bitmap */ 200 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap(201 bg_ref->block_group, sb);202 200 uint32_t bitmap_block_addr = ext4_block_group_get_inode_bitmap( 201 bg_ref->block_group, sb); 202 203 203 block_t *bitmap_block; 204 rc = block_get(&bitmap_block, fs->device, 205 bitmap_block_addr,BLOCK_FLAGS_NONE);206 if (rc != EOK) {204 rc = block_get(&bitmap_block, fs->device, bitmap_block_addr, 205 BLOCK_FLAGS_NONE); 206 if (rc != EOK) 207 207 return rc; 208 } 209 208 210 209 /* Try to allocate i-node in the bitmap */ 211 210 uint32_t inodes_in_group = ext4_superblock_get_inodes_in_group(sb, bgid); 212 211 uint32_t index_in_group; 213 rc = ext4_bitmap_find_free_bit_and_set( 214 bitmap_block->data,0, &index_in_group, inodes_in_group);215 212 rc = ext4_bitmap_find_free_bit_and_set(bitmap_block->data, 213 0, &index_in_group, inodes_in_group); 214 216 215 /* Block group has not any free i-node */ 217 216 if (rc == ENOSPC) { … … 220 219 continue; 221 220 } 222 221 223 222 /* Free i-node found, save the bitmap */ 224 223 bitmap_block->dirty = true; 225 224 226 225 rc = block_put(bitmap_block); 227 if (rc != EOK) {226 if (rc != EOK) 228 227 return rc; 229 } 230 228 231 229 /* Modify filesystem counters */ 232 230 free_inodes--; 233 231 ext4_block_group_set_free_inodes_count(bg, sb, free_inodes); 234 232 235 233 /* Increment used directories counter */ 236 234 if (is_dir) { … … 238 236 ext4_block_group_set_used_dirs_count(bg, sb, used_dirs); 239 237 } 240 238 241 239 /* Decrease unused inodes count */ 242 240 if (ext4_block_group_has_flag(bg, 243 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) { 244 241 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) { 245 242 uint32_t unused = 246 ext4_block_group_get_itable_unused(bg, sb);247 243 ext4_block_group_get_itable_unused(bg, sb); 244 248 245 uint32_t inodes_in_group = 249 ext4_superblock_get_inodes_in_group(sb, bgid);250 246 ext4_superblock_get_inodes_in_group(sb, bgid); 247 251 248 uint32_t free = inodes_in_group - unused; 252 249 253 250 if (index_in_group >= free) { 254 251 unused = inodes_in_group - (index_in_group + 1); 255 256 252 ext4_block_group_set_itable_unused(bg, sb, unused); 257 253 } 258 254 } 259 255 260 256 /* Save modified block group */ 261 257 bg_ref->dirty = true; 262 258 263 259 rc = ext4_filesystem_put_block_group_ref(bg_ref); 264 if (rc != EOK) {260 if (rc != EOK) 265 261 return rc; 266 } 267 262 268 263 /* Update superblock */ 269 264 sb_free_inodes--; 270 265 ext4_superblock_set_free_inodes_count(sb, sb_free_inodes); 271 266 272 267 /* Compute the absolute i-nodex number */ 273 268 *index = ext4_ialloc_index_in_group2inode(sb, index_in_group, bgid); 274 269 275 270 return EOK; 276 277 271 } 278 272 279 273 /* Block group not modified, put it and jump to the next block group */ 280 274 ext4_filesystem_put_block_group_ref(bg_ref); 281 275 ++bgid; 282 276 } 283 277 284 278 return ENOSPC; 285 279 } … … 287 281 /** 288 282 * @} 289 */ 283 */ -
uspace/lib/ext4/libext4_ialloc.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_IALLOC_H_ … … 38 38 extern int ext4_ialloc_free_inode(ext4_filesystem_t *, uint32_t, bool); 39 39 extern int ext4_ialloc_alloc_inode(ext4_filesystem_t *, uint32_t *, bool); 40 40 41 #endif 41 42 -
uspace/lib/ext4/libext4_inode.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file libext4_inode.c35 * @brief Ext4 inode structure operations.33 * @file libext4_inode.c 34 * @brief Ext4 i-node structure operations. 36 35 */ 37 36 … … 43 42 /** Compute number of bits for block count. 44 43 * 45 * @param block_size filesystem block_size 46 * @return number of bits 44 * @param block_size Filesystem block_size 45 * 46 * @return Number of bits 47 * 47 48 */ 48 49 static uint32_t ext4_inode_block_bits_count(uint32_t block_size) … … 50 51 uint32_t bits = 8; 51 52 uint32_t size = block_size; 52 53 53 54 do { 54 55 bits++; 55 56 size = size >> 1; 56 57 } while (size > 256); 57 58 58 59 return bits; 59 60 } … … 61 62 /** Get mode of the i-node. 62 63 * 63 * @param sb superblock 64 * @param inode i-node to load mode from 65 * @return mode of the i-node 64 * @param sb Superblock 65 * @param inode I-node to load mode from 66 * 67 * @return Mode of the i-node 68 * 66 69 */ 67 70 uint32_t ext4_inode_get_mode(ext4_superblock_t *sb, ext4_inode_t *inode) 68 71 { 69 72 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD) { 70 return ((uint32_t) uint16_t_le2host(inode->osd2.hurd2.mode_high)) << 16 |71 ((uint32_t) uint16_t_le2host(inode->mode));73 return ((uint32_t) uint16_t_le2host(inode->osd2.hurd2.mode_high)) << 16 | 74 ((uint32_t) uint16_t_le2host(inode->mode)); 72 75 } 76 73 77 return uint16_t_le2host(inode->mode); 74 78 } … … 76 80 /** Set mode of the i-node. 77 81 * 78 * @param sb superblock 79 * @param inode i-node to set mode to 80 * @param mode mode to set to i-node 82 * @param sb Superblock 83 * @param inode I-node to set mode to 84 * @param mode Mode to set to i-node 85 * 81 86 */ 82 87 void ext4_inode_set_mode(ext4_superblock_t *sb, ext4_inode_t *inode, uint32_t mode) 83 88 { 84 89 inode->mode = host2uint16_t_le((mode << 16) >> 16); 85 86 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD) {90 91 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_HURD) 87 92 inode->osd2.hurd2.mode_high = host2uint16_t_le(mode >> 16); 88 }89 93 } 90 94 91 95 /** Get ID of the i-node owner (user id). 92 96 * 93 * @param inode i-node to load uid from 94 * @return user ID of the i-node owner 97 * @param inode I-node to load uid from 98 * 99 * @return User ID of the i-node owner 100 * 95 101 */ 96 102 uint32_t ext4_inode_get_uid(ext4_inode_t *inode) … … 101 107 /** Set ID of the i-node owner. 102 108 * 103 * @param inode i-node to set uid to 104 * @param uid ID of the i-node owner 109 * @param inode I-node to set uid to 110 * @param uid ID of the i-node owner 111 * 105 112 */ 106 113 void ext4_inode_set_uid(ext4_inode_t *inode, uint32_t uid) … … 111 118 /** Get real i-node size. 112 119 * 113 * @param sb superblock 114 * @param inode i-node to load size from 115 * @return real size of i-node 120 * @param sb Superblock 121 * @param inode I-node to load size from 122 * 123 * @return Real size of i-node 124 * 116 125 */ 117 126 uint64_t ext4_inode_get_size(ext4_superblock_t *sb, ext4_inode_t *inode) 118 127 { 119 128 uint32_t major_rev = ext4_superblock_get_rev_level(sb); 120 121 if ((major_rev > 0) && ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) { 129 130 if ((major_rev > 0) && 131 (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE))) 122 132 return ((uint64_t)uint32_t_le2host(inode->size_hi)) << 32 | 123 ((uint64_t)uint32_t_le2host(inode->size_lo));124 }133 ((uint64_t)uint32_t_le2host(inode->size_lo)); 134 125 135 return uint32_t_le2host(inode->size_lo); 126 136 } … … 128 138 /** Set real i-node size. 129 139 * 130 * @param inode inode to set size to 131 * @param size size of the i-node 132 */ 133 void ext4_inode_set_size(ext4_inode_t *inode, uint64_t size) { 140 * @param inode I-node to set size to 141 * @param size Size of the i-node 142 * 143 */ 144 void ext4_inode_set_size(ext4_inode_t *inode, uint64_t size) 145 { 134 146 inode->size_lo = host2uint32_t_le((size << 32) >> 32); 135 147 inode->size_hi = host2uint32_t_le(size >> 32); … … 138 150 /** Get time, when i-node was last accessed. 139 151 * 140 * @param inode i-node 141 * @return time of the last access (POSIX) 152 * @param inode I-node 153 * 154 * @return Time of the last access (POSIX) 155 * 142 156 */ 143 157 uint32_t ext4_inode_get_access_time(ext4_inode_t *inode) … … 148 162 /** Set time, when i-node was last accessed. 149 163 * 150 * @param inode i-node 151 * @param time time of the last access (POSIX) 164 * @param inode I-node 165 * @param time Time of the last access (POSIX) 166 * 152 167 */ 153 168 void ext4_inode_set_access_time(ext4_inode_t *inode, uint32_t time) … … 158 173 /** Get time, when i-node was last changed. 159 174 * 160 * @param inode i-node 161 * @return time of the last change (POSIX) 175 * @param inode I-node 176 * 177 * @return Time of the last change (POSIX) 178 * 162 179 */ 163 180 uint32_t ext4_inode_get_change_inode_time(ext4_inode_t *inode) … … 168 185 /** Set time, when i-node was last changed. 169 186 * 170 * @param inode i-node 171 * @param time time of the last change (POSIX) 187 * @param inode I-node 188 * @param time Time of the last change (POSIX) 189 * 172 190 */ 173 191 void ext4_inode_set_change_inode_time(ext4_inode_t *inode, uint32_t time) … … 178 196 /** Get time, when i-node content was last modified. 179 197 * 180 * @param inode i-node 181 * @return time of the last content modification (POSIX) 198 * @param inode I-node 199 * 200 * @return Time of the last content modification (POSIX) 201 * 182 202 */ 183 203 uint32_t ext4_inode_get_modification_time(ext4_inode_t *inode) … … 188 208 /** Set time, when i-node content was last modified. 189 209 * 190 * @param inode i-node 191 * @param time time of the last content modification (POSIX) 210 * @param inode I-node 211 * @param time Time of the last content modification (POSIX) 212 * 192 213 */ 193 214 void ext4_inode_set_modification_time(ext4_inode_t *inode, uint32_t time) … … 198 219 /** Get time, when i-node was deleted. 199 220 * 200 * @param inode i-node 201 * @return time of the delete action (POSIX) 221 * @param inode I-node 222 * 223 * @return Time of the delete action (POSIX) 224 * 202 225 */ 203 226 uint32_t ext4_inode_get_deletion_time(ext4_inode_t *inode) … … 208 231 /** Set time, when i-node was deleted. 209 232 * 210 * @param inode i-node 211 * @param time time of the delete action (POSIX) 233 * @param inode I-node 234 * @param time Time of the delete action (POSIX) 235 * 212 236 */ 213 237 void ext4_inode_set_deletion_time(ext4_inode_t *inode, uint32_t time) … … 218 242 /** Get ID of the i-node owner's group. 219 243 * 220 * @param inode i-node to load gid from 221 * @return group ID of the i-node owner 244 * @param inode I-node to load gid from 245 * 246 * @return Group ID of the i-node owner 247 * 222 248 */ 223 249 uint32_t ext4_inode_get_gid(ext4_inode_t *inode) … … 228 254 /** Set ID ot the i-node owner's group. 229 255 * 230 * @param inode i-node to set gid to 231 * @param gid group ID of the i-node owner 256 * @param inode I-node to set gid to 257 * @param gid Group ID of the i-node owner 258 * 232 259 */ 233 260 void ext4_inode_set_gid(ext4_inode_t *inode, uint32_t gid) … … 238 265 /** Get number of links to i-node. 239 266 * 240 * @param inode i-node to load number of links from 241 * @return number of links to i-node 267 * @param inode I-node to load number of links from 268 * 269 * @return Number of links to i-node 270 * 242 271 */ 243 272 uint16_t ext4_inode_get_links_count(ext4_inode_t *inode) … … 248 277 /** Set number of links to i-node. 249 278 * 250 * @param inode i-node to set number of links to 251 * @param count number of links to i-node 279 * @param inode I-node to set number of links to 280 * @param count Number of links to i-node 281 * 252 282 */ 253 283 void ext4_inode_set_links_count(ext4_inode_t *inode, uint16_t count) … … 258 288 /** Get number of 512-bytes blocks used for i-node. 259 289 * 260 * @param sb superblock 261 * @param inode i-node 262 * @return number of 512-bytes blocks 290 * @param sb Superblock 291 * @param inode I-node 292 * 293 * @return Number of 512-bytes blocks 294 * 263 295 */ 264 296 uint64_t ext4_inode_get_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode) 265 297 { 266 if (ext4_superblock_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {267 298 if (ext4_superblock_has_feature_read_only(sb, 299 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { 268 300 /* 48-bit field */ 269 uint64_t count = ((uint64_t)uint16_t_le2host(inode->osd2.linux2.blocks_high)) << 32 | 270 uint32_t_le2host(inode->blocks_count_lo); 271 301 uint64_t count = ((uint64_t) 302 uint16_t_le2host(inode->osd2.linux2.blocks_high)) << 32 | 303 uint32_t_le2host(inode->blocks_count_lo); 304 272 305 if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_HUGE_FILE)) { 273 uint32_t block_size = ext4_superblock_get_block_size(sb);274 uint32_t block_bits = ext4_inode_block_bits_count(block_size);275 return count << (block_bits - 9);276 } else {306 uint32_t block_size = ext4_superblock_get_block_size(sb); 307 uint32_t block_bits = ext4_inode_block_bits_count(block_size); 308 return count << (block_bits - 9); 309 } else 277 310 return count; 278 } 311 } else 312 return uint32_t_le2host(inode->blocks_count_lo); 313 } 314 315 /** Set number of 512-bytes blocks used for i-node. 316 * 317 * @param sb Superblock 318 * @param inode I-node 319 * @param count Number of 512-bytes blocks 320 * 321 * @return Error code 322 * 323 */ 324 int ext4_inode_set_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode, 325 uint64_t count) 326 { 327 /* 32-bit maximum */ 328 uint64_t max = 0; 329 max = ~max >> 32; 330 331 if (count <= max) { 332 inode->blocks_count_lo = host2uint32_t_le(count); 333 inode->osd2.linux2.blocks_high = 0; 334 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE); 335 336 return EOK; 337 } 338 339 /* Check if there can be used huge files (many blocks) */ 340 if (!ext4_superblock_has_feature_read_only(sb, 341 EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) 342 return EINVAL; 343 344 /* 48-bit maximum */ 345 max = 0; 346 max = ~max >> 16; 347 348 if (count <= max) { 349 inode->blocks_count_lo = host2uint32_t_le(count); 350 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32); 351 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE); 279 352 } else { 280 return uint32_t_le2host(inode->blocks_count_lo); 281 } 282 } 283 284 /** Set number of 512-bytes blocks used for i-node. 285 * 286 * @param sb superblock 287 * @param inode i-node 288 * @param count number of 512-bytes blocks 289 * @return error code 290 */ 291 int ext4_inode_set_blocks_count(ext4_superblock_t *sb, ext4_inode_t *inode, 292 uint64_t count) 293 { 294 /* 32-bit maximum */ 295 uint64_t max = 0; 296 max = ~max >> 32; 297 298 if (count <= max) { 299 inode->blocks_count_lo = host2uint32_t_le(count); 300 inode->osd2.linux2.blocks_high = 0; 301 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE); 302 return EOK; 303 } 304 305 /* Check if there can be used huge files (many blocks) */ 306 if (!ext4_superblock_has_feature_read_only(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) { 307 return EINVAL; 308 } 309 310 /* 48-bit maximum */ 311 max = 0; 312 max = ~max >> 16; 313 314 if (count <= max) { 315 inode->blocks_count_lo = host2uint32_t_le(count); 316 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32); 317 ext4_inode_clear_flag(inode, EXT4_INODE_FLAG_HUGE_FILE); 318 } else { 319 uint32_t block_size = ext4_superblock_get_block_size(sb); 320 uint32_t block_bits = ext4_inode_block_bits_count(block_size); 321 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE); 322 count = count >> (block_bits - 9); 323 inode->blocks_count_lo = host2uint32_t_le(count); 324 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32); 325 } 326 return EOK; 353 uint32_t block_size = ext4_superblock_get_block_size(sb); 354 uint32_t block_bits = ext4_inode_block_bits_count(block_size); 355 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_HUGE_FILE); 356 count = count >> (block_bits - 9); 357 inode->blocks_count_lo = host2uint32_t_le(count); 358 inode->osd2.linux2.blocks_high = host2uint16_t_le(count >> 32); 359 } 360 361 return EOK; 327 362 } 328 363 329 364 /** Get flags (features) of i-node. 330 * 331 * @param inode i-node to get flags from 332 * @return flags (bitmap) 333 */ 334 uint32_t ext4_inode_get_flags(ext4_inode_t *inode) { 365 * 366 * @param inode I-node to get flags from 367 * 368 * @return Flags (bitmap) 369 * 370 */ 371 uint32_t ext4_inode_get_flags(ext4_inode_t *inode) 372 { 335 373 return uint32_t_le2host(inode->flags); 336 374 } … … 338 376 /** Set flags (features) of i-node. 339 377 * 340 * @param inode i-node to set flags to 341 * @param flags flags to set to i-node 342 */ 343 void ext4_inode_set_flags(ext4_inode_t *inode, uint32_t flags) { 378 * @param inode I-node to set flags to 379 * @param flags Flags to set to i-node 380 * 381 */ 382 void ext4_inode_set_flags(ext4_inode_t *inode, uint32_t flags) 383 { 344 384 inode->flags = host2uint32_t_le(flags); 345 385 } … … 347 387 /** Get file generation (used by NFS). 348 388 * 349 * @param inode i-node 350 * @return file generation 389 * @param inode I-node 390 * 391 * @return File generation 392 * 351 393 */ 352 394 uint32_t ext4_inode_get_generation(ext4_inode_t *inode) … … 357 399 /** Set file generation (used by NFS). 358 400 * 359 * @param inode i-node 360 * @param generation file generation 401 * @param inode I-node 402 * @param generation File generation 403 * 361 404 */ 362 405 void ext4_inode_set_generation(ext4_inode_t *inode, uint32_t generation) … … 367 410 /** Get address of block, where are extended attributes located. 368 411 * 369 * @param inode i-node 370 * @param sb superblock 371 * @return block address 412 * @param inode I-node 413 * @param sb Superblock 414 * 415 * @return Block address 416 * 372 417 */ 373 418 uint64_t ext4_inode_get_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb) 374 419 { 375 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX) { 376 return ((uint32_t)uint16_t_le2host(inode->osd2.linux2.file_acl_high)) << 16 | 420 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX) 421 return ((uint32_t) 422 uint16_t_le2host(inode->osd2.linux2.file_acl_high)) << 16 | 377 423 (uint32_t_le2host(inode->file_acl_lo)); 378 } 379 424 380 425 return uint32_t_le2host(inode->file_acl_lo); 381 426 } … … 383 428 /** Set address of block, where are extended attributes located. 384 429 * 385 * @param inode i-node 386 * @param sb superblock 387 * @param file_acl block address 430 * @param inode I-node 431 * @param sb Superblock 432 * @param file_acl Block address 433 * 388 434 */ 389 435 void ext4_inode_set_file_acl(ext4_inode_t *inode, ext4_superblock_t *sb, 390 uint64_t file_acl)436 uint64_t file_acl) 391 437 { 392 438 inode->file_acl_lo = host2uint32_t_le((file_acl << 32) >> 32); 393 394 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX) {439 440 if (ext4_superblock_get_creator_os(sb) == EXT4_SUPERBLOCK_OS_LINUX) 395 441 inode->osd2.linux2.file_acl_high = host2uint16_t_le(file_acl >> 32); 396 } 397 } 398 399 /***********************************************************************/ 442 } 400 443 401 444 /** Get block address of specified direct block. 402 445 * 403 * @param inode i-node to load block from 404 * @param idx index of logical block 405 * @return physical block address 446 * @param inode I-node to load block from 447 * @param idx Index of logical block 448 * 449 * @return Physical block address 450 * 406 451 */ 407 452 uint32_t ext4_inode_get_direct_block(ext4_inode_t *inode, uint32_t idx) 408 453 { 409 454 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT); 455 410 456 return uint32_t_le2host(inode->blocks[idx]); 411 457 } … … 413 459 /** Set block address of specified direct block. 414 460 * 415 * @param inode i-node to set block address to 416 * @param idx index of logical block 417 * @param fblock physical block address 461 * @param inode I-node to set block address to 462 * @param idx Index of logical block 463 * @param fblock Physical block address 464 * 418 465 */ 419 466 void ext4_inode_set_direct_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock) 420 467 { 421 468 assert(idx < EXT4_INODE_DIRECT_BLOCK_COUNT); 469 422 470 inode->blocks[idx] = host2uint32_t_le(fblock); 423 471 } … … 425 473 /** Get block address of specified indirect block. 426 474 * 427 * @param inode i-node to get block address from 428 * @param idx index of indirect block 429 * @return physical block address 475 * @param inode I-node to get block address from 476 * @param idx Index of indirect block 477 * 478 * @return Physical block address 479 * 430 480 */ 431 481 uint32_t ext4_inode_get_indirect_block(ext4_inode_t *inode, uint32_t idx) … … 436 486 /** Set block address of specified indirect block. 437 487 * 438 * @param inode i-node to set block address to 439 * @param idx index of indirect block 440 * @param fblock physical block address 441 */ 442 void ext4_inode_set_indirect_block(ext4_inode_t *inode, uint32_t idx, uint32_t fblock) 443 { 444 inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = host2uint32_t_le(fblock); 488 * @param inode I-node to set block address to 489 * @param idx Index of indirect block 490 * @param fblock Physical block address 491 * 492 */ 493 void ext4_inode_set_indirect_block(ext4_inode_t *inode, uint32_t idx, 494 uint32_t fblock) 495 { 496 inode->blocks[idx + EXT4_INODE_INDIRECT_BLOCK] = 497 host2uint32_t_le(fblock); 445 498 } 446 499 447 500 /** Check if i-node has specified type. 448 501 * 449 * @param sb superblock 450 * @param inode i-node to check type of 451 * @param type type to check 452 * @return result of check operation 453 */ 454 bool ext4_inode_is_type(ext4_superblock_t *sb, ext4_inode_t *inode, uint32_t type) 502 * @param sb Superblock 503 * @param inode I-node to check type of 504 * @param type Type to check 505 * 506 * @return Result of check operation 507 * 508 */ 509 bool ext4_inode_is_type(ext4_superblock_t *sb, ext4_inode_t *inode, 510 uint32_t type) 455 511 { 456 512 uint32_t mode = ext4_inode_get_mode(sb, inode); … … 460 516 /** Get extent header from the root of the extent tree. 461 517 * 462 * @param inode i-node to get extent header from 463 * @return pointer to extent header of the root node 518 * @param inode I-node to get extent header from 519 * 520 * @return Pointer to extent header of the root node 521 * 464 522 */ 465 523 ext4_extent_header_t * ext4_inode_get_extent_header(ext4_inode_t *inode) 466 524 { 467 return (ext4_extent_header_t *) inode->blocks;525 return (ext4_extent_header_t *) inode->blocks; 468 526 } 469 527 470 528 /** Check if i-node has specified flag. 471 529 * 472 * @param inode i-node to check flags of 473 * @param flag flag to check 474 * @return result of check operation 530 * @param inode I-node to check flags of 531 * @param flag Flag to check 532 * 533 * @return Result of check operation 534 * 475 535 */ 476 536 bool ext4_inode_has_flag(ext4_inode_t *inode, uint32_t flag) 477 537 { 478 if (ext4_inode_get_flags(inode) & flag) {538 if (ext4_inode_get_flags(inode) & flag) 479 539 return true; 480 }540 481 541 return false; 482 542 } … … 484 544 /** Remove specified flag from i-node. 485 545 * 486 * @param inode i-node to clear flag on 487 * @param clear_flag flag to be cleared 546 * @param inode I-node to clear flag on 547 * @param clear_flag Flag to be cleared 548 * 488 549 */ 489 550 void ext4_inode_clear_flag(ext4_inode_t *inode, uint32_t clear_flag) … … 496 557 /** Set specified flag to i-node. 497 558 * 498 * @param inode i-node to set flag on 499 * @param set_flag falt to be set 559 * @param inode I-node to set flag on 560 * @param set_flag Flag to be set 561 * 500 562 */ 501 563 void ext4_inode_set_flag(ext4_inode_t *inode, uint32_t set_flag) … … 508 570 /** Check if i-node can be truncated. 509 571 * 510 * @param sb superblock 511 * @param inode i-node to check 512 * @return result of the check operation 572 * @param sb Superblock 573 * @param inode I-node to check 574 * 575 * @return Result of the check operation 576 * 513 577 */ 514 578 bool ext4_inode_can_truncate(ext4_superblock_t *sb, ext4_inode_t *inode) 515 579 { 516 if (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND) 517 || ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE)) { 518 return false; 519 } 520 521 if (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE) 522 || ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY)) { 523 return true; 524 } 525 526 return false; 580 if ((ext4_inode_has_flag(inode, EXT4_INODE_FLAG_APPEND)) || 581 (ext4_inode_has_flag(inode, EXT4_INODE_FLAG_IMMUTABLE))) 582 return false; 583 584 if ((ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_FILE)) || 585 (ext4_inode_is_type(sb, inode, EXT4_INODE_MODE_DIRECTORY))) 586 return true; 587 588 return false; 527 589 } 528 590 529 591 /** 530 592 * @} 531 */ 593 */ -
uspace/lib/ext4/libext4_inode.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_INODE_H_ … … 56 56 extern uint16_t ext4_inode_get_links_count(ext4_inode_t *); 57 57 extern void ext4_inode_set_links_count(ext4_inode_t *, uint16_t); 58 extern uint64_t ext4_inode_get_blocks_count(ext4_superblock_t *, ext4_inode_t *); 59 extern int ext4_inode_set_blocks_count(ext4_superblock_t *, ext4_inode_t *, uint64_t); 58 extern uint64_t ext4_inode_get_blocks_count(ext4_superblock_t *, 59 ext4_inode_t *); 60 extern int ext4_inode_set_blocks_count(ext4_superblock_t *, ext4_inode_t *, 61 uint64_t); 60 62 extern uint32_t ext4_inode_get_flags(ext4_inode_t *); 61 63 extern void ext4_inode_set_flags(ext4_inode_t *, uint32_t); … … 63 65 extern void ext4_inode_set_generation(ext4_inode_t *, uint32_t); 64 66 extern uint64_t ext4_inode_get_file_acl(ext4_inode_t *, ext4_superblock_t *); 65 extern void ext4_inode_set_file_acl(ext4_inode_t *, ext4_superblock_t *, uint64_t); 66 /* 67 uint16_t extra_isize; 68 uint32_t ctime_extra; // Extra change time (nsec << 2 | epoch) 69 uint32_t mtime_extra; // Extra Modification time (nsec << 2 | epoch) 70 uint32_t atime_extra; // Extra Access time (nsec << 2 | epoch) 71 uint32_t crtime; // File creation time 72 uint32_t crtime_extra; // Extra file creation time (nsec << 2 | epoch) 73 uint32_t version_hi; // High 32 bits for 64-bit version 74 */ 75 76 /******************************************/ 67 extern void ext4_inode_set_file_acl(ext4_inode_t *, ext4_superblock_t *, 68 uint64_t); 77 69 78 70 extern uint32_t ext4_inode_get_direct_block(ext4_inode_t *, uint32_t); -
uspace/lib/ext4/libext4_superblock.c
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 /** 34 * @file libext4_superblock.c35 * @brief Ext4 superblock operations.34 * @file libext4_superblock.c 35 * @brief Ext4 superblock operations. 36 36 */ 37 37 … … 44 44 /** Get number of i-nodes in the whole filesystem. 45 45 * 46 * @param sb superblock 47 * @return number of i-nodes 46 * @param sb Superblock 47 * 48 * @return Number of i-nodes 49 * 48 50 */ 49 51 uint32_t ext4_superblock_get_inodes_count(ext4_superblock_t *sb) … … 54 56 /** Set number of i-nodes in the whole filesystem. 55 57 * 56 * @param sb superblock 57 * @param count number of i-nodes 58 * @param sb Superblock 59 * @param count Number of i-nodes 60 * 58 61 */ 59 62 void ext4_superblock_set_inodes_count(ext4_superblock_t *sb, uint32_t count) … … 64 67 /** Get number of data blocks in the whole filesystem. 65 68 * 66 * @param sb superblock 67 * @return number of data blocks 69 * @param sb Superblock 70 * 71 * @return Number of data blocks 72 * 68 73 */ 69 74 uint64_t ext4_superblock_get_blocks_count(ext4_superblock_t *sb) 70 75 { 71 return ((uint64_t) uint32_t_le2host(sb->blocks_count_hi) << 32) |72 uint32_t_le2host(sb->blocks_count_lo);76 return ((uint64_t) uint32_t_le2host(sb->blocks_count_hi) << 32) | 77 uint32_t_le2host(sb->blocks_count_lo); 73 78 } 74 79 75 80 /** Set number of data blocks in the whole filesystem. 76 81 * 77 * @param sb superblock 78 * @param count number of data blocks 82 * @param sb Superblock 83 * @param count Number of data blocks 84 * 79 85 */ 80 86 void ext4_superblock_set_blocks_count(ext4_superblock_t *sb, uint64_t count) … … 86 92 /** Get number of reserved data blocks in the whole filesystem. 87 93 * 88 * @param sb superblock 89 * @return number of reserved data blocks 94 * @param sb Superblock 95 * 96 * @return Number of reserved data blocks 97 * 90 98 */ 91 99 uint64_t ext4_superblock_get_reserved_blocks_count(ext4_superblock_t *sb) 92 100 { 93 return ((uint64_t)uint32_t_le2host(sb->reserved_blocks_count_hi) << 32) | 94 uint32_t_le2host(sb->reserved_blocks_count_lo); 101 return ((uint64_t) 102 uint32_t_le2host(sb->reserved_blocks_count_hi) << 32) | 103 uint32_t_le2host(sb->reserved_blocks_count_lo); 95 104 } 96 105 97 106 /** Set number of reserved data blocks in the whole filesystem. 98 107 * 99 * @param sb superblock 100 * @param count number of reserved data blocks 101 */ 102 void ext4_superblock_set_reserved_blocks_count(ext4_superblock_t *sb, uint64_t count) 108 * @param sb Superblock 109 * @param count Number of reserved data blocks 110 * 111 */ 112 void ext4_superblock_set_reserved_blocks_count(ext4_superblock_t *sb, 113 uint64_t count) 103 114 { 104 115 sb->reserved_blocks_count_lo = host2uint32_t_le((count << 32) >> 32); … … 108 119 /** Get number of free data blocks in the whole filesystem. 109 120 * 110 * @param sb superblock 111 * @return number of free data blocks 121 * @param sb Superblock 122 * 123 * @return Number of free data blocks 124 * 112 125 */ 113 126 uint64_t ext4_superblock_get_free_blocks_count(ext4_superblock_t *sb) 114 127 { 115 return ((uint64_t)uint32_t_le2host(sb->free_blocks_count_hi) << 32) | 116 uint32_t_le2host(sb->free_blocks_count_lo); 128 return ((uint64_t) 129 uint32_t_le2host(sb->free_blocks_count_hi) << 32) | 130 uint32_t_le2host(sb->free_blocks_count_lo); 117 131 } 118 132 119 133 /** Set number of free data blocks in the whole filesystem. 120 134 * 121 * @param sb superblock 122 * @param count number of free data blocks 123 */ 124 void ext4_superblock_set_free_blocks_count(ext4_superblock_t *sb, uint64_t count) 135 * @param sb Superblock 136 * @param count Number of free data blocks 137 * 138 */ 139 void ext4_superblock_set_free_blocks_count(ext4_superblock_t *sb, 140 uint64_t count) 125 141 { 126 142 sb->free_blocks_count_lo = host2uint32_t_le((count << 32) >> 32); … … 130 146 /** Get number of free i-nodes in the whole filesystem. 131 147 * 132 * @param sb superblock 133 * @return number of free i-nodes 148 * @param sb Superblock 149 * 150 * @return Number of free i-nodes 151 * 134 152 */ 135 153 uint32_t ext4_superblock_get_free_inodes_count(ext4_superblock_t *sb) … … 140 158 /** Set number of free i-nodes in the whole filesystem. 141 159 * 142 * @param sb superblock 143 * @param count number of free i-nodes 144 */ 145 void ext4_superblock_set_free_inodes_count(ext4_superblock_t *sb, uint32_t count) 160 * @param sb Superblock 161 * @param count Number of free i-nodes 162 * 163 */ 164 void ext4_superblock_set_free_inodes_count(ext4_superblock_t *sb, 165 uint32_t count) 146 166 { 147 167 sb->free_inodes_count = host2uint32_t_le(count); 148 168 } 149 169 150 /** Get index of first data block (block, where is located superblock) 151 * 152 * @param sb superblock 153 * @return index of the first data block 170 /** Get index of first data block (block where the superblock is located) 171 * 172 * @param sb Superblock 173 * 174 * @return Index of the first data block 175 * 154 176 */ 155 177 uint32_t ext4_superblock_get_first_data_block(ext4_superblock_t *sb) … … 158 180 } 159 181 160 /** Set index of first data block (block, where is located superblock) 161 * 162 * @param sb superblock 163 * @param first index of the first data block 164 */ 165 void ext4_superblock_set_first_data_block(ext4_superblock_t *sb, uint32_t first) 182 /** Set index of first data block (block where the superblock is located) 183 * 184 * @param sb Superblock 185 * @param first Index of the first data block 186 * 187 */ 188 void ext4_superblock_set_first_data_block(ext4_superblock_t *sb, 189 uint32_t first) 166 190 { 167 191 sb->first_data_block = host2uint32_t_le(first); … … 170 194 /** Get logarithmic block size (1024 << size == block_size) 171 195 * 172 * @param sb superblock 173 * @return logarithmic block size 196 * @param sb Superblock 197 * 198 * @return Logarithmic block size 199 * 174 200 */ 175 201 uint32_t ext4_superblock_get_log_block_size(ext4_superblock_t *sb) … … 180 206 /** Set logarithmic block size (1024 << size == block_size) 181 207 * 182 * @param sb superblock 183 * @return logarithmic block size 184 */ 185 void ext4_superblock_set_log_block_size(ext4_superblock_t *sb, uint32_t log_size) 208 * @param sb Superblock 209 * 210 * @return Logarithmic block size 211 * 212 */ 213 void ext4_superblock_set_log_block_size(ext4_superblock_t *sb, 214 uint32_t log_size) 186 215 { 187 216 sb->log_block_size = host2uint32_t_le(log_size); … … 190 219 /** Get size of data block (in bytes). 191 220 * 192 * @param sb superblock 193 * @return size of data block 221 * @param sb Superblock 222 * 223 * @return Size of data block 224 * 194 225 */ 195 226 uint32_t ext4_superblock_get_block_size(ext4_superblock_t *sb) … … 200 231 /** Set size of data block (in bytes). 201 232 * 202 * @param sb superblock 203 * @param size size of data block (must be power of 2, at least 1024) 233 * @param sb Superblock 234 * @param size Size of data block (must be power of 2, at least 1024) 235 * 204 236 */ 205 237 void ext4_superblock_set_block_size(ext4_superblock_t *sb, uint32_t size) … … 207 239 uint32_t log = 0; 208 240 uint32_t tmp = size / EXT4_MIN_BLOCK_SIZE; 209 241 210 242 tmp >>= 1; 211 243 while (tmp) { … … 213 245 tmp >>= 1; 214 246 } 215 247 216 248 ext4_superblock_set_log_block_size(sb, log); 217 249 } … … 219 251 /** Get logarithmic fragment size (1024 << size) 220 252 * 221 * @param sb superblock 222 * @return logarithmic fragment size 253 * @param sb Superblock 254 * 255 * @return Logarithmic fragment size 256 * 223 257 */ 224 258 uint32_t ext4_superblock_get_log_frag_size(ext4_superblock_t *sb) … … 229 263 /** Set logarithmic fragment size (1024 << size) 230 264 * 231 * @param sb superblock 232 * @return logarithmic fragment size 233 */ 234 235 void ext4_superblock_set_log_frag_size(ext4_superblock_t *sb, uint32_t frag_size) 265 * @param sb Superblock 266 * @param frag_size Logarithmic fragment size 267 * 268 */ 269 void ext4_superblock_set_log_frag_size(ext4_superblock_t *sb, 270 uint32_t frag_size) 236 271 { 237 272 sb->log_frag_size = host2uint32_t_le(frag_size); … … 240 275 /** Get size of fragment (in bytes). 241 276 * 242 * @param sb superblock 243 * @return size of fragment 277 * @param sb Superblock 278 * 279 * @return Size of fragment 280 * 244 281 */ 245 282 uint32_t ext4_superblock_get_frag_size(ext4_superblock_t *sb) … … 250 287 /** Set size of fragment (in bytes). 251 288 * 252 * @param sb superblock 253 * @param size size of fragment (must be power of 2, at least 1024) 289 * @param sb Superblock 290 * @param size Size of fragment (must be power of 2, at least 1024) 291 * 254 292 */ 255 293 void ext4_superblock_set_frag_size(ext4_superblock_t *sb, uint32_t size) … … 257 295 uint32_t log = 0; 258 296 uint32_t tmp = size / EXT4_MIN_BLOCK_SIZE; 259 297 260 298 tmp >>= 1; 261 299 while (tmp) { … … 263 301 tmp >>= 1; 264 302 } 265 303 266 304 ext4_superblock_set_log_frag_size(sb, log); 267 305 } … … 269 307 /** Get number of data blocks per block group (except last BG) 270 308 * 271 * @param sb superblock 272 * @return data blocks per block group 309 * @param sb Superblock 310 * 311 * @return Data blocks per block group 312 * 273 313 */ 274 314 uint32_t ext4_superblock_get_blocks_per_group(ext4_superblock_t *sb) … … 279 319 /** Set number of data blocks per block group (except last BG) 280 320 * 281 * @param sb superblock 282 * @param blocks data blocks per block group 283 */ 284 void ext4_superblock_set_blocks_per_group(ext4_superblock_t *sb, uint32_t blocks) 321 * @param sb Superblock 322 * @param blocks Data blocks per block group 323 * 324 */ 325 void ext4_superblock_set_blocks_per_group(ext4_superblock_t *sb, 326 uint32_t blocks) 285 327 { 286 328 sb->blocks_per_group = host2uint32_t_le(blocks); … … 289 331 /** Get number of fragments per block group (except last BG) 290 332 * 291 * @param sb superblock 292 * @return fragments per block group 333 * @param sb Superblock 334 * 335 * @return Fragments per block group 336 * 293 337 */ 294 338 uint32_t ext4_superblock_get_frags_per_group(ext4_superblock_t *sb) … … 299 343 /** Set number of fragment per block group (except last BG) 300 344 * 301 * @param sb superblock302 * @param frags fragments per block group345 * @param sb Superblock 346 * @param frags Fragments per block group 303 347 */ 304 348 void ext4_superblock_set_frags_per_group(ext4_superblock_t *sb, uint32_t frags) … … 307 351 } 308 352 309 310 353 /** Get number of i-nodes per block group (except last BG) 311 354 * 312 * @param sb superblock 313 * @return i-nodes per block group 355 * @param sb Superblock 356 * 357 * @return I-nodes per block group 358 * 314 359 */ 315 360 uint32_t ext4_superblock_get_inodes_per_group(ext4_superblock_t *sb) … … 320 365 /** Set number of i-nodes per block group (except last BG) 321 366 * 322 * @param sb superblock 323 * @param inodes i-nodes per block group 324 */ 325 void ext4_superblock_set_inodes_per_group(ext4_superblock_t *sb, uint32_t inodes) 367 * @param sb Superblock 368 * @param inodes I-nodes per block group 369 * 370 */ 371 void ext4_superblock_set_inodes_per_group(ext4_superblock_t *sb, 372 uint32_t inodes) 326 373 { 327 374 sb->inodes_per_group = host2uint32_t_le(inodes); … … 330 377 /** Get time when filesystem was mounted (POSIX time). 331 378 * 332 * @param sb superblock 333 * @return mount time 379 * @param sb Superblock 380 * 381 * @return Mount time 382 * 334 383 */ 335 384 uint32_t ext4_superblock_get_mount_time(ext4_superblock_t *sb) … … 340 389 /** Set time when filesystem was mounted (POSIX time). 341 390 * 342 * @param sb superblock 343 * @param time mount time 391 * @param sb Superblock 392 * @param time Mount time 393 * 344 394 */ 345 395 void ext4_superblock_set_mount_time(ext4_superblock_t *sb, uint32_t time) … … 350 400 /** Get time when filesystem was last accesed by write operation (POSIX time). 351 401 * 352 * @param sb superblock 353 * @return write time 402 * @param sb Superblock 403 * 404 * @return Write time 405 * 354 406 */ 355 407 uint32_t ext4_superblock_get_write_time(ext4_superblock_t *sb) … … 360 412 /** Set time when filesystem was last accesed by write operation (POSIX time). 361 413 * 362 * @param sb superblock 363 * @param time write time 414 * @param sb Superblock 415 * @param time Write time 416 * 364 417 */ 365 418 void ext4_superblock_set_write_time(ext4_superblock_t *sb, uint32_t time) … … 370 423 /** Get number of mount from last filesystem check. 371 424 * 372 * @param sb superblock 373 * @return number of mounts 425 * @param sb Superblock 426 * 427 * @return Number of mounts 428 * 374 429 */ 375 430 uint16_t ext4_superblock_get_mount_count(ext4_superblock_t *sb) … … 380 435 /** Set number of mount from last filesystem check. 381 436 * 382 * @param sb superblock 383 * @param count number of mounts 437 * @param sb Superblock 438 * @param count Number of mounts 439 * 384 440 */ 385 441 void ext4_superblock_set_mount_count(ext4_superblock_t *sb, uint16_t count) … … 390 446 /** Get maximum number of mount from last filesystem check. 391 447 * 392 * @param sb superblock 393 * @return maximum number of mounts 448 * @param sb Superblock 449 * 450 * @return Maximum number of mounts 451 * 394 452 */ 395 453 uint16_t ext4_superblock_get_max_mount_count(ext4_superblock_t *sb) … … 400 458 /** Set maximum number of mount from last filesystem check. 401 459 * 402 * @param sb superblock 403 * @param count maximum number of mounts 460 * @param sb Superblock 461 * @param count Maximum number of mounts 462 * 404 463 */ 405 464 void ext4_superblock_set_max_mount_count(ext4_superblock_t *sb, uint16_t count) … … 410 469 /** Get superblock magic value. 411 470 * 412 * @param sb superblock 413 * @return magic value 471 * @param sb Superblock 472 * 473 * @return Magic value 474 * 414 475 */ 415 476 uint16_t ext4_superblock_get_magic(ext4_superblock_t *sb) … … 420 481 /** Set superblock magic value. 421 482 * 422 * @param sb superblock 423 * @param magic value 483 * @param sb Superblock 484 * @param magic Magic value 485 * 424 486 */ 425 487 void ext4_superblock_set_magic(ext4_superblock_t *sb, uint16_t magic) … … 430 492 /** Get filesystem state. 431 493 * 432 * @param sb superblock 433 * @return filesystem state 494 * @param sb Superblock 495 * 496 * @return Filesystem state 497 * 434 498 */ 435 499 uint16_t ext4_superblock_get_state(ext4_superblock_t *sb) … … 440 504 /** Set filesystem state. 441 505 * 442 * @param sb superblock 443 * @param state filesystem state 506 * @param sb Superblock 507 * @param state Filesystem state 508 * 444 509 */ 445 510 void ext4_superblock_set_state(ext4_superblock_t *sb, uint16_t state) … … 450 515 /** Get behavior code when errors detected. 451 516 * 452 * @param sb superblock 453 * @return behavior code 517 * @param sb Superblock 518 * 519 * @return Behavior code 520 * 454 521 */ 455 522 uint16_t ext4_superblock_get_errors(ext4_superblock_t *sb) … … 460 527 /** Set behavior code when errors detected. 461 528 * 462 * @param sb superblock 463 * @param errors behavior code 529 * @param sb Superblock 530 * @param errors Behavior code 531 * 464 532 */ 465 533 void ext4_superblock_set_errors(ext4_superblock_t *sb, uint16_t errors) … … 470 538 /** Get minor revision level of the filesystem. 471 539 * 472 * @param sb superblock 473 * @return minor revision level 540 * @param sb Superblock 541 * 542 * @return Minor revision level 543 * 474 544 */ 475 545 uint16_t ext4_superblock_get_minor_rev_level(ext4_superblock_t *sb) … … 480 550 /** Set minor revision level of the filesystem. 481 551 * 482 * @param sb superblock 483 * @param level minor revision level 552 * @param sb Superblock 553 * @param level Minor revision level 554 * 484 555 */ 485 556 void ext4_superblock_set_minor_rev_level(ext4_superblock_t *sb, uint16_t level) … … 490 561 /** Get time of the last filesystem check. 491 562 * 492 * @param sb superblock 493 * @return time of the last check (POSIX) 563 * @param sb Superblock 564 * 565 * @return Time of the last check (POSIX) 566 * 494 567 */ 495 568 uint32_t ext4_superblock_get_last_check_time(ext4_superblock_t *sb) … … 500 573 /** Set time of the last filesystem check. 501 574 * 502 * @param sb superblock 503 * @param time time of the last check (POSIX) 575 * @param sb Superblock 576 * @param time Time of the last check (POSIX) 577 * 504 578 */ 505 579 void ext4_superblock_set_last_check_time(ext4_superblock_t *sb, uint32_t time) … … 510 584 /** Get maximum time interval between two filesystem checks. 511 585 * 512 * @param sb superblock 513 * @return time interval between two check (POSIX) 514 */ 515 uint32_t ext4_superblock_get_check_interval(ext4_superblock_t *sb){ 586 * @param sb Superblock 587 * 588 * @return Time interval between two check (POSIX) 589 * 590 */ 591 uint32_t ext4_superblock_get_check_interval(ext4_superblock_t *sb) 592 { 516 593 return uint32_t_le2host(sb->check_interval); 517 594 } … … 519 596 /** Set maximum time interval between two filesystem checks. 520 597 * 521 * @param sb superblock 522 * @param interval time interval between two check (POSIX) 598 * @param sb Superblock 599 * @param interval Time interval between two check (POSIX) 600 * 523 601 */ 524 602 void ext4_superblock_set_check_interval(ext4_superblock_t *sb, uint32_t interval) … … 529 607 /** Get operation system identifier, on which the filesystem was created. 530 608 * 531 * @param sb superblock 532 * @return operation system identifier 609 * @param sb Superblock 610 * 611 * @return Operation system identifier 612 * 533 613 */ 534 614 uint32_t ext4_superblock_get_creator_os(ext4_superblock_t *sb) … … 539 619 /** Set operation system identifier, on which the filesystem was created. 540 620 * 541 * @param sb superblock 542 * @param os operation system identifier 621 * @param sb Superblock 622 * @param os Operation system identifier 623 * 543 624 */ 544 625 void ext4_superblock_set_creator_os(ext4_superblock_t *sb, uint32_t os) … … 549 630 /** Get revision level of the filesystem. 550 631 * 551 * @param sb superblock 552 * @return revision level 632 * @param sb Superblock 633 * 634 * @return Revision level 635 * 553 636 */ 554 637 uint32_t ext4_superblock_get_rev_level(ext4_superblock_t *sb) … … 559 642 /** Set revision level of the filesystem. 560 643 * 561 * @param sb superblock 562 * @param level revision level 644 * @param sb Superblock 645 * @param level Revision level 646 * 563 647 */ 564 648 void ext4_superblock_set_rev_level(ext4_superblock_t *sb, uint32_t level) … … 569 653 /** Get default user id for reserved blocks. 570 654 * 571 * @param sb superblock 572 * @return default user id for reserved blocks. 655 * @param sb Superblock 656 * 657 * @return Default user id for reserved blocks. 658 * 573 659 */ 574 660 uint16_t ext4_superblock_get_def_resuid(ext4_superblock_t *sb) … … 579 665 /** Set default user id for reserved blocks. 580 666 * 581 * @param sb superblock 582 * @param uid default user id for reserved blocks. 667 * @param sb Superblock 668 * @param uid Default user id for reserved blocks. 669 * 583 670 */ 584 671 void ext4_superblock_set_def_resuid(ext4_superblock_t *sb, uint16_t uid) … … 589 676 /** Get default group id for reserved blocks. 590 677 * 591 * @param sb superblock 592 * @return default group id for reserved blocks. 678 * @param sb Superblock 679 * 680 * @return Default group id for reserved blocks. 681 * 593 682 */ 594 683 uint16_t ext4_superblock_get_def_resgid(ext4_superblock_t *sb) … … 599 688 /** Set default group id for reserved blocks. 600 689 * 601 * @param sb superblock 602 * @param gid default group id for reserved blocks. 690 * @param sb Superblock 691 * @param gid Default group id for reserved blocks. 692 * 603 693 */ 604 694 void ext4_superblock_set_def_resgid(ext4_superblock_t *sb, uint16_t gid) … … 609 699 /** Get index of the first i-node, which can be used for allocation. 610 700 * 611 * @param sb superblock 612 * @return i-node index 701 * @param sb Superblock 702 * 703 * @return I-node index 704 * 613 705 */ 614 706 uint32_t ext4_superblock_get_first_inode(ext4_superblock_t *sb) … … 619 711 /** Set index of the first i-node, which can be used for allocation. 620 712 * 621 * @param sb superblock 622 * @param first_inode i-node index 623 */ 624 void ext4_superblock_set_first_inode(ext4_superblock_t *sb, uint32_t first_inode) 713 * @param sb Superblock 714 * @param first_inode I-node index 715 * 716 */ 717 void ext4_superblock_set_first_inode(ext4_superblock_t *sb, 718 uint32_t first_inode) 625 719 { 626 720 sb->first_inode = host2uint32_t_le(first_inode); … … 631 725 * For the oldest revision return constant number. 632 726 * 633 * @param sb superblock 634 * @return size of i-node structure 727 * @param sb Superblock 728 * 729 * @return Size of i-node structure 730 * 635 731 */ 636 732 uint16_t ext4_superblock_get_inode_size(ext4_superblock_t *sb) 637 733 { 638 if (ext4_superblock_get_rev_level(sb) == 0) {734 if (ext4_superblock_get_rev_level(sb) == 0) 639 735 return EXT4_REV0_INODE_SIZE; 640 }736 641 737 return uint16_t_le2host(sb->inode_size); 642 738 } … … 644 740 /** Set size of i-node structure. 645 741 * 646 * @param sb superblock 647 * @param size size of i-node structure 742 * @param sb Superblock 743 * @param size Size of i-node structure 744 * 648 745 */ 649 746 void ext4_superblock_set_inode_size(ext4_superblock_t *sb, uint16_t size) … … 654 751 /** Get index of block group, where superblock copy is located. 655 752 * 656 * @param sb superblock 657 * @return block group index 753 * @param sb Superblock 754 * 755 * @return Block group index 756 * 658 757 */ 659 758 uint16_t ext4_superblock_get_block_group_index(ext4_superblock_t *sb) … … 664 763 /** Set index of block group, where superblock copy is located. 665 764 * 666 * @param sb superblock 667 * @param bgid block group index 765 * @param sb Superblock 766 * @param bgid Block group index 767 * 668 768 */ 669 769 void ext4_superblock_set_block_group_index(ext4_superblock_t *sb, uint16_t bgid) … … 674 774 /** Get compatible features supported by the filesystem. 675 775 * 676 * @param sb superblock 677 * @return compatible features bitmap 776 * @param sb Superblock 777 * 778 * @return Compatible features bitmap 779 * 678 780 */ 679 781 uint32_t ext4_superblock_get_features_compatible(ext4_superblock_t *sb) … … 684 786 /** Set compatible features supported by the filesystem. 685 787 * 686 * @param sb superblock 687 * @param features compatible features bitmap 688 */ 689 void ext4_superblock_set_features_compatible(ext4_superblock_t *sb, uint32_t features) 788 * @param sb Superblock 789 * @param features Compatible features bitmap 790 * 791 */ 792 void ext4_superblock_set_features_compatible(ext4_superblock_t *sb, 793 uint32_t features) 690 794 { 691 795 sb->features_compatible = host2uint32_t_le(features); … … 694 798 /** Get incompatible features supported by the filesystem. 695 799 * 696 * @param sb superblock 697 * @return incompatible features bitmap 800 * @param sb Superblock 801 * 802 * @return Incompatible features bitmap 803 * 698 804 */ 699 805 uint32_t ext4_superblock_get_features_incompatible(ext4_superblock_t *sb) … … 704 810 /** Set incompatible features supported by the filesystem. 705 811 * 706 * @param sb superblock 707 * @param features incompatible features bitmap 708 */ 709 void ext4_superblock_set_features_incompatible(ext4_superblock_t *sb, uint32_t features) 812 * @param sb Superblock 813 * @param features Incompatible features bitmap 814 * 815 */ 816 void ext4_superblock_set_features_incompatible(ext4_superblock_t *sb, 817 uint32_t features) 710 818 { 711 819 sb->features_incompatible = host2uint32_t_le(features); … … 714 822 /** Get compatible features supported by the filesystem. 715 823 * 716 * @param sb superblock 717 * @return read-only compatible features bitmap 824 * @param sb Superblock 825 * 826 * @return Read-only compatible features bitmap 827 * 718 828 */ 719 829 uint32_t ext4_superblock_get_features_read_only(ext4_superblock_t *sb) … … 724 834 /** Set compatible features supported by the filesystem. 725 835 * 726 * @param sb superblock 727 * @param feature read-only compatible features bitmap 728 */ 729 void ext4_superblock_set_features_read_only(ext4_superblock_t *sb, uint32_t features) 836 * @param sb Superblock 837 * @param feature Read-only compatible features bitmap 838 * 839 */ 840 void ext4_superblock_set_features_read_only(ext4_superblock_t *sb, 841 uint32_t features) 730 842 { 731 843 sb->features_read_only = host2uint32_t_le(features); … … 734 846 /** Get UUID of the filesystem. 735 847 * 736 * @param sb superblock 737 * @return pointer to UUID array 738 */ 739 const uint8_t * ext4_superblock_get_uuid(ext4_superblock_t *sb) 848 * @param sb superblock 849 * 850 * @return Pointer to UUID array 851 * 852 */ 853 const uint8_t *ext4_superblock_get_uuid(ext4_superblock_t *sb) 740 854 { 741 855 return sb->uuid; … … 744 858 /** Set UUID of the filesystem. 745 859 * 746 * @param sb superblock 747 * @param uuid pointer to UUID array 860 * @param sb Superblock 861 * @param uuid Pointer to UUID array 862 * 748 863 */ 749 864 void ext4_superblock_set_uuid(ext4_superblock_t *sb, const uint8_t *uuid) … … 754 869 /** Get name of the filesystem volume. 755 870 * 756 * @param sb superblock 757 * @return name of the volume 758 */ 759 const char * ext4_superblock_get_volume_name(ext4_superblock_t *sb) 871 * @param sb Superblock 872 * 873 * @return Name of the volume 874 * 875 */ 876 const char *ext4_superblock_get_volume_name(ext4_superblock_t *sb) 760 877 { 761 878 return sb->volume_name; … … 764 881 /** Set name of the filesystem volume. 765 882 * 766 * @param sb superblock767 * @param name new name of the volume883 * @param sb Superblock 884 * @param name New name of the volume 768 885 */ 769 886 void ext4_superblock_set_volume_name(ext4_superblock_t *sb, const char *name) … … 774 891 /** Get name of the directory, where this filesystem was mounted at last. 775 892 * 776 * @param sb superblock 777 * @return directory name 778 */ 779 const char * ext4_superblock_get_last_mounted(ext4_superblock_t *sb) 893 * @param sb Superblock 894 * 895 * @return Directory name 896 * 897 */ 898 const char *ext4_superblock_get_last_mounted(ext4_superblock_t *sb) 780 899 { 781 900 return sb->last_mounted; … … 784 903 /** Set name of the directory, where this filesystem was mounted at last. 785 904 * 786 * @param sb superblock 787 * @param last directory name 905 * @param sb Superblock 906 * @param last Directory name 907 * 788 908 */ 789 909 void ext4_superblock_set_last_mounted(ext4_superblock_t *sb, const char *last) … … 796 916 * Orphans are stored in linked list. 797 917 * 798 * @param sb superblock 799 * @return last orphaned i-node index 918 * @param sb Superblock 919 * 920 * @return Last orphaned i-node index 921 * 800 922 */ 801 923 uint32_t ext4_superblock_get_last_orphan(ext4_superblock_t *sb) … … 808 930 * Orphans are stored in linked list. 809 931 * 810 * @param sb superblock 811 * @param last_orphan last orphaned i-node index 812 */ 813 void ext4_superblock_set_last_orphan(ext4_superblock_t *sb, uint32_t last_orphan) 932 * @param sb Superblock 933 * @param last_orphan Last orphaned i-node index 934 * 935 */ 936 void ext4_superblock_set_last_orphan(ext4_superblock_t *sb, 937 uint32_t last_orphan) 814 938 { 815 939 sb->last_orphan = host2uint32_t_le(last_orphan); … … 818 942 /** Get hash seed for directory index hash function. 819 943 * 820 * @param sb superblock 821 * @return hash seed pointer 822 */ 823 const uint32_t * ext4_superblock_get_hash_seed(ext4_superblock_t *sb) 944 * @param sb Superblock 945 * 946 * @return Hash seed pointer 947 * 948 */ 949 const uint32_t *ext4_superblock_get_hash_seed(ext4_superblock_t *sb) 824 950 { 825 951 return sb->hash_seed; … … 828 954 /** Set hash seed for directory index hash function. 829 955 * 830 * @param sb superblock 831 * @param seed hash seed pointer 956 * @param sb Superblock 957 * @param seed Hash seed pointer 958 * 832 959 */ 833 960 void ext4_superblock_set_hash_seed(ext4_superblock_t *sb, const uint32_t *seed) … … 838 965 /** Get default version of the hash algorithm version for directory index. 839 966 * 840 * @param sb superblock 841 * @return default hash version 967 * @param sb Superblock 968 * 969 * @return Default hash version 970 * 842 971 */ 843 972 uint8_t ext4_superblock_get_default_hash_version(ext4_superblock_t *sb) … … 848 977 /** Set default version of the hash algorithm version for directory index. 849 978 * 850 * @param sb superblock 851 * @param version default hash version 852 */ 853 void ext4_superblock_set_default_hash_version(ext4_superblock_t *sb, uint8_t version) 979 * @param sb Superblock 980 * @param version Default hash version 981 * 982 */ 983 void ext4_superblock_set_default_hash_version(ext4_superblock_t *sb, 984 uint8_t version) 854 985 { 855 986 sb->default_hash_version = version; … … 860 991 * Output value is checked for minimal size. 861 992 * 862 * @param sb superblock 863 * @return size of block group descriptor 993 * @param sb Superblock 994 * 995 * @return Size of block group descriptor 996 * 864 997 */ 865 998 uint16_t ext4_superblock_get_desc_size(ext4_superblock_t *sb) 866 999 { 867 1000 uint16_t size = uint16_t_le2host(sb->desc_size); 868 869 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) {1001 1002 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 870 1003 size = EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE; 871 } 872 1004 873 1005 return size; 874 1006 } … … 878 1010 * Input value is checked for minimal size. 879 1011 * 880 * @param sb superblock 881 * @param size size of block group descriptor 1012 * @param sb Superblock 1013 * @param size Size of block group descriptor 1014 * 882 1015 */ 883 1016 void ext4_superblock_set_desc_size(ext4_superblock_t *sb, uint16_t size) 884 1017 { 885 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) {886 sb->desc_size = host2uint16_t_le(EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE);887 }888 1018 if (size < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 1019 sb->desc_size = 1020 host2uint16_t_le(EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE); 1021 889 1022 sb->desc_size = host2uint16_t_le(size); 890 1023 } … … 892 1025 /** Get superblock flags. 893 1026 * 894 * @param sb superblock 895 * @return flags from the superblock 1027 * @param sb Superblock 1028 * 1029 * @return Flags from the superblock 1030 * 896 1031 */ 897 1032 uint32_t ext4_superblock_get_flags(ext4_superblock_t *sb) … … 902 1037 /** Set superblock flags. 903 1038 * 904 * @param sb superblock 905 * @param flags flags for the superblock 1039 * @param sb Superblock 1040 * @param flags Flags for the superblock 1041 * 906 1042 */ 907 1043 void ext4_superblock_set_flags(ext4_superblock_t *sb, uint32_t flags) … … 916 1052 /** Check if superblock has specified flag. 917 1053 * 918 * @param sb superblock 919 * @param flag flag to be checked 920 * @return true, if superblock has the flag 1054 * @param sb Superblock 1055 * @param flag Flag to be checked 1056 * 1057 * @return True, if superblock has the flag 1058 * 921 1059 */ 922 1060 bool ext4_superblock_has_flag(ext4_superblock_t *sb, uint32_t flag) 923 1061 { 924 if (ext4_superblock_get_flags(sb) & flag) {1062 if (ext4_superblock_get_flags(sb) & flag) 925 1063 return true; 926 }1064 927 1065 return false; 928 1066 } … … 930 1068 /** Check if filesystem supports compatible feature. 931 1069 * 932 * @param sb superblock 933 * @param feature feature to be checked 934 * @return true, if filesystem supports the feature 935 */ 936 bool ext4_superblock_has_feature_compatible(ext4_superblock_t *sb, uint32_t feature) 937 { 938 if (ext4_superblock_get_features_compatible(sb) & feature) { 1070 * @param sb Superblock 1071 * @param feature Feature to be checked 1072 * 1073 * @return True, if filesystem supports the feature 1074 * 1075 */ 1076 bool ext4_superblock_has_feature_compatible(ext4_superblock_t *sb, 1077 uint32_t feature) 1078 { 1079 if (ext4_superblock_get_features_compatible(sb) & feature) 939 1080 return true; 940 }1081 941 1082 return false; 942 1083 } … … 944 1085 /** Check if filesystem supports incompatible feature. 945 1086 * 946 * @param sb superblock 947 * @param feature feature to be checked 948 * @return true, if filesystem supports the feature 949 */ 950 bool ext4_superblock_has_feature_incompatible(ext4_superblock_t *sb, uint32_t feature) 951 { 952 if (ext4_superblock_get_features_incompatible(sb) & feature) { 1087 * @param sb Superblock 1088 * @param feature Feature to be checked 1089 * 1090 * @return True, if filesystem supports the feature 1091 * 1092 */ 1093 bool ext4_superblock_has_feature_incompatible(ext4_superblock_t *sb, 1094 uint32_t feature) 1095 { 1096 if (ext4_superblock_get_features_incompatible(sb) & feature) 953 1097 return true; 954 }1098 955 1099 return false; 956 1100 } … … 958 1102 /** Check if filesystem supports read-only compatible feature. 959 1103 * 960 * @param sb superblock 961 * @param feature feature to be checked 962 * @return true, if filesystem supports the feature 963 */ 964 bool ext4_superblock_has_feature_read_only(ext4_superblock_t *sb, uint32_t feature) 965 { 966 if (ext4_superblock_get_features_read_only(sb) & feature) { 1104 * @param sb Superblock 1105 * @param feature Feature to be checked 1106 * 1107 * @return True, if filesystem supports the feature 1108 * 1109 */ 1110 bool ext4_superblock_has_feature_read_only(ext4_superblock_t *sb, 1111 uint32_t feature) 1112 { 1113 if (ext4_superblock_get_features_read_only(sb) & feature) 967 1114 return true; 968 }1115 969 1116 return false; 970 1117 } … … 972 1119 /** Read superblock directly from block device. 973 1120 * 974 * @param service_id block device identifier 975 * @param sb output pointer to memory structure 976 * @return error code. 977 */ 978 int ext4_superblock_read_direct(service_id_t service_id, 979 ext4_superblock_t **sb) 980 { 981 int rc; 982 1121 * @param service_id Block device identifier 1122 * @param sb Output pointer to memory structure 1123 * 1124 * @return Eerror code. 1125 * 1126 */ 1127 int ext4_superblock_read_direct(service_id_t service_id, ext4_superblock_t **sb) 1128 { 983 1129 /* Allocated memory for superblock structure */ 984 1130 void *data = malloc(EXT4_SUPERBLOCK_SIZE); 985 if (data == NULL) {1131 if (data == NULL) 986 1132 return ENOMEM; 987 } 988 1133 989 1134 /* Read data from block device */ 990 rc = block_read_bytes_direct(service_id, EXT4_SUPERBLOCK_OFFSET,1135 int rc = block_read_bytes_direct(service_id, EXT4_SUPERBLOCK_OFFSET, 991 1136 EXT4_SUPERBLOCK_SIZE, data); 992 1137 993 1138 if (rc != EOK) { 994 1139 free(data); 995 1140 return rc; 996 1141 } 997 1142 998 1143 /* Set output value */ 999 1144 (*sb) = data; 1000 1145 1001 1146 return EOK; 1002 1147 } … … 1004 1149 /** Write superblock structure directly to block device. 1005 1150 * 1006 * @param service_id block device identifier 1007 * @param sb superblock to be written 1008 * @return error code 1009 */ 1010 int ext4_superblock_write_direct(service_id_t service_id, 1011 ext4_superblock_t *sb) 1012 { 1013 int rc; 1151 * @param service_id Block device identifier 1152 * @param sb Superblock to be written 1153 * 1154 * @return Error code 1155 * 1156 */ 1157 int ext4_superblock_write_direct(service_id_t service_id, ext4_superblock_t *sb) 1158 { 1159 /* Load physical block size from block device */ 1014 1160 size_t phys_block_size; 1015 1016 /* Load physical block size from block device */ 1017 rc = block_get_bsize(service_id, &phys_block_size); 1018 if (rc != EOK) { 1161 int rc = block_get_bsize(service_id, &phys_block_size); 1162 if (rc != EOK) 1019 1163 return rc; 1020 } 1021 1164 1022 1165 /* Compute address of the first block */ 1023 1166 uint64_t first_block = EXT4_SUPERBLOCK_OFFSET / phys_block_size; 1167 1024 1168 /* Compute number of block to write */ 1025 1169 size_t block_count = EXT4_SUPERBLOCK_SIZE / phys_block_size; 1026 1170 1027 1171 /* Check alignment */ 1028 if (EXT4_SUPERBLOCK_SIZE % phys_block_size) {1172 if (EXT4_SUPERBLOCK_SIZE % phys_block_size) 1029 1173 block_count++; 1030 } 1031 1174 1032 1175 /* Write data */ 1033 1176 return block_write_direct(service_id, first_block, block_count, sb); 1034 1035 1177 } 1036 1178 … … 1040 1182 * Checks are described by one-line comments in the code. 1041 1183 * 1042 * @param sb superblock to check 1043 * @return error code 1184 * @param sb Superblock to check 1185 * 1186 * @return Error code 1187 * 1044 1188 */ 1045 1189 int ext4_superblock_check_sanity(ext4_superblock_t *sb) 1046 1190 { 1047 if (ext4_superblock_get_magic(sb) != EXT4_SUPERBLOCK_MAGIC) {1191 if (ext4_superblock_get_magic(sb) != EXT4_SUPERBLOCK_MAGIC) 1048 1192 return ENOTSUP; 1049 } 1050 1051 if (ext4_superblock_get_inodes_count(sb) == 0) { 1193 1194 if (ext4_superblock_get_inodes_count(sb) == 0) 1052 1195 return ENOTSUP; 1053 } 1054 1055 if (ext4_superblock_get_blocks_count(sb) == 0) { 1196 1197 if (ext4_superblock_get_blocks_count(sb) == 0) 1056 1198 return ENOTSUP; 1057 } 1058 1059 if (ext4_superblock_get_blocks_per_group(sb) == 0) { 1199 1200 if (ext4_superblock_get_blocks_per_group(sb) == 0) 1060 1201 return ENOTSUP; 1061 } 1062 1063 if (ext4_superblock_get_inodes_per_group(sb) == 0) { 1202 1203 if (ext4_superblock_get_inodes_per_group(sb) == 0) 1064 1204 return ENOTSUP; 1065 } 1066 1067 if (ext4_superblock_get_inode_size(sb) < 128) { 1205 1206 if (ext4_superblock_get_inode_size(sb) < 128) 1068 1207 return ENOTSUP; 1069 } 1070 1071 if (ext4_superblock_get_first_inode(sb) < 11) { 1208 1209 if (ext4_superblock_get_first_inode(sb) < 11) 1072 1210 return ENOTSUP; 1073 }1074 1075 if (ext4_superblock_get_desc_size(sb) < EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) {1211 1212 if (ext4_superblock_get_desc_size(sb) < 1213 EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE) 1076 1214 return ENOTSUP; 1077 }1078 1079 if (ext4_superblock_get_desc_size(sb) > EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE) {1215 1216 if (ext4_superblock_get_desc_size(sb) > 1217 EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE) 1080 1218 return ENOTSUP; 1081 } 1082 1219 1083 1220 return EOK; 1084 1221 } … … 1086 1223 /** Compute number of block groups in the filesystem. 1087 1224 * 1088 * @param sb superblock 1089 * @return number of block groups 1225 * @param sb Superblock 1226 * 1227 * @return Number of block groups 1228 * 1090 1229 */ 1091 1230 uint32_t ext4_superblock_get_block_group_count(ext4_superblock_t *sb) … … 1093 1232 uint64_t blocks_count = ext4_superblock_get_blocks_count(sb); 1094 1233 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb); 1095 1234 1096 1235 uint32_t block_groups_count = blocks_count / blocks_per_group; 1097 1098 if (blocks_count % blocks_per_group) {1236 1237 if (blocks_count % blocks_per_group) 1099 1238 block_groups_count++; 1100 } 1101 1239 1102 1240 return block_groups_count; 1103 1104 1241 } 1105 1242 1106 1243 /** Compute number of blocks in specified block group. 1107 1244 * 1108 * @param sb superblock 1109 * @param bgid block group index 1110 * @return number of blocks 1245 * @param sb Superblock 1246 * @param bgid Block group index 1247 * 1248 * @return Number of blocks 1249 * 1111 1250 */ 1112 1251 uint32_t ext4_superblock_get_blocks_in_group(ext4_superblock_t *sb, uint32_t bgid) 1113 1252 { 1114 uint32_t block_group_count = ext4_superblock_get_block_group_count(sb); 1115 uint32_t blocks_per_group = ext4_superblock_get_blocks_per_group(sb); 1116 uint64_t total_blocks = ext4_superblock_get_blocks_count(sb); 1117 1118 if (bgid < block_group_count - 1) { 1253 uint32_t block_group_count = 1254 ext4_superblock_get_block_group_count(sb); 1255 uint32_t blocks_per_group = 1256 ext4_superblock_get_blocks_per_group(sb); 1257 uint64_t total_blocks = 1258 ext4_superblock_get_blocks_count(sb); 1259 1260 if (bgid < block_group_count - 1) 1119 1261 return blocks_per_group; 1120 } else {1262 else 1121 1263 return (total_blocks - ((block_group_count - 1) * blocks_per_group)); 1122 }1123 1124 1264 } 1125 1265 1126 1266 /** Compute number of i-nodes in specified block group. 1127 1267 * 1128 * @param sb superblock 1129 * @param bgid block group index 1130 * @return number of i-nodes 1268 * @param sb Superblock 1269 * @param bgid Block group index 1270 * 1271 * @return Number of i-nodes 1272 * 1131 1273 */ 1132 1274 uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *sb, uint32_t bgid) 1133 1275 { 1134 uint32_t block_group_count = ext4_superblock_get_block_group_count(sb); 1135 uint32_t inodes_per_group = ext4_superblock_get_inodes_per_group(sb); 1136 uint32_t total_inodes = ext4_superblock_get_inodes_count(sb); 1137 1138 if (bgid < block_group_count - 1) { 1276 uint32_t block_group_count = 1277 ext4_superblock_get_block_group_count(sb); 1278 uint32_t inodes_per_group = 1279 ext4_superblock_get_inodes_per_group(sb); 1280 uint32_t total_inodes = 1281 ext4_superblock_get_inodes_count(sb); 1282 1283 if (bgid < block_group_count - 1) 1139 1284 return inodes_per_group; 1140 } else {1285 else 1141 1286 return (total_inodes - ((block_group_count - 1) * inodes_per_group)); 1142 }1143 1144 1287 } 1145 1288 1146 1289 /** 1147 1290 * @} 1148 */ 1291 */ -
uspace/lib/ext4/libext4_superblock.h
rb08e7970 r38542dc 36 36 #include <libblock.h> 37 37 #include <sys/types.h> 38 39 38 #include "libext4_types.h" 40 39 … … 44 43 extern void ext4_superblock_set_blocks_count(ext4_superblock_t *, uint64_t); 45 44 extern uint64_t ext4_superblock_get_reserved_blocks_count(ext4_superblock_t *); 46 extern void ext4_superblock_set_reserved_blocks_count(ext4_superblock_t *, uint64_t); 45 extern void ext4_superblock_set_reserved_blocks_count(ext4_superblock_t *, 46 uint64_t); 47 47 extern uint64_t ext4_superblock_get_free_blocks_count(ext4_superblock_t *); 48 extern void ext4_superblock_set_free_blocks_count(ext4_superblock_t *, uint64_t); 48 extern void ext4_superblock_set_free_blocks_count(ext4_superblock_t *, 49 uint64_t); 49 50 extern uint32_t ext4_superblock_get_free_inodes_count(ext4_superblock_t *); 50 extern void ext4_superblock_set_free_inodes_count(ext4_superblock_t *, uint32_t); 51 extern void ext4_superblock_set_free_inodes_count(ext4_superblock_t *, 52 uint32_t); 51 53 extern uint32_t ext4_superblock_get_first_data_block(ext4_superblock_t *); 52 54 extern void ext4_superblock_set_first_data_block(ext4_superblock_t *, uint32_t); … … 98 100 extern void ext4_superblock_set_inode_size(ext4_superblock_t *, uint16_t); 99 101 extern uint16_t ext4_superblock_get_block_group_index(ext4_superblock_t *); 100 extern void ext4_superblock_set_block_group_index(ext4_superblock_t *, uint16_t); 101 extern uint32_t ext4_superblock_get_features_compatible(ext4_superblock_t *); 102 extern void ext4_superblock_set_features_compatible(ext4_superblock_t *, uint32_t); 103 extern uint32_t ext4_superblock_get_features_incompatible(ext4_superblock_t *); 104 extern void ext4_superblock_set_features_incompatible(ext4_superblock_t *, uint32_t); 105 extern uint32_t ext4_superblock_get_features_read_only(ext4_superblock_t *); 106 extern void ext4_superblock_set_features_read_only(ext4_superblock_t *, uint32_t); 102 extern void ext4_superblock_set_block_group_index(ext4_superblock_t *, 103 uint16_t); 104 extern uint32_t ext4_superblock_get_features_compatible(ext4_superblock_t *); 105 extern void ext4_superblock_set_features_compatible(ext4_superblock_t *, 106 uint32_t); 107 extern uint32_t ext4_superblock_get_features_incompatible(ext4_superblock_t *); 108 extern void ext4_superblock_set_features_incompatible(ext4_superblock_t *, 109 uint32_t); 110 extern uint32_t ext4_superblock_get_features_read_only(ext4_superblock_t *); 111 extern void ext4_superblock_set_features_read_only(ext4_superblock_t *, 112 uint32_t); 107 113 108 114 extern const uint8_t * ext4_superblock_get_uuid(ext4_superblock_t *); … … 113 119 extern void ext4_superblock_set_last_mounted(ext4_superblock_t *, const char *); 114 120 115 /*116 uint32_t s_algorithm_usage_bitmap; // For compression117 uint8_t s_prealloc_blocks; // Number of blocks to try to preallocate118 uint8_t s_prealloc_dir_blocks; // Number to preallocate for dirs119 uint16_t s_reserved_gdt_blocks; // Per group desc for online growth120 uint8_t s_journal_uuid[16]; // UUID of journal superblock121 uint32_t s_journal_inum; // Inode number of journal file122 uint32_t s_journal_dev; // Device number of journal file123 */124 121 extern uint32_t ext4_superblock_get_last_orphan(ext4_superblock_t *); 125 122 extern void ext4_superblock_set_last_orphan(ext4_superblock_t *, uint32_t); 126 123 extern const uint32_t * ext4_superblock_get_hash_seed(ext4_superblock_t *); 127 extern void ext4_superblock_set_hash_seed(ext4_superblock_t *, const uint32_t *); 124 extern void ext4_superblock_set_hash_seed(ext4_superblock_t *, 125 const uint32_t *); 128 126 extern uint8_t ext4_superblock_get_default_hash_version(ext4_superblock_t *); 129 extern void ext4_superblock_set_default_hash_version(ext4_superblock_t *, uint8_t); 130 /* 131 uint8_t s_jnl_backup_type; 132 */ 127 extern void ext4_superblock_set_default_hash_version(ext4_superblock_t *, 128 uint8_t); 133 129 134 130 extern uint16_t ext4_superblock_get_desc_size(ext4_superblock_t *); 135 131 extern void ext4_superblock_set_desc_size(ext4_superblock_t *, uint16_t); 136 132 137 /*138 uint32_t s_default_mount_opts; // Default mount options139 uint32_t s_first_meta_bg; // First metablock block group140 uint32_t s_mkfs_time; // When the filesystem was created141 uint32_t s_jnl_blocks[17]; // Backup of the journal inode142 uint16_t s_min_extra_isize; // All inodes have at least # bytes143 uint16_t s_want_extra_isize; // New inodes should reserve # bytes144 */145 133 extern uint32_t ext4_superblock_get_flags(ext4_superblock_t *); 146 134 extern void ext4_superblock_set_flags(ext4_superblock_t *, uint32_t); 147 /*148 uint16_t s_raid_stride; // RAID stride149 uint16_t s_mmp_interval; // # seconds to wait in MMP checking150 uint64_t s_mmp_block; // Block for multi-mount protection151 uint32_t s_raid_stripe_width; // blocks on all data disks (N*stride)152 uint8_t s_log_groups_per_flex; // FLEX_BG group size153 uint8_t s_reserved_char_pad;154 uint16_t s_reserved_pad;155 uint64_t s_kbytes_written; // Number of lifetime kilobytes written156 uint32_t s_snapshot_inum; // Inode number of active snapshot157 uint32_t s_snapshot_id; // Sequential ID of active snapshot158 uint64_t s_snapshot_r_blocks_count; // reserved blocks for active snapshot's future use159 uint32_t s_snapshot_list; // inode number of the head of the on-disk snapshot list160 uint32_t s_error_count; // number of fs errors161 uint32_t s_first_error_time; // First time an error happened162 uint32_t s_first_error_ino; // Inode involved in first error163 uint64_t s_first_error_block; // block involved of first error164 uint8_t s_first_error_func[32]; // Function where the error happened165 uint32_t s_first_error_line; // Line number where error happened166 uint32_t s_last_error_time; // Most recent time of an error167 uint32_t s_last_error_ino; // Inode involved in last error168 uint32_t s_last_error_line; // Line number where error happened169 uint64_t s_last_error_block; // block involved of last error170 uint8_t s_last_error_func[32]; // function where the error happened171 uint8_t s_mount_opts[64];172 */173 135 174 136 /* More complex superblock functions */ 175 137 extern bool ext4_superblock_has_flag(ext4_superblock_t *, uint32_t); 176 extern bool ext4_superblock_has_feature_compatible(ext4_superblock_t *, uint32_t); 177 extern bool ext4_superblock_has_feature_incompatible(ext4_superblock_t *, uint32_t); 178 extern bool ext4_superblock_has_feature_read_only(ext4_superblock_t *, uint32_t); 138 extern bool ext4_superblock_has_feature_compatible(ext4_superblock_t *, 139 uint32_t); 140 extern bool ext4_superblock_has_feature_incompatible(ext4_superblock_t *, 141 uint32_t); 142 extern bool ext4_superblock_has_feature_read_only(ext4_superblock_t *, 143 uint32_t); 179 144 extern int ext4_superblock_read_direct(service_id_t, ext4_superblock_t **); 180 145 extern int ext4_superblock_write_direct(service_id_t, ext4_superblock_t *); … … 182 147 183 148 extern uint32_t ext4_superblock_get_block_group_count(ext4_superblock_t *); 184 extern uint32_t ext4_superblock_get_blocks_in_group(ext4_superblock_t *, uint32_t); 185 extern uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *, uint32_t); 149 extern uint32_t ext4_superblock_get_blocks_in_group(ext4_superblock_t *, 150 uint32_t); 151 extern uint32_t ext4_superblock_get_inodes_in_group(ext4_superblock_t *, 152 uint32_t); 186 153 187 154 #endif -
uspace/lib/ext4/libext4_types.h
rb08e7970 r38542dc 29 29 /** @addtogroup libext4 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef LIBEXT4_LIBEXT4_TYPES_H_ … … 40 40 */ 41 41 typedef struct ext4_superblock { 42 uint32_t inodes_count; // Inodes count43 uint32_t blocks_count_lo; // Blocks count44 uint32_t reserved_blocks_count_lo; // Reserved blocks count45 uint32_t free_blocks_count_lo; // Free blocks count46 uint32_t free_inodes_count; // Free inodes count47 uint32_t first_data_block; // First Data Block48 uint32_t log_block_size; // Block size49 uint32_t log_frag_size; // Obsoleted fragment size50 uint32_t blocks_per_group; // Number of blocks per group51 uint32_t frags_per_group; // Obsoleted fragments per group52 uint32_t inodes_per_group; // Number of inodes per group53 uint32_t mount_time; // Mount time54 uint32_t write_time; // Write time55 uint16_t mount_count; // Mount count56 uint16_t max_mount_count; // Maximal mount count57 uint16_t magic; // Magic signature58 uint16_t state; // Filesystem state59 uint16_t errors; // Behaviour when detecting errors60 uint16_t minor_rev_level; // Minor revision level61 uint32_t last_check_time; // Time of last check62 uint32_t check_interval; // Maximum time between checks63 uint32_t creator_os; // Creator OS64 uint32_t rev_level; // Revision level65 uint16_t def_resuid; // Default uid for reserved blocks66 uint16_t def_resgid; // Default gid for reserved blocks67 68 / / Fields for EXT4_DYNAMIC_REV superblocks only.69 uint32_t first_inode; // First non-reserved inode70 uint16_t inode_size; // Size of inode structure71 uint16_t block_group_index; // Block group index of this superblock72 uint32_t features_compatible; // Compatible feature set73 uint32_t features_incompatible; // Incompatible feature set74 uint32_t features_read_only; // Readonly-compatible feature set75 uint8_t uuid[16]; // 128-bit uuid for volume76 char volume_name[16]; // Volume name77 char last_mounted[64]; // Directory where last mounted78 uint32_t algorithm_usage_bitmap; // For compression79 42 uint32_t inodes_count; /* I-nodes count */ 43 uint32_t blocks_count_lo; /* Blocks count */ 44 uint32_t reserved_blocks_count_lo; /* Reserved blocks count */ 45 uint32_t free_blocks_count_lo; /* Free blocks count */ 46 uint32_t free_inodes_count; /* Free inodes count */ 47 uint32_t first_data_block; /* First Data Block */ 48 uint32_t log_block_size; /* Block size */ 49 uint32_t log_frag_size; /* Obsoleted fragment size */ 50 uint32_t blocks_per_group; /* Number of blocks per group */ 51 uint32_t frags_per_group; /* Obsoleted fragments per group */ 52 uint32_t inodes_per_group; /* Number of inodes per group */ 53 uint32_t mount_time; /* Mount time */ 54 uint32_t write_time; /* Write time */ 55 uint16_t mount_count; /* Mount count */ 56 uint16_t max_mount_count; /* Maximal mount count */ 57 uint16_t magic; /* Magic signature */ 58 uint16_t state; /* File system state */ 59 uint16_t errors; /* Behaviour when detecting errors */ 60 uint16_t minor_rev_level; /* Minor revision level */ 61 uint32_t last_check_time; /* Time of last check */ 62 uint32_t check_interval; /* Maximum time between checks */ 63 uint32_t creator_os; /* Creator OS */ 64 uint32_t rev_level; /* Revision level */ 65 uint16_t def_resuid; /* Default uid for reserved blocks */ 66 uint16_t def_resgid; /* Default gid for reserved blocks */ 67 68 /* Fields for EXT4_DYNAMIC_REV superblocks only. */ 69 uint32_t first_inode; /* First non-reserved inode */ 70 uint16_t inode_size; /* Size of inode structure */ 71 uint16_t block_group_index; /* Block group index of this superblock */ 72 uint32_t features_compatible; /* Compatible feature set */ 73 uint32_t features_incompatible; /* Incompatible feature set */ 74 uint32_t features_read_only; /* Readonly-compatible feature set */ 75 uint8_t uuid[16]; /* 128-bit uuid for volume */ 76 char volume_name[16]; /* Volume name */ 77 char last_mounted[64]; /* Directory where last mounted */ 78 uint32_t algorithm_usage_bitmap; /* For compression */ 79 80 80 /* 81 81 * Performance hints. Directory preallocation should only 82 82 * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on. 83 83 */ 84 uint8_t s_prealloc_blocks; // Number of blocks to try to preallocate85 uint8_t s_prealloc_dir_blocks; // Number to preallocate for dirs86 uint16_t s_reserved_gdt_blocks; // Per group desc for online growth87 84 uint8_t s_prealloc_blocks; /* Number of blocks to try to preallocate */ 85 uint8_t s_prealloc_dir_blocks; /* Number to preallocate for dirs */ 86 uint16_t s_reserved_gdt_blocks; /* Per group desc for online growth */ 87 88 88 /* 89 89 * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set. 90 90 */ 91 uint8_t journal_uuid[16]; // UUID of journal superblock92 uint32_t journal_inode_number; // Inode number of journal file93 uint32_t journal_dev; // Device number of journal file94 uint32_t last_orphan; // Head of list of inodes to delete95 uint32_t hash_seed[4]; // HTREE hash seed96 uint8_t default_hash_version; // Default hash version to use91 uint8_t journal_uuid[16]; /* UUID of journal superblock */ 92 uint32_t journal_inode_number; /* Inode number of journal file */ 93 uint32_t journal_dev; /* Device number of journal file */ 94 uint32_t last_orphan; /* Head of list of inodes to delete */ 95 uint32_t hash_seed[4]; /* HTREE hash seed */ 96 uint8_t default_hash_version; /* Default hash version to use */ 97 97 uint8_t journal_backup_type; 98 uint16_t desc_size; // Size of group descriptor99 uint32_t default_mount_opts; // Default mount options100 uint32_t first_meta_bg; // First metablock block group101 uint32_t mkfs_time; // When the filesystem was created102 uint32_t journal_blocks[17]; // Backup of the journal inode98 uint16_t desc_size; /* Size of group descriptor */ 99 uint32_t default_mount_opts; /* Default mount options */ 100 uint32_t first_meta_bg; /* First metablock block group */ 101 uint32_t mkfs_time; /* When the filesystem was created */ 102 uint32_t journal_blocks[17]; /* Backup of the journal inode */ 103 103 104 104 /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */ 105 uint32_t blocks_count_hi; // Blocks count106 uint32_t reserved_blocks_count_hi; // Reserved blocks count107 uint32_t free_blocks_count_hi; // Free blocks count108 uint16_t min_extra_isize; // All inodes have at least # bytes109 uint16_t want_extra_isize; // New inodes should reserve # bytes110 uint32_t flags; // Miscellaneous flags111 uint16_t raid_stride; // RAID stride112 uint16_t mmp_interval; // # seconds to wait in MMP checking113 uint64_t mmp_block; // Block for multi-mount protection114 uint32_t raid_stripe_width; // blocks on all data disks (N*stride)115 uint8_t log_groups_per_flex; // FLEX_BG group size105 uint32_t blocks_count_hi; /* Blocks count */ 106 uint32_t reserved_blocks_count_hi; /* Reserved blocks count */ 107 uint32_t free_blocks_count_hi; /* Free blocks count */ 108 uint16_t min_extra_isize; /* All inodes have at least # bytes */ 109 uint16_t want_extra_isize; /* New inodes should reserve # bytes */ 110 uint32_t flags; /* Miscellaneous flags */ 111 uint16_t raid_stride; /* RAID stride */ 112 uint16_t mmp_interval; /* # seconds to wait in MMP checking */ 113 uint64_t mmp_block; /* Block for multi-mount protection */ 114 uint32_t raid_stripe_width; /* Blocks on all data disks (N * stride) */ 115 uint8_t log_groups_per_flex; /* FLEX_BG group size */ 116 116 uint8_t reserved_char_pad; 117 117 uint16_t reserved_pad; 118 uint64_t kbytes_written; // Number of lifetime kilobytes written119 uint32_t snapshot_inum; // Inode number of active snapshot120 uint32_t snapshot_id; // Sequential ID of active snapshot121 uint64_t snapshot_r_blocks_count; /* reserved blocks for active snapshot's future use */122 uint32_t snapshot_list; // inode number of the head of the on-disk snapshot list123 uint32_t error_count; // number of fs errors124 uint32_t first_error_time; // First time an error happened125 uint32_t first_error_ino; // Inode involved in first error126 uint64_t first_error_block; // block involved of first error127 uint8_t first_error_func[32]; // Function where the error happened128 uint32_t first_error_line; // Line number where error happened129 uint32_t last_error_time; // Most recent time of an error130 uint32_t last_error_ino; // Inode involved in last error131 uint32_t last_error_line; // Line number where error happened132 uint64_t last_error_block; // Block involved of last error133 uint8_t last_error_func[32]; // Function where the error happened118 uint64_t kbytes_written; /* Number of lifetime kilobytes written */ 119 uint32_t snapshot_inum; /* I-node number of active snapshot */ 120 uint32_t snapshot_id; /* Sequential ID of active snapshot */ 121 uint64_t snapshot_r_blocks_count; /* Reserved blocks for active snapshot's future use */ 122 uint32_t snapshot_list; /* I-node number of the head of the on-disk snapshot list */ 123 uint32_t error_count; /* Number of file system errors */ 124 uint32_t first_error_time; /* First time an error happened */ 125 uint32_t first_error_ino; /* I-node involved in first error */ 126 uint64_t first_error_block; /* Block involved of first error */ 127 uint8_t first_error_func[32]; /* Function where the error happened */ 128 uint32_t first_error_line; /* Line number where error happened */ 129 uint32_t last_error_time; /* Most recent time of an error */ 130 uint32_t last_error_ino; /* I-node involved in last error */ 131 uint32_t last_error_line; /* Line number where error happened */ 132 uint64_t last_error_block; /* Block involved of last error */ 133 uint8_t last_error_func[32]; /* Function where the error happened */ 134 134 uint8_t mount_opts[64]; 135 uint32_t padding[112]; // Padding to the end of the block135 uint32_t padding[112]; /* Padding to the end of the block */ 136 136 } __attribute__((packed)) ext4_superblock_t; 137 137 138 138 139 #define EXT4_SUPERBLOCK_MAGIC 0xEF53140 #define EXT4_SUPERBLOCK_SIZE 1024141 #define EXT4_SUPERBLOCK_OFFSET 1024142 143 #define EXT4_SUPERBLOCK_OS_LINUX 0144 #define EXT4_SUPERBLOCK_OS_HURD 1139 #define EXT4_SUPERBLOCK_MAGIC 0xEF53 140 #define EXT4_SUPERBLOCK_SIZE 1024 141 #define EXT4_SUPERBLOCK_OFFSET 1024 142 143 #define EXT4_SUPERBLOCK_OS_LINUX 0 144 #define EXT4_SUPERBLOCK_OS_HURD 1 145 145 146 146 /* 147 147 * Misc. filesystem flags 148 148 */ 149 #define EXT4_SUPERBLOCK_FLAGS_SIGNED_HASH 0x0001 // Signed dirhash in use150 #define EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH 0x0002 // Unsigned dirhash in use151 #define EXT4_SUPERBLOCK_FLAGS_TEST_FILESYS 0x0004 // to test development code149 #define EXT4_SUPERBLOCK_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */ 150 #define EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */ 151 #define EXT4_SUPERBLOCK_FLAGS_TEST_FILESYS 0x0004 /* to test development code */ 152 152 153 153 /* 154 154 * Filesystem states 155 155 */ 156 #define EXT4_SUPERBLOCK_STATE_VALID_FS 0x0001 // Unmounted cleanly157 #define EXT4_SUPERBLOCK_STATE_ERROR_FS 0x0002 // Errors detected158 #define EXT4_SUPERBLOCK_STATE_ORPHAN_FS 0x0004 // Orphans being recovered156 #define EXT4_SUPERBLOCK_STATE_VALID_FS 0x0001 /* Unmounted cleanly */ 157 #define EXT4_SUPERBLOCK_STATE_ERROR_FS 0x0002 /* Errors detected */ 158 #define EXT4_SUPERBLOCK_STATE_ORPHAN_FS 0x0004 /* Orphans being recovered */ 159 159 160 160 /* 161 161 * Behaviour when errors detected 162 162 */ 163 #define EXT4_SUPERBLOCK_ERRORS_CONTINUE 1 // Continue execution164 #define EXT4_SUPERBLOCK_ERRORS_RO 2 // Remount fs read-only165 #define EXT4_SUPERBLOCK_ERRORS_PANIC 3 // Panic166 #define EXT4_SUPERBLOCK_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE163 #define EXT4_SUPERBLOCK_ERRORS_CONTINUE 1 /* Continue execution */ 164 #define EXT4_SUPERBLOCK_ERRORS_RO 2 /* Remount fs read-only */ 165 #define EXT4_SUPERBLOCK_ERRORS_PANIC 3 /* Panic */ 166 #define EXT4_SUPERBLOCK_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE 167 167 168 168 /* 169 169 * Compatible features 170 170 */ 171 #define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001172 #define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002173 #define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004174 #define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008175 #define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010176 #define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020171 #define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001 172 #define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002 173 #define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004 174 #define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008 175 #define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010 176 #define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020 177 177 178 178 /* 179 179 * Read-only compatible features 180 180 */ 181 #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001182 #define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002183 #define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004184 #define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008185 #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010186 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020187 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040181 #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 182 #define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 183 #define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 184 #define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 185 #define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 186 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 187 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 188 188 189 189 /* 190 190 * Incompatible features 191 191 */ 192 #define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 193 #define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002 194 #define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ 195 #define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ 196 #define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 197 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ 198 #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 199 #define EXT4_FEATURE_INCOMPAT_MMP 0x0100 200 #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 201 #define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */ 202 #define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */ 203 204 #define EXT4_FEATURE_COMPAT_SUPP (EXT4_FEATURE_COMPAT_DIR_INDEX) 205 206 #define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE | \ 207 EXT4_FEATURE_INCOMPAT_EXTENTS | \ 208 EXT4_FEATURE_INCOMPAT_64BIT) 209 210 #define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | \ 211 EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \ 212 EXT4_FEATURE_RO_COMPAT_HUGE_FILE | \ 213 EXT4_FEATURE_RO_COMPAT_LARGE_FILE | \ 214 EXT4_FEATURE_RO_COMPAT_GDT_CSUM | \ 215 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) 216 217 218 /*****************************************************************************/ 192 #define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 193 #define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002 194 #define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ 195 #define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ 196 #define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 197 #define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ 198 #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 199 #define EXT4_FEATURE_INCOMPAT_MMP 0x0100 200 #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 201 #define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */ 202 #define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */ 203 204 #define EXT4_FEATURE_COMPAT_SUPP (EXT4_FEATURE_COMPAT_DIR_INDEX) 205 206 #define EXT4_FEATURE_INCOMPAT_SUPP \ 207 (EXT4_FEATURE_INCOMPAT_FILETYPE | \ 208 EXT4_FEATURE_INCOMPAT_EXTENTS | \ 209 EXT4_FEATURE_INCOMPAT_64BIT) 210 211 #define EXT4_FEATURE_RO_COMPAT_SUPP \ 212 (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | \ 213 EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \ 214 EXT4_FEATURE_RO_COMPAT_HUGE_FILE | \ 215 EXT4_FEATURE_RO_COMPAT_LARGE_FILE | \ 216 EXT4_FEATURE_RO_COMPAT_GDT_CSUM | \ 217 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE) 219 218 220 219 typedef struct ext4_filesystem { 221 220 service_id_t device; 222 ext4_superblock_t * superblock;221 ext4_superblock_t *superblock; 223 222 aoff64_t inode_block_limits[4]; 224 223 aoff64_t inode_blocks_per_level[4]; … … 226 225 227 226 228 /*****************************************************************************/ 229 230 #define EXT4_BLOCK_GROUP_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */ 231 #define EXT4_BLOCK_GROUP_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */ 232 #define EXT4_BLOCK_GROUP_ITABLE_ZEROED 0x0004 /* On-disk itable initialized to zero */ 227 #define EXT4_BLOCK_GROUP_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */ 228 #define EXT4_BLOCK_GROUP_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */ 229 #define EXT4_BLOCK_GROUP_ITABLE_ZEROED 0x0004 /* On-disk itable initialized to zero */ 233 230 234 231 /* … … 236 233 */ 237 234 typedef struct ext4_block_group { 238 uint32_t block_bitmap_lo; // Blocks bitmap block239 uint32_t inode_bitmap_lo; // Inodes bitmap block240 uint32_t inode_table_first_block_lo; // Inodes table block241 uint16_t free_blocks_count_lo; // Free blocks count242 uint16_t free_inodes_count_lo; // Free inodes count243 uint16_t used_dirs_count_lo; // Directories count244 uint16_t flags; // EXT4_BG_flags (INODE_UNINIT, etc)245 uint32_t reserved[2]; // Likely block/inode bitmap checksum246 uint16_t itable_unused_lo; // Unused inodes count247 uint16_t checksum; // crc16(sb_uuid+group+desc)248 /* -------------- */249 uint32_t block_bitmap_hi; // Blocks bitmap block MSB250 uint32_t inode_bitmap_hi; // Inodes bitmap block MSB251 uint32_t inode_table_first_block_hi; // Inodes table block MSB252 uint16_t free_blocks_count_hi; // Free blocks count MSB253 uint16_t free_inodes_count_hi; // Free inodes count MSB254 uint16_t used_dirs_count_hi; // Directories count MSB255 uint16_t itable_unused_hi; // Unused inodes count MSB256 uint32_t reserved2[3]; // Padding235 uint32_t block_bitmap_lo; /* Blocks bitmap block */ 236 uint32_t inode_bitmap_lo; /* Inodes bitmap block */ 237 uint32_t inode_table_first_block_lo; /* Inodes table block */ 238 uint16_t free_blocks_count_lo; /* Free blocks count */ 239 uint16_t free_inodes_count_lo; /* Free inodes count */ 240 uint16_t used_dirs_count_lo; /* Directories count */ 241 uint16_t flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ 242 uint32_t reserved[2]; /* Likely block/inode bitmap checksum */ 243 uint16_t itable_unused_lo; /* Unused inodes count */ 244 uint16_t checksum; /* crc16(sb_uuid+group+desc) */ 245 246 uint32_t block_bitmap_hi; /* Blocks bitmap block MSB */ 247 uint32_t inode_bitmap_hi; /* I-nodes bitmap block MSB */ 248 uint32_t inode_table_first_block_hi; /* I-nodes table block MSB */ 249 uint16_t free_blocks_count_hi; /* Free blocks count MSB */ 250 uint16_t free_inodes_count_hi; /* Free i-nodes count MSB */ 251 uint16_t used_dirs_count_hi; /* Directories count MSB */ 252 uint16_t itable_unused_hi; /* Unused inodes count MSB */ 253 uint32_t reserved2[3]; /* Padding */ 257 254 } ext4_block_group_t; 258 255 259 256 typedef struct ext4_block_group_ref { 260 block_t *block; // Reference to a block containing this block group descr257 block_t *block; /* Reference to a block containing this block group descr */ 261 258 ext4_block_group_t *block_group; 262 259 ext4_filesystem_t *fs; … … 265 262 } ext4_block_group_ref_t; 266 263 267 268 #define EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE 32 269 #define EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE 64 270 271 /*****************************************************************************/ 272 273 274 #define EXT4_MIN_BLOCK_SIZE 1024 //1 KiB 275 #define EXT4_MAX_BLOCK_SIZE 65536 //64 KiB 276 #define EXT4_REV0_INODE_SIZE 128 277 278 #define EXT4_INODE_BLOCK_SIZE 512 279 280 #define EXT4_INODE_DIRECT_BLOCK_COUNT 12 281 #define EXT4_INODE_INDIRECT_BLOCK EXT4_INODE_DIRECT_BLOCK_COUNT 282 #define EXT4_INODE_DOUBLE_INDIRECT_BLOCK (EXT4_INODE_INDIRECT_BLOCK + 1) 283 #define EXT4_INODE_TRIPPLE_INDIRECT_BLOCK (EXT4_INODE_DOUBLE_INDIRECT_BLOCK + 1) 284 #define EXT4_INODE_BLOCKS (EXT4_INODE_TRIPPLE_INDIRECT_BLOCK + 1) 285 #define EXT4_INODE_INDIRECT_BLOCK_COUNT (EXT4_INODE_BLOCKS - EXT4_INODE_DIRECT_BLOCK_COUNT) 264 #define EXT4_MIN_BLOCK_GROUP_DESCRIPTOR_SIZE 32 265 #define EXT4_MAX_BLOCK_GROUP_DESCRIPTOR_SIZE 64 266 267 #define EXT4_MIN_BLOCK_SIZE 1024 /* 1 KiB */ 268 #define EXT4_MAX_BLOCK_SIZE 65536 /* 64 KiB */ 269 #define EXT4_REV0_INODE_SIZE 128 270 271 #define EXT4_INODE_BLOCK_SIZE 512 272 273 #define EXT4_INODE_DIRECT_BLOCK_COUNT 12 274 #define EXT4_INODE_INDIRECT_BLOCK EXT4_INODE_DIRECT_BLOCK_COUNT 275 #define EXT4_INODE_DOUBLE_INDIRECT_BLOCK (EXT4_INODE_INDIRECT_BLOCK + 1) 276 #define EXT4_INODE_TRIPPLE_INDIRECT_BLOCK (EXT4_INODE_DOUBLE_INDIRECT_BLOCK + 1) 277 #define EXT4_INODE_BLOCKS (EXT4_INODE_TRIPPLE_INDIRECT_BLOCK + 1) 278 #define EXT4_INODE_INDIRECT_BLOCK_COUNT (EXT4_INODE_BLOCKS - EXT4_INODE_DIRECT_BLOCK_COUNT) 286 279 287 280 /* … … 289 282 */ 290 283 typedef struct ext4_inode { 291 uint16_t mode; // File mode 292 uint16_t uid; // Low 16 bits of owner uid 293 uint32_t size_lo; // Size in bytes 294 uint32_t access_time; // Access time 295 uint32_t change_inode_time; // Inode change time 296 uint32_t modification_time; // Modification time 297 uint32_t deletion_time; // Deletion time 298 uint16_t gid; // Low 16 bits of group id 299 uint16_t links_count; // Links count 300 uint32_t blocks_count_lo; // Blocks count 301 uint32_t flags; // File flags 302 uint32_t unused_osd1; // OS dependent - not used in HelenOS 303 uint32_t blocks[EXT4_INODE_BLOCKS]; // Pointers to blocks 304 uint32_t generation; // File version (for NFS) 305 uint32_t file_acl_lo; // File ACL 306 uint32_t size_hi; 307 uint32_t obso_faddr; // Obsoleted fragment address 308 union { 309 struct { 310 uint16_t blocks_high; /* were l_i_reserved1 */ 311 uint16_t file_acl_high; 312 uint16_t uid_high; /* these 2 fields */ 313 uint16_t gid_high; /* were reserved2[0] */ 314 uint32_t reserved2; 315 } linux2; 316 struct { 317 uint16_t reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ 318 uint16_t mode_high; 319 uint16_t uid_high; 320 uint16_t gid_high; 321 uint32_t author; 322 } hurd2; 323 } __attribute__ ((packed)) osd2; 324 325 uint16_t extra_isize; 326 uint16_t pad1; 327 uint32_t ctime_extra; // Extra change time (nsec << 2 | epoch) 328 uint32_t mtime_extra; // Extra Modification time (nsec << 2 | epoch) 329 uint32_t atime_extra; // Extra Access time (nsec << 2 | epoch) 330 uint32_t crtime; // File creation time 331 uint32_t crtime_extra; // Extra file creation time (nsec << 2 | epoch) 332 uint32_t version_hi; // High 32 bits for 64-bit version 284 uint16_t mode; /* File mode */ 285 uint16_t uid; /* Low 16 bits of owner uid */ 286 uint32_t size_lo; /* Size in bytes */ 287 uint32_t access_time; /* Access time */ 288 uint32_t change_inode_time; /* I-node change time */ 289 uint32_t modification_time; /* Modification time */ 290 uint32_t deletion_time; /* Deletion time */ 291 uint16_t gid; /* Low 16 bits of group id */ 292 uint16_t links_count; /* Links count */ 293 uint32_t blocks_count_lo; /* Blocks count */ 294 uint32_t flags; /* File flags */ 295 uint32_t unused_osd1; /* OS dependent - not used in HelenOS */ 296 uint32_t blocks[EXT4_INODE_BLOCKS]; /* Pointers to blocks */ 297 uint32_t generation; /* File version (for NFS) */ 298 uint32_t file_acl_lo; /* File ACL */ 299 uint32_t size_hi; 300 uint32_t obso_faddr; /* Obsoleted fragment address */ 301 302 union { 303 struct { 304 uint16_t blocks_high; 305 uint16_t file_acl_high; 306 uint16_t uid_high; 307 uint16_t gid_high; 308 uint32_t reserved2; 309 } linux2; 310 struct { 311 uint16_t reserved1; 312 uint16_t mode_high; 313 uint16_t uid_high; 314 uint16_t gid_high; 315 uint32_t author; 316 } hurd2; 317 } __attribute__ ((packed)) osd2; 318 319 uint16_t extra_isize; 320 uint16_t pad1; 321 uint32_t ctime_extra; /* Extra change time (nsec << 2 | epoch) */ 322 uint32_t mtime_extra; /* Extra Modification time (nsec << 2 | epoch) */ 323 uint32_t atime_extra; /* Extra Access time (nsec << 2 | epoch) */ 324 uint32_t crtime; /* File creation time */ 325 uint32_t crtime_extra; /* Extra file creation time (nsec << 2 | epoch) */ 326 uint32_t version_hi; /* High 32 bits for 64-bit version */ 333 327 } __attribute__ ((packed)) ext4_inode_t; 334 328 335 #define EXT4_INODE_MODE_FIFO 0x1000336 #define EXT4_INODE_MODE_CHARDEV 0x2000337 #define EXT4_INODE_MODE_DIRECTORY 0x4000338 #define EXT4_INODE_MODE_BLOCKDEV 0x6000339 #define EXT4_INODE_MODE_FILE 0x8000340 #define EXT4_INODE_MODE_SOFTLINK 0xA000341 #define EXT4_INODE_MODE_SOCKET 0xC000342 #define EXT4_INODE_MODE_TYPE_MASK 0xF000329 #define EXT4_INODE_MODE_FIFO 0x1000 330 #define EXT4_INODE_MODE_CHARDEV 0x2000 331 #define EXT4_INODE_MODE_DIRECTORY 0x4000 332 #define EXT4_INODE_MODE_BLOCKDEV 0x6000 333 #define EXT4_INODE_MODE_FILE 0x8000 334 #define EXT4_INODE_MODE_SOFTLINK 0xA000 335 #define EXT4_INODE_MODE_SOCKET 0xC000 336 #define EXT4_INODE_MODE_TYPE_MASK 0xF000 343 337 344 338 /* 345 339 * Inode flags 346 340 */ 347 #define EXT4_INODE_FLAG_SECRM 0x00000001 // Secure deletion 348 #define EXT4_INODE_FLAG_UNRM 0x00000002 // Undelete 349 #define EXT4_INODE_FLAG_COMPR 0x00000004 // Compress file 350 #define EXT4_INODE_FLAG_SYNC 0x00000008 // Synchronous updates 351 #define EXT4_INODE_FLAG_IMMUTABLE 0x00000010 // Immutable file 352 #define EXT4_INODE_FLAG_APPEND 0x00000020 // writes to file may only append 353 #define EXT4_INODE_FLAG_NODUMP 0x00000040 // do not dump file 354 #define EXT4_INODE_FLAG_NOATIME 0x00000080 // do not update atime 341 #define EXT4_INODE_FLAG_SECRM 0x00000001 /* Secure deletion */ 342 #define EXT4_INODE_FLAG_UNRM 0x00000002 /* Undelete */ 343 #define EXT4_INODE_FLAG_COMPR 0x00000004 /* Compress file */ 344 #define EXT4_INODE_FLAG_SYNC 0x00000008 /* Synchronous updates */ 345 #define EXT4_INODE_FLAG_IMMUTABLE 0x00000010 /* Immutable file */ 346 #define EXT4_INODE_FLAG_APPEND 0x00000020 /* writes to file may only append */ 347 #define EXT4_INODE_FLAG_NODUMP 0x00000040 /* do not dump file */ 348 #define EXT4_INODE_FLAG_NOATIME 0x00000080 /* do not update atime */ 349 355 350 /* Compression flags */ 356 #define EXT4_INODE_FLAG_DIRTY 0x00000100357 #define EXT4_INODE_FLAG_COMPRBLK 0x00000200 // One or more compressed clusters358 #define EXT4_INODE_FLAG_NOCOMPR 0x00000400 // Don't compress359 #define EXT4_INODE_FLAG_ECOMPR 0x00000800 // Compression error360 /* End compression flags --- maybe not all used */ 361 #define EXT4_INODE_FLAG_INDEX 0x00001000 // hash-indexed directory362 #define EXT4_INODE_FLAG_IMAGIC 0x00002000 //AFS directory */363 #define EXT4_INODE_FLAG_JOURNAL_DATA 0x00004000 // File data should be journaled364 #define EXT4_INODE_FLAG_NOTAIL 0x00008000 // File tail should not be merged365 #define EXT4_INODE_FLAG_DIRSYNC 0x00010000 // Dirsync behaviour (directories only)366 #define EXT4_INODE_FLAG_TOPDIR 0x00020000 // Top of directory hierarchies367 #define EXT4_INODE_FLAG_HUGE_FILE 0x00040000 // Set to each huge file368 #define EXT4_INODE_FLAG_EXTENTS 0x00080000 // Inode uses extents369 #define EXT4_INODE_FLAG_EA_INODE 0x00200000 // Inode used for large EA370 #define EXT4_INODE_FLAG_EOFBLOCKS 0x00400000 // Blocks allocated beyond EOF371 #define EXT4_INODE_FLAG_RESERVED 0x80000000 // reserved for ext4 lib372 373 #define EXT4_INODE_ROOT_INDEX 2351 #define EXT4_INODE_FLAG_DIRTY 0x00000100 352 #define EXT4_INODE_FLAG_COMPRBLK 0x00000200 /* One or more compressed clusters */ 353 #define EXT4_INODE_FLAG_NOCOMPR 0x00000400 /* Don't compress */ 354 #define EXT4_INODE_FLAG_ECOMPR 0x00000800 /* Compression error */ 355 356 #define EXT4_INODE_FLAG_INDEX 0x00001000 /* hash-indexed directory */ 357 #define EXT4_INODE_FLAG_IMAGIC 0x00002000 /* AFS directory */ 358 #define EXT4_INODE_FLAG_JOURNAL_DATA 0x00004000 /* File data should be journaled */ 359 #define EXT4_INODE_FLAG_NOTAIL 0x00008000 /* File tail should not be merged */ 360 #define EXT4_INODE_FLAG_DIRSYNC 0x00010000 /* Dirsync behaviour (directories only) */ 361 #define EXT4_INODE_FLAG_TOPDIR 0x00020000 /* Top of directory hierarchies */ 362 #define EXT4_INODE_FLAG_HUGE_FILE 0x00040000 /* Set to each huge file */ 363 #define EXT4_INODE_FLAG_EXTENTS 0x00080000 /* Inode uses extents */ 364 #define EXT4_INODE_FLAG_EA_INODE 0x00200000 /* Inode used for large EA */ 365 #define EXT4_INODE_FLAG_EOFBLOCKS 0x00400000 /* Blocks allocated beyond EOF */ 366 #define EXT4_INODE_FLAG_RESERVED 0x80000000 /* reserved for ext4 lib */ 367 368 #define EXT4_INODE_ROOT_INDEX 2 374 369 375 370 typedef struct ext4_inode_ref { 376 block_t *block; // Reference to a block containing this inode371 block_t *block; /* Reference to a block containing this inode */ 377 372 ext4_inode_t *inode; 378 373 ext4_filesystem_t *fs; 379 uint32_t index; // Index number of this inode374 uint32_t index; /* Index number of this inode */ 380 375 bool dirty; 381 376 } ext4_inode_ref_t; 382 377 383 /*****************************************************************************/ 384 385 #define EXT4_DIRECTORY_FILENAME_LEN 255 386 387 #define EXT4_DIRECTORY_FILETYPE_UNKNOWN 0 388 #define EXT4_DIRECTORY_FILETYPE_REG_FILE 1 389 #define EXT4_DIRECTORY_FILETYPE_DIR 2 390 #define EXT4_DIRECTORY_FILETYPE_CHRDEV 3 391 #define EXT4_DIRECTORY_FILETYPE_BLKDEV 4 392 #define EXT4_DIRECTORY_FILETYPE_FIFO 5 393 #define EXT4_DIRECTORY_FILETYPE_SOCK 6 394 #define EXT4_DIRECTORY_FILETYPE_SYMLINK 7 378 379 #define EXT4_DIRECTORY_FILENAME_LEN 255 380 381 #define EXT4_DIRECTORY_FILETYPE_UNKNOWN 0 382 #define EXT4_DIRECTORY_FILETYPE_REG_FILE 1 383 #define EXT4_DIRECTORY_FILETYPE_DIR 2 384 #define EXT4_DIRECTORY_FILETYPE_CHRDEV 3 385 #define EXT4_DIRECTORY_FILETYPE_BLKDEV 4 386 #define EXT4_DIRECTORY_FILETYPE_FIFO 5 387 #define EXT4_DIRECTORY_FILETYPE_SOCK 6 388 #define EXT4_DIRECTORY_FILETYPE_SYMLINK 7 395 389 396 390 /** … … 398 392 */ 399 393 typedef struct ext4_directory_entry_ll { 400 uint32_t inode; // Inode for the entry 401 uint16_t entry_length; // Distance to the next directory entry 402 uint8_t name_length; // Lower 8 bits of name length 394 uint32_t inode; /* I-node for the entry */ 395 uint16_t entry_length; /* Distance to the next directory entry */ 396 uint8_t name_length; /* Lower 8 bits of name length */ 397 403 398 union { 404 uint8_t name_length_high; // Higher 8 bits of name length405 uint8_t inode_type; // Type of referenced inode (in rev >= 0.5)399 uint8_t name_length_high; /* Higher 8 bits of name length */ 400 uint8_t inode_type; /* Type of referenced inode (in rev >= 0.5) */ 406 401 } __attribute__ ((packed)); 407 uint8_t name[EXT4_DIRECTORY_FILENAME_LEN]; // Entry name 408 } __attribute__ ((packed)) ext4_directory_entry_ll_t; 402 403 uint8_t name[EXT4_DIRECTORY_FILENAME_LEN]; /* Entry name */ 404 } __attribute__((packed)) ext4_directory_entry_ll_t; 409 405 410 406 typedef struct ext4_directory_iterator { … … 420 416 } ext4_directory_search_result_t; 421 417 422 423 /*****************************************************************************/424 425 418 /* Structures for indexed directory */ 426 419 427 420 typedef struct ext4_directory_dx_countlimit { 428 421 uint16_t limit; 429 uint16_t count;422 uint16_t count; 430 423 } ext4_directory_dx_countlimit_t; 431 424 … … 433 426 uint32_t inode; 434 427 uint16_t entry_length; 435 uint8_t name_length;436 uint8_t inode_type;437 uint8_t name[4];428 uint8_t name_length; 429 uint8_t inode_type; 430 uint8_t name[4]; 438 431 } ext4_directory_dx_dot_entry_t; 439 432 … … 452 445 453 446 typedef struct ext4_directory_dx_root { 454 ext4_directory_dx_dot_entry_t dots[2];455 ext4_directory_dx_root_info_t info;456 ext4_directory_dx_entry_t entries[0];447 ext4_directory_dx_dot_entry_t dots[2]; 448 ext4_directory_dx_root_info_t info; 449 ext4_directory_dx_entry_t entries[0]; 457 450 } ext4_directory_dx_root_t; 458 451 … … 469 462 } ext4_directory_dx_node_t; 470 463 471 472 464 typedef struct ext4_directory_dx_block { 473 465 block_t *block; … … 476 468 } ext4_directory_dx_block_t; 477 469 478 479 480 #define EXT4_ERR_BAD_DX_DIR (-75000) 481 #define EXT4_DIRECTORY_HTREE_EOF (uint32_t)0x7fffffff 482 483 /*****************************************************************************/ 470 #define EXT4_ERR_BAD_DX_DIR (-75000) 471 #define EXT4_DIRECTORY_HTREE_EOF UINT32_C(0x7fffffff) 484 472 485 473 /* … … 488 476 */ 489 477 typedef struct ext4_extent { 490 uint32_t first_block; // First logical block extent covers491 uint16_t block_count; // Number of blocks covered by extent492 uint16_t start_hi; // High 16 bits of physical block493 uint32_t start_lo; // Low 32 bits of physical block478 uint32_t first_block; /* First logical block extent covers */ 479 uint16_t block_count; /* Number of blocks covered by extent */ 480 uint16_t start_hi; /* High 16 bits of physical block */ 481 uint32_t start_lo; /* Low 32 bits of physical block */ 494 482 } ext4_extent_t; 495 483 … … 499 487 */ 500 488 typedef struct ext4_extent_index { 501 uint32_t first_block; // Index covers logical blocks from 'block' 502 uint32_t leaf_lo; /* Pointer to the physical block of the next 503 * level. leaf or next index could be there */ 504 uint16_t leaf_hi; /* high 16 bits of physical block */ 489 uint32_t first_block; /* Index covers logical blocks from 'block' */ 490 491 /** 492 * Pointer to the physical block of the next 493 * level. leaf or next index could be there 494 * high 16 bits of physical block 495 */ 496 uint32_t leaf_lo; 497 uint16_t leaf_hi; 505 498 uint16_t padding; 506 499 } ext4_extent_index_t; … … 511 504 typedef struct ext4_extent_header { 512 505 uint16_t magic; 513 uint16_t entries_count; // Number of valid entries514 uint16_t max_entries_count; // Capacity of store in entries515 uint16_t depth; // Has tree real underlying blocks?516 uint32_t generation; // generation of the tree506 uint16_t entries_count; /* Number of valid entries */ 507 uint16_t max_entries_count; /* Capacity of store in entries */ 508 uint16_t depth; /* Has tree real underlying blocks? */ 509 uint32_t generation; /* generation of the tree */ 517 510 } ext4_extent_header_t; 518 511 … … 525 518 } ext4_extent_path_t; 526 519 527 #define EXT4_EXTENT_MAGIC 0xF30A528 #define EXT4_EXTENT_FIRST(header) \ 529 ((ext4_extent_t *) (((void *) (header)) + sizeof(ext4_extent_header_t))) 530 #define EXT4_EXTENT_FIRST_INDEX(header) \ 531 ((ext4_extent_index_t *) (((void *) (header)) + sizeof(ext4_extent_header_t))) 532 533 /*****************************************************************************/ 534 535 #define EXT4_HASH_VERSION_LEGACY 0536 #define EXT4_HASH_VERSION_HALF_MD4 1537 #define EXT4_HASH_VERSION_TEA 2538 #define EXT4_HASH_VERSION_LEGACY_UNSIGNED 3539 #define EXT4_HASH_VERSION_HALF_MD4_UNSIGNED 4540 #define EXT4_HASH_VERSION_TEA_UNSIGNED 5520 #define EXT4_EXTENT_MAGIC 0xF30A 521 522 #define EXT4_EXTENT_FIRST(header) \ 523 ((ext4_extent_t *) (((void *) (header)) + sizeof(ext4_extent_header_t))) 524 525 #define EXT4_EXTENT_FIRST_INDEX(header) \ 526 ((ext4_extent_index_t *) (((void *) (header)) + sizeof(ext4_extent_header_t))) 527 528 #define EXT4_HASH_VERSION_LEGACY 0 529 #define EXT4_HASH_VERSION_HALF_MD4 1 530 #define EXT4_HASH_VERSION_TEA 2 531 #define EXT4_HASH_VERSION_LEGACY_UNSIGNED 3 532 #define EXT4_HASH_VERSION_HALF_MD4_UNSIGNED 4 533 #define EXT4_HASH_VERSION_TEA_UNSIGNED 5 541 534 542 535 typedef struct ext4_hash_info { -
uspace/srv/fs/ext4fs/Makefile
rb08e7970 r38542dc 28 28 29 29 USPACE_PREFIX = ../../.. 30 LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a $(LIBEXT4_PREFIX)/libext4.a $(LIBPOSIX_PREFIX)/libposix.a31 EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX) -I$(LIBEXT4_PREFIX) -I$(LIBPOSIX_PREFIX)30 LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a $(LIBEXT4_PREFIX)/libext4.a 31 EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX) -I$(LIBEXT4_PREFIX) 32 32 BINARY = ext4fs 33 33 -
uspace/srv/fs/ext4fs/ext4fs.c
rb08e7970 r38542dc 29 29 /** @addtogroup fs 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file ext4fs.c35 * @brief EXT4 file system driver for HelenOS.33 * @file ext4fs.c 34 * @brief Ext4 file system driver for HelenOS. 36 35 */ 37 36 … … 46 45 #include "../../vfs/vfs.h" 47 46 48 #define NAME "ext4fs"47 #define NAME "ext4fs" 49 48 50 49 vfs_info_t ext4fs_vfs_info = { 51 50 .name = NAME, 52 .instance = 0 ,51 .instance = 0 53 52 }; 54 53 55 /**56 * Entry point of ext4fs server.57 * Initialize data structures and IPC, then accepts connections in server mode.58 */59 54 int main(int argc, char **argv) 60 55 { 61 printf( NAME ": HelenOS EXT4 file system server\n");62 56 printf("%s: HelenOS EXT4 file system server\n", NAME); 57 63 58 if (argc == 3) { 64 59 if (!str_cmp(argv[1], "--instance")) 65 60 ext4fs_vfs_info.instance = strtol(argv[2], NULL, 10); 66 61 else { 67 printf( NAME " Unrecognized parameters\n");68 return -1;62 printf("%s: Unrecognized parameters\n", NAME); 63 return 1; 69 64 } 70 65 } 71 66 72 67 async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE, 73 SERVICE_VFS, 0, 0);68 SERVICE_VFS, 0, 0); 74 69 if (!vfs_sess) { 75 printf( NAME ": failed to connect to VFS\n");76 return -1;70 printf("%s: Failed to connect to VFS\n", NAME); 71 return 2; 77 72 } 78 73 79 74 int rc = ext4fs_global_init(); 80 75 if (rc != EOK) { 81 printf( NAME ": Failed global initialization\n");82 return 1;76 printf("%s: Global initialization failed\n", NAME); 77 return rc; 83 78 } 84 79 85 80 rc = fs_register(vfs_sess, &ext4fs_vfs_info, &ext4fs_ops, 86 81 &ext4fs_libfs_ops); 87 82 if (rc != EOK) { 88 fprintf(stdout, NAME ": Failed to register fs (%d)\n", rc);89 return 1;83 printf("%s: Failed to register file system\n", NAME); 84 return rc; 90 85 } 91 92 printf( NAME ": Accepting connections\n");86 87 printf("%s: Accepting connections\n", NAME); 93 88 task_retval(0); 94 89 async_manager(); 95 /* not reached */ 90 91 /* Not reached */ 96 92 return 0; 97 93 } … … 99 95 /** 100 96 * @} 101 */ 97 */ -
uspace/srv/fs/ext4fs/ext4fs.h
rb08e7970 r38542dc 29 29 /** @addtogroup fs 30 30 * @{ 31 */ 31 */ 32 32 33 33 #ifndef EXT4FS_EXT4FS_H_ -
uspace/srv/fs/ext4fs/ext4fs_ops.c
rb08e7970 r38542dc 29 29 /** @addtogroup fs 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file ext4fs_ops.c35 * @brief VFS operations for EXT4 filesystem.33 * @file ext4fs_ops.c 34 * @brief VFS operations for ext4 filesystem. 36 35 */ 37 36 … … 42 41 #include <macros.h> 43 42 #include <malloc.h> 44 #include <string.h>45 43 #include <adt/hash_table.h> 46 44 #include <ipc/loc.h> … … 48 46 #include "../../vfs/vfs.h" 49 47 50 #define EXT4FS_NODE(node) ((node) ? (ext4fs_node_t *) (node)->data : NULL) 51 52 #define OPEN_NODES_KEYS 2 53 #define OPEN_NODES_DEV_HANDLE_KEY 0 54 #define OPEN_NODES_INODE_KEY 1 55 #define OPEN_NODES_BUCKETS 256 48 #define EXT4FS_NODE(node) \ 49 ((node) ? (ext4fs_node_t *) (node)->data : NULL) 50 51 #define OPEN_NODES_KEYS 2 52 53 #define OPEN_NODES_DEV_HANDLE_KEY 0 54 #define OPEN_NODES_INODE_KEY 1 55 56 #define OPEN_NODES_BUCKETS 256 56 57 57 58 /** … … 87 88 static int ext4fs_node_put_core(ext4fs_node_t *); 88 89 89 /* Forward declarations of EXT4 libfs operations. */90 /* Forward declarations of ext4 libfs operations. */ 90 91 91 92 static int ext4fs_root_get(fs_node_t **, service_id_t); … … 122 123 /** Compare given item with values in hash table. 123 124 * 124 * @return bool result of compare operation125 125 */ 126 126 static int open_nodes_compare(unsigned long key[], hash_count_t keys, 127 127 link_t *item) 128 128 { 129 ext4fs_node_t *enode = hash_table_get_instance(item, ext4fs_node_t, link);130 129 assert(keys > 0); 130 131 ext4fs_node_t *enode = 132 hash_table_get_instance(item, ext4fs_node_t, link); 133 131 134 if (enode->instance->service_id != 132 ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {135 ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) 133 136 return false; 134 }135 if (keys == 1) {137 138 if (keys == 1) 136 139 return true; 137 }140 138 141 assert(keys == 2); 142 139 143 return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]); 140 144 } … … 154 158 }; 155 159 156 157 160 /** Basic initialization of the driver. 158 161 * 159 * There is only needed to create hash table for storing open nodes. 160 * 161 * @return error code 162 * This is only needed to create the hash table 163 * for storing open nodes. 164 * 165 * @return Error code 166 * 162 167 */ 163 168 int ext4fs_global_init(void) 164 169 { 165 170 if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS, 166 OPEN_NODES_KEYS, &open_nodes_ops)) {171 OPEN_NODES_KEYS, &open_nodes_ops)) 167 172 return ENOMEM; 168 }173 169 174 return EOK; 170 175 } … … 172 177 /* Finalization of the driver. 173 178 * 174 * Th ere is only needed to destroyhash table.175 * 176 * @return error code179 * This is only needed to destroy the hash table. 180 * 181 * @return Error code 177 182 */ 178 183 int ext4fs_global_fini(void) … … 182 187 } 183 188 184 185 189 /* 186 * E XT4 libfs operations.190 * Ext4 libfs operations. 187 191 */ 188 192 189 193 /** Get instance from internal table by service_id. 190 194 * 191 * @param service_id device identifier 192 * @param inst output instance if successful operation 193 * @return error code 195 * @param service_id Device identifier 196 * @param inst Output instance if successful operation 197 * 198 * @return Error code 199 * 194 200 */ 195 201 int ext4fs_instance_get(service_id_t service_id, ext4fs_instance_t **inst) 196 202 { 197 203 fibril_mutex_lock(&instance_list_mutex); 198 204 199 205 if (list_empty(&instance_list)) { 200 206 fibril_mutex_unlock(&instance_list_mutex); 201 207 return EINVAL; 202 208 } 203 204 ext4fs_instance_t *tmp; 209 205 210 list_foreach(instance_list, link) { 206 tmp = list_get_instance(link, ext4fs_instance_t, link); 207 211 ext4fs_instance_t *tmp = 212 list_get_instance(link, ext4fs_instance_t, link); 213 208 214 if (tmp->service_id == service_id) { 209 215 *inst = tmp; … … 212 218 } 213 219 } 214 220 215 221 fibril_mutex_unlock(&instance_list_mutex); 216 222 return EINVAL; 217 223 } 218 224 219 220 225 /** Get root node of filesystem specified by service_id. 221 226 * 222 * @param rfn output pointer to loaded node 223 * @param service_id device to load root node from 224 * @return error code 227 * @param rfn Output pointer to loaded node 228 * @param service_id Device to load root node from 229 * 230 * @return Error code 231 * 225 232 */ 226 233 int ext4fs_root_get(fs_node_t **rfn, service_id_t service_id) … … 233 240 * If match is found, load and return matching node. 234 241 * 235 * @param rfn output pointer to node if operation successful 236 * @param pfn parent directory node 237 * @param component name to check directory for 238 * @return error code 242 * @param rfn Output pointer to node if operation successful 243 * @param pfn Parent directory node 244 * @param component Name to check directory for 245 * 246 * @return Error code 247 * 239 248 */ 240 249 int ext4fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component) 241 250 { 242 int rc;243 244 251 ext4fs_node_t *eparent = EXT4FS_NODE(pfn); 245 252 ext4_filesystem_t *fs = eparent->instance->filesystem; 246 253 247 254 if (!ext4_inode_is_type(fs->superblock, eparent->inode_ref->inode, 248 EXT4_INODE_MODE_DIRECTORY)) {255 EXT4_INODE_MODE_DIRECTORY)) 249 256 return ENOTDIR; 250 } 251 257 252 258 /* Try to find entry */ 253 259 ext4_directory_search_result_t result; 254 rc = ext4_directory_find_entry(&result, eparent->inode_ref, component); 260 int rc = ext4_directory_find_entry(&result, eparent->inode_ref, 261 component); 255 262 if (rc != EOK) { 256 263 if (rc == ENOENT) { … … 258 265 return EOK; 259 266 } 260 return rc; 261 } 262 267 268 return rc; 269 } 270 263 271 /* Load node from search result */ 264 272 uint32_t inode = ext4_directory_entry_ll_get_inode(result.dentry); 265 273 rc = ext4fs_node_get_core(rfn, eparent->instance, inode); 266 if (rc != EOK) { 267 return rc; 268 } 269 274 if (rc != EOK) 275 return rc; 276 270 277 /* Destroy search result structure */ 271 rc = ext4_directory_destroy_result(&result); 272 if (rc != EOK) { 273 return rc; 274 } 275 276 return EOK; 278 return ext4_directory_destroy_result(&result); 277 279 } 278 280 … … 281 283 * It's wrapper for node_put_core operation 282 284 * 283 * @param rfn output pointer to loaded node if operation successful 284 * @param service_id device identifier 285 * @param index node index (here i-node number) 286 * @return error code 285 * @param rfn Output pointer to loaded node if operation successful 286 * @param service_id Device identifier 287 * @param index Node index (here i-node number) 288 * 289 * @return Error code 290 * 287 291 */ 288 292 int ext4fs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index) 289 293 { 290 int rc;291 292 294 ext4fs_instance_t *inst; 293 rc = ext4fs_instance_get(service_id, &inst); 294 if (rc != EOK) { 295 return rc; 296 } 297 295 int rc = ext4fs_instance_get(service_id, &inst); 296 if (rc != EOK) 297 return rc; 298 298 299 return ext4fs_node_get_core(rfn, inst, index); 299 300 } … … 301 302 /** Main function for getting node from the filesystem. 302 303 * 303 * @param rfn output point to loaded node if operation successful 304 * @param inst instance of filesystem 305 * @param index index of node (i-node number) 306 * @return error code 304 * @param rfn Output point to loaded node if operation successful 305 * @param inst Instance of filesystem 306 * @param index Index of node (i-node number) 307 * 308 * @return Error code 309 * 307 310 */ 308 311 int ext4fs_node_get_core(fs_node_t **rfn, ext4fs_instance_t *inst, 309 fs_index_t index) 310 { 311 int rc; 312 312 fs_index_t index) 313 { 313 314 fibril_mutex_lock(&open_nodes_lock); 314 315 315 316 /* Check if the node is not already open */ 316 317 unsigned long key[] = { 317 318 [OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id, 318 [OPEN_NODES_INODE_KEY] = index ,319 [OPEN_NODES_INODE_KEY] = index 319 320 }; 320 321 321 322 link_t *already_open = hash_table_find(&open_nodes, key); 322 323 ext4fs_node_t *enode = NULL; … … 325 326 *rfn = enode->fs_node; 326 327 enode->references++; 327 328 328 329 fibril_mutex_unlock(&open_nodes_lock); 329 330 return EOK; 330 331 } 331 332 332 333 /* Prepare new enode */ 333 334 enode = malloc(sizeof(ext4fs_node_t)); … … 336 337 return ENOMEM; 337 338 } 338 339 339 340 /* Prepare new fs_node and initialize */ 340 341 fs_node_t *fs_node = malloc(sizeof(fs_node_t)); … … 344 345 return ENOMEM; 345 346 } 347 346 348 fs_node_initialize(fs_node); 347 349 348 350 /* Load i-node from filesystem */ 349 351 ext4_inode_ref_t *inode_ref; 350 rc = ext4_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref); 352 int rc = ext4_filesystem_get_inode_ref(inst->filesystem, index, 353 &inode_ref); 351 354 if (rc != EOK) { 352 355 free(enode); … … 355 358 return rc; 356 359 } 357 360 358 361 /* Initialize enode */ 359 362 enode->inode_ref = inode_ref; … … 362 365 enode->fs_node = fs_node; 363 366 link_initialize(&enode->link); 364 367 365 368 fs_node->data = enode; 366 369 *rfn = fs_node; 367 370 368 371 hash_table_insert(&open_nodes, key, &enode->link); 369 372 inst->open_nodes_count++; 370 373 371 374 fibril_mutex_unlock(&open_nodes_lock); 372 375 373 376 return EOK; 374 377 } … … 376 379 /** Put previously loaded node. 377 380 * 378 * @param enode node to put back 379 * @return error code 381 * @param enode Node to put back 382 * 383 * @return Error code 384 * 380 385 */ 381 386 int ext4fs_node_put_core(ext4fs_node_t *enode) 382 387 { 383 int rc;384 388 unsigned long key[] = { 385 389 [OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id, 386 [OPEN_NODES_INODE_KEY] = enode->inode_ref->index ,390 [OPEN_NODES_INODE_KEY] = enode->inode_ref->index 387 391 }; 388 392 389 393 hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS); 390 394 assert(enode->instance->open_nodes_count > 0); 391 395 enode->instance->open_nodes_count--; 392 396 393 397 /* Put inode back in filesystem */ 394 rc = ext4_filesystem_put_inode_ref(enode->inode_ref); 395 if (rc != EOK) { 396 return rc; 397 } 398 398 int rc = ext4_filesystem_put_inode_ref(enode->inode_ref); 399 if (rc != EOK) 400 return rc; 401 399 402 /* Destroy data structure */ 400 403 free(enode->fs_node); 401 404 free(enode); 402 405 403 406 return EOK; 404 407 } 405 408 406 407 409 /** Open node. 408 410 * 409 411 * This operation is stateless in this driver. 410 412 * 411 * @param fn node to open 412 * @return error code (EOK) 413 * @param fn Node to open 414 * 415 * @return EOK 416 * 413 417 */ 414 418 int ext4fs_node_open(fs_node_t *fn) … … 418 422 } 419 423 420 421 424 /** Put previously loaded node. 422 425 * 423 * It's wrapper for node_put_core operation 424 * 425 * @param fn node to put back 426 * @return error code 426 * A wrapper for node_put_core operation 427 * 428 * @param fn Node to put back 429 * @return Error code 430 * 427 431 */ 428 432 int ext4fs_node_put(fs_node_t *fn) 429 433 { 430 int rc;431 432 434 fibril_mutex_lock(&open_nodes_lock); 433 435 434 436 ext4fs_node_t *enode = EXT4FS_NODE(fn); 435 437 assert(enode->references > 0); 436 438 enode->references--; 437 439 if (enode->references == 0) { 438 rc = ext4fs_node_put_core(enode);440 int rc = ext4fs_node_put_core(enode); 439 441 if (rc != EOK) { 440 442 fibril_mutex_unlock(&open_nodes_lock); … … 442 444 } 443 445 } 444 446 445 447 fibril_mutex_unlock(&open_nodes_lock); 446 448 447 449 return EOK; 448 450 } 449 451 450 451 452 /** Create new node in filesystem. 452 453 * 453 * @param rfn output pointer to newly created node if successful 454 * @param service_id device identifier, where the filesystem is 455 * @param flags flags for specification of new node parameters 456 * @return error code 454 * @param rfn Output pointer to newly created node if successful 455 * @param service_id Device identifier, where the filesystem is 456 * @param flags Flags for specification of new node parameters 457 * 458 * @return Error code 459 * 457 460 */ 458 461 int ext4fs_create_node(fs_node_t **rfn, service_id_t service_id, int flags) 459 462 { 460 int rc;461 462 463 /* Allocate enode */ 463 464 ext4fs_node_t *enode; 464 465 enode = malloc(sizeof(ext4fs_node_t)); 465 if (enode == NULL) {466 if (enode == NULL) 466 467 return ENOMEM; 467 } 468 468 469 469 /* Allocate fs_node */ 470 470 fs_node_t *fs_node; … … 474 474 return ENOMEM; 475 475 } 476 476 477 477 /* Load instance */ 478 478 ext4fs_instance_t *inst; 479 rc = ext4fs_instance_get(service_id, &inst);479 int rc = ext4fs_instance_get(service_id, &inst); 480 480 if (rc != EOK) { 481 481 free(enode); … … 483 483 return rc; 484 484 } 485 485 486 486 /* Allocate new i-node in filesystem */ 487 487 ext4_inode_ref_t *inode_ref; … … 492 492 return rc; 493 493 } 494 494 495 495 /* Do some interconnections in references */ 496 496 enode->inode_ref = inode_ref; 497 497 enode->instance = inst; 498 498 enode->references = 1; 499 499 500 500 link_initialize(&enode->link); 501 501 502 502 unsigned long key[] = { 503 503 [OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id, 504 [OPEN_NODES_INODE_KEY] = inode_ref->index ,504 [OPEN_NODES_INODE_KEY] = inode_ref->index 505 505 }; 506 506 507 507 fibril_mutex_lock(&open_nodes_lock); 508 508 hash_table_insert(&open_nodes, key, &enode->link); 509 509 fibril_mutex_unlock(&open_nodes_lock); 510 510 inst->open_nodes_count++; 511 511 512 512 enode->inode_ref->dirty = true; 513 513 514 514 fs_node_initialize(fs_node); 515 515 fs_node->data = enode; 516 516 enode->fs_node = fs_node; 517 517 *rfn = fs_node; 518 518 519 519 return EOK; 520 520 } 521 521 522 523 522 /** Destroy existing node. 524 523 * 525 * @param fs node to destroy 526 * @return error code 524 * @param fs Node to destroy 525 * 526 * @return Error code 527 * 527 528 */ 528 529 int ext4fs_destroy_node(fs_node_t *fn) 529 530 { 530 int rc;531 532 531 /* If directory, check for children */ 533 532 bool has_children; 534 rc = ext4fs_has_children(&has_children, fn);533 int rc = ext4fs_has_children(&has_children, fn); 535 534 if (rc != EOK) { 536 535 ext4fs_node_put(fn); 537 536 return rc; 538 537 } 539 538 540 539 if (has_children) { 541 540 ext4fs_node_put(fn); 542 541 return EINVAL; 543 542 } 544 543 545 544 ext4fs_node_t *enode = EXT4FS_NODE(fn); 546 545 ext4_inode_ref_t *inode_ref = enode->inode_ref; 547 546 548 547 /* Release data blocks */ 549 548 rc = ext4_filesystem_truncate_inode(inode_ref, 0); … … 552 551 return rc; 553 552 } 554 555 // TODO set real deletion time when it will be supported, temporary set fake time 556 // time_t now = time(NULL); 553 554 /* 555 * TODO: Sset real deletion time when it will be supported. 556 * Temporary set fake deletion time. 557 */ 557 558 ext4_inode_set_deletion_time(inode_ref->inode, 0xdeadbeef); 558 559 inode_ref->dirty = true; 559 560 560 561 /* Free inode */ 561 562 rc = ext4_filesystem_free_inode(inode_ref); … … 564 565 return rc; 565 566 } 566 567 567 568 return ext4fs_node_put(fn); 568 569 } 569 570 570 571 571 /** Link the specfied node to directory. 572 572 * 573 * @param pfn parent node to link in 574 * @param cfn node to be linked 575 * @param name name which will be assigned to directory entry 576 * @return error code 573 * @param pfn Parent node to link in 574 * @param cfn Node to be linked 575 * @param name Name which will be assigned to directory entry 576 * 577 * @return Error code 578 * 577 579 */ 578 580 int ext4fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name) 579 581 { 580 int rc;581 582 582 /* Check maximum name length */ 583 if (str len(name) > EXT4_DIRECTORY_FILENAME_LEN) {583 if (str_size(name) > EXT4_DIRECTORY_FILENAME_LEN) 584 584 return ENAMETOOLONG; 585 }585 586 586 ext4fs_node_t *parent = EXT4FS_NODE(pfn); 587 587 ext4fs_node_t *child = EXT4FS_NODE(cfn); 588 588 ext4_filesystem_t *fs = parent->instance->filesystem; 589 589 590 590 /* Add entry to parent directory */ 591 rc = ext4_directory_add_entry(parent->inode_ref, name, child->inode_ref);592 if (rc != EOK) {593 return rc;594 }595 591 int rc = ext4_directory_add_entry(parent->inode_ref, name, 592 child->inode_ref); 593 if (rc != EOK) 594 return rc; 595 596 596 /* Fill new dir -> add '.' and '..' entries */ 597 if (ext4_inode_is_type(fs->superblock, child->inode_ref->inode, EXT4_INODE_MODE_DIRECTORY)) { 598 599 rc = ext4_directory_add_entry(child->inode_ref, ".", child->inode_ref); 597 if (ext4_inode_is_type(fs->superblock, child->inode_ref->inode, 598 EXT4_INODE_MODE_DIRECTORY)) { 599 rc = ext4_directory_add_entry(child->inode_ref, ".", 600 child->inode_ref); 600 601 if (rc != EOK) { 601 602 ext4_directory_remove_entry(parent->inode_ref, name); 602 603 return rc; 603 604 } 604 605 rc = ext4_directory_add_entry(child->inode_ref, "..", parent->inode_ref); 605 606 rc = ext4_directory_add_entry(child->inode_ref, "..", 607 parent->inode_ref); 606 608 if (rc != EOK) { 607 609 ext4_directory_remove_entry(parent->inode_ref, name); … … 609 611 return rc; 610 612 } 611 613 612 614 /* Initialize directory index if supported */ 613 if (ext4_superblock_has_feature_compatible( 614 fs->superblock, EXT4_FEATURE_COMPAT_DIR_INDEX)) { 615 615 if (ext4_superblock_has_feature_compatible(fs->superblock, 616 EXT4_FEATURE_COMPAT_DIR_INDEX)) { 616 617 rc = ext4_directory_dx_init(child->inode_ref); 617 if (rc != EOK) {618 if (rc != EOK) 618 619 return rc; 619 }620 621 ext4_inode_set_flag(child->inode_ref->inode,EXT4_INODE_FLAG_INDEX);620 621 ext4_inode_set_flag(child->inode_ref->inode, 622 EXT4_INODE_FLAG_INDEX); 622 623 child->inode_ref->dirty = true; 623 624 } 624 625 uint16_t parent_links = ext4_inode_get_links_count(parent->inode_ref->inode); 625 626 uint16_t parent_links = 627 ext4_inode_get_links_count(parent->inode_ref->inode); 626 628 parent_links++; 627 629 ext4_inode_set_links_count(parent->inode_ref->inode, parent_links); 628 630 629 631 parent->inode_ref->dirty = true; 630 631 }632 633 uint16_t child_links =ext4_inode_get_links_count(child->inode_ref->inode);632 } 633 634 uint16_t child_links = 635 ext4_inode_get_links_count(child->inode_ref->inode); 634 636 child_links++; 635 637 ext4_inode_set_links_count(child->inode_ref->inode, child_links); 636 638 637 639 child->inode_ref->dirty = true; 638 640 639 641 return EOK; 640 642 } 641 643 642 643 644 /** Unlink node from specified directory. 644 645 * 645 * @param pfn parent node to delete node from 646 * @param cfn child node to be unlinked from directory 647 * @param name name of entry that will be removed 648 * @return error code 646 * @param pfn Parent node to delete node from 647 * @param cfn Child node to be unlinked from directory 648 * @param name Name of entry that will be removed 649 * 650 * @return Error code 651 * 649 652 */ 650 653 int ext4fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *name) 651 654 { 652 int rc;653 654 655 bool has_children; 655 rc = ext4fs_has_children(&has_children, cfn); 656 if (rc != EOK) { 657 return rc; 658 } 659 656 int rc = ext4fs_has_children(&has_children, cfn); 657 if (rc != EOK) 658 return rc; 659 660 660 /* Cannot unlink non-empty node */ 661 if (has_children) {661 if (has_children) 662 662 return ENOTEMPTY; 663 } 664 663 665 664 /* Remove entry from parent directory */ 666 665 ext4_inode_ref_t *parent = EXT4FS_NODE(pfn)->inode_ref; 667 666 rc = ext4_directory_remove_entry(parent, name); 668 if (rc != EOK) { 669 return rc; 670 } 671 667 if (rc != EOK) 668 return rc; 669 672 670 /* Decrement links count */ 673 ext4_inode_ref_t * child_inode_ref = EXT4FS_NODE(cfn)->inode_ref; 674 675 uint32_t lnk_count = ext4_inode_get_links_count(child_inode_ref->inode); 671 ext4_inode_ref_t *child_inode_ref = EXT4FS_NODE(cfn)->inode_ref; 672 673 uint32_t lnk_count = 674 ext4_inode_get_links_count(child_inode_ref->inode); 676 675 lnk_count--; 677 676 678 677 /* If directory - handle links from parent */ 679 if (lnk_count <= 1 && ext4fs_is_directory(cfn)) { 680 678 if ((lnk_count <= 1) && (ext4fs_is_directory(cfn))) { 681 679 assert(lnk_count == 1); 680 682 681 lnk_count--; 683 682 684 683 ext4_inode_ref_t *parent_inode_ref = EXT4FS_NODE(pfn)->inode_ref; 685 684 686 685 uint32_t parent_lnk_count = ext4_inode_get_links_count( 687 parent_inode_ref->inode);688 686 parent_inode_ref->inode); 687 689 688 parent_lnk_count--; 690 689 ext4_inode_set_links_count(parent_inode_ref->inode, parent_lnk_count); 691 690 692 691 parent->dirty = true; 693 692 } 694 693 695 // TODO set timestamps for parent (when we have wall-clock time) 696 // time_t now = time(NULL); 697 // ext4_inode_set_change_inode_time(parent->inode, (uint32_t)now); 698 // ext4_inode_set_modification_time(parent->inode, (uint32_t)now); 699 // parent->dirty = true; 700 701 // TODO set timestamp for inode 702 // ext4_inode_set_change_inode_time(child_inode_ref->inode, (uint32_t)now); 694 /* 695 * TODO: Update timestamps of the parent 696 * (when we have wall-clock time). 697 * 698 * ext4_inode_set_change_inode_time(parent->inode, (uint32_t) now); 699 * ext4_inode_set_modification_time(parent->inode, (uint32_t) now); 700 * parent->dirty = true; 701 */ 702 703 /* 704 * TODO: Update timestamp for inode. 705 * 706 * ext4_inode_set_change_inode_time(child_inode_ref->inode, 707 * (uint32_t) now); 708 */ 709 703 710 ext4_inode_set_links_count(child_inode_ref->inode, lnk_count); 704 711 child_inode_ref->dirty = true; 705 712 706 713 return EOK; 707 714 } 708 715 709 710 716 /** Check if specified node has children. 711 * 717 * 712 718 * For files is response allways false and check is executed only for directories. 713 719 * 714 * @param has_children output value for response 715 * @param fn node to check 716 * @return error code 720 * @param has_children Output value for response 721 * @param fn Node to check 722 * 723 * @return Error code 724 * 717 725 */ 718 726 int ext4fs_has_children(bool *has_children, fs_node_t *fn) 719 727 { 720 int rc;721 722 728 ext4fs_node_t *enode = EXT4FS_NODE(fn); 723 729 ext4_filesystem_t *fs = enode->instance->filesystem; 724 730 725 731 /* Check if node is directory */ 726 732 if (!ext4_inode_is_type(fs->superblock, enode->inode_ref->inode, … … 729 735 return EOK; 730 736 } 731 737 732 738 ext4_directory_iterator_t it; 733 rc = ext4_directory_iterator_init(&it, enode->inode_ref, 0); 734 if (rc != EOK) { 735 return rc; 736 } 737 739 int rc = ext4_directory_iterator_init(&it, enode->inode_ref, 0); 740 if (rc != EOK) 741 return rc; 742 738 743 /* Find a non-empty directory entry */ 739 744 bool found = false; 740 745 while (it.current != NULL) { 741 746 if (it.current->inode != 0) { 742 uint16_t name_size = ext4_directory_entry_ll_get_name_length(fs->superblock, 743 it.current); 747 uint16_t name_size = 748 ext4_directory_entry_ll_get_name_length(fs->superblock, 749 it.current); 744 750 if (!ext4fs_is_dots(it.current->name, name_size)) { 745 751 found = true; … … 747 753 } 748 754 } 749 755 750 756 rc = ext4_directory_iterator_next(&it); 751 757 if (rc != EOK) { … … 754 760 } 755 761 } 756 762 757 763 rc = ext4_directory_iterator_fini(&it); 758 if (rc != EOK) { 759 return rc; 760 } 761 764 if (rc != EOK) 765 return rc; 766 762 767 *has_children = found; 763 768 764 769 return EOK; 765 770 } 766 771 767 768 772 /** Unpack index number from node. 769 * 770 * @param fn node to load index from 771 * @return index number of i-node 773 * 774 * @param fn Node to load index from 775 * 776 * @return Index number of i-node 777 * 772 778 */ 773 779 fs_index_t ext4fs_index_get(fs_node_t *fn) … … 777 783 } 778 784 779 780 785 /** Get real size of file / directory. 781 786 * 782 * @param fn node to get size of 783 * @return real size of node 787 * @param fn Node to get size of 788 * 789 * @return Real size of node 790 * 784 791 */ 785 792 aoff64_t ext4fs_size_get(fs_node_t *fn) … … 790 797 } 791 798 792 793 799 /** Get number of links to specified node. 794 800 * 795 * @param fn node to get links to 796 * @return number of links 801 * @param fn Node to get links to 802 * 803 * @return Number of links 804 * 797 805 */ 798 806 unsigned ext4fs_lnkcnt_get(fs_node_t *fn) … … 800 808 ext4fs_node_t *enode = EXT4FS_NODE(fn); 801 809 uint32_t lnkcnt = ext4_inode_get_links_count(enode->inode_ref->inode); 802 810 803 811 if (ext4fs_is_directory(fn)) { 804 if (lnkcnt > 1) {812 if (lnkcnt > 1) 805 813 return 1; 806 } else {814 else 807 815 return 0; 808 } 809 } 810 816 } 817 811 818 /* For regular files return real links count */ 812 819 return lnkcnt; 813 820 } 814 821 815 816 822 /** Check if node is directory. 817 823 * 818 * @param fn node to check 819 * @return result of check 824 * @param fn Node to check 825 * 826 * @return Result of check 827 * 820 828 */ 821 829 bool ext4fs_is_directory(fs_node_t *fn) … … 823 831 ext4fs_node_t *enode = EXT4FS_NODE(fn); 824 832 ext4_superblock_t *sb = enode->instance->filesystem->superblock; 825 return ext4_inode_is_type(826 sb, enode->inode_ref->inode, EXT4_INODE_MODE_DIRECTORY);827 } 828 833 834 return ext4_inode_is_type(sb, enode->inode_ref->inode, 835 EXT4_INODE_MODE_DIRECTORY); 836 } 829 837 830 838 /** Check if node is regular file. 831 839 * 832 * @param fn node to check 833 * @return result of check 840 * @param fn Node to check 841 * 842 * @return Result of check 843 * 834 844 */ 835 845 bool ext4fs_is_file(fs_node_t *fn) … … 837 847 ext4fs_node_t *enode = EXT4FS_NODE(fn); 838 848 ext4_superblock_t *sb = enode->instance->filesystem->superblock; 839 return ext4_inode_is_type( 840 sb, enode->inode_ref->inode, EXT4_INODE_MODE_FILE); 849 850 return ext4_inode_is_type(sb, enode->inode_ref->inode, 851 EXT4_INODE_MODE_FILE); 841 852 } 842 853 843 854 /** Extract device identifier from node. 844 855 * 845 * @param node node to extract id from 846 * @return id of device, where is the filesystem 856 * @param node Node to extract id from 857 * 858 * @return id of device, where is the filesystem 859 * 847 860 */ 848 861 service_id_t ext4fs_service_get(fs_node_t *fn) … … 874 887 }; 875 888 876 877 889 /* 878 890 * VFS operations. 879 891 */ 880 892 881 /** Mount operation. 893 /** Mount operation. 882 894 * 883 895 * Try to mount specified filesystem from device. 884 * 885 * @param service_id identifier of device 886 * @param opts mount options 887 * @param index output value - index of root node 888 * @param size output value - size of root node 889 * @param lnkcnt output value - link count of root node 890 * @return error code 896 * 897 * @param service_id Identifier of device 898 * @param opts Mount options 899 * @param index Output value - index of root node 900 * @param size Output value - size of root node 901 * @param lnkcnt Output value - link count of root node 902 * 903 * @return Error code 904 * 891 905 */ 892 906 static int ext4fs_mounted(service_id_t service_id, const char *opts, 893 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt) 894 { 895 int rc; 896 907 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt) 908 { 897 909 /* Allocate libext4 filesystem structure */ 898 ext4_filesystem_t *fs ;899 fs = (ext4_filesystem_t *)malloc(sizeof(ext4_filesystem_t));900 if (fs == NULL) {910 ext4_filesystem_t *fs = (ext4_filesystem_t *) 911 malloc(sizeof(ext4_filesystem_t)); 912 if (fs == NULL) 901 913 return ENOMEM; 902 } 903 914 904 915 /* Allocate instance structure */ 905 ext4fs_instance_t *inst ;906 inst = (ext4fs_instance_t *)malloc(sizeof(ext4fs_instance_t));916 ext4fs_instance_t *inst = (ext4fs_instance_t *) 917 malloc(sizeof(ext4fs_instance_t)); 907 918 if (inst == NULL) { 908 919 free(fs); 909 920 return ENOMEM; 910 921 } 911 922 912 923 enum cache_mode cmode; 913 if (str_cmp(opts, "wtcache") == 0) {924 if (str_cmp(opts, "wtcache") == 0) 914 925 cmode = CACHE_MODE_WT; 915 } else {926 else 916 927 cmode = CACHE_MODE_WB; 917 } 918 928 919 929 /* Initialize the filesystem */ 920 rc = ext4_filesystem_init(fs, service_id, cmode);930 int rc = ext4_filesystem_init(fs, service_id, cmode); 921 931 if (rc != EOK) { 922 932 free(fs); … … 924 934 return rc; 925 935 } 926 936 927 937 /* Do some sanity checking */ 928 938 rc = ext4_filesystem_check_sanity(fs); … … 933 943 return rc; 934 944 } 935 945 936 946 /* Check flags */ 937 947 bool read_only; … … 943 953 return rc; 944 954 } 945 955 946 956 /* Initialize instance */ 947 957 link_initialize(&inst->link); … … 949 959 inst->filesystem = fs; 950 960 inst->open_nodes_count = 0; 951 961 952 962 /* Read root node */ 953 963 fs_node_t *root_node; … … 959 969 return rc; 960 970 } 961 971 962 972 /* Add instance to the list */ 963 973 fibril_mutex_lock(&instance_list_mutex); 964 974 list_append(&inst->link, &instance_list); 965 975 fibril_mutex_unlock(&instance_list_mutex); 966 976 967 977 ext4fs_node_t *enode = EXT4FS_NODE(root_node); 968 978 969 979 *index = EXT4_INODE_ROOT_INDEX; 970 980 *size = ext4_inode_get_size(fs->superblock, enode->inode_ref->inode); 971 981 *lnkcnt = 1; 972 982 973 983 ext4fs_node_put(root_node); 974 984 975 985 return EOK; 976 986 } … … 980 990 * Correctly release the filesystem. 981 991 * 982 * @param service_id device to be unmounted 983 * @return error code 992 * @param service_id Device to be unmounted 993 * 994 * @return Error code 995 * 984 996 */ 985 997 static int ext4fs_unmounted(service_id_t service_id) 986 998 { 987 int rc;988 989 999 ext4fs_instance_t *inst; 990 rc = ext4fs_instance_get(service_id, &inst); 991 if (rc != EOK) { 992 return rc; 993 } 994 1000 int rc = ext4fs_instance_get(service_id, &inst); 1001 if (rc != EOK) 1002 return rc; 1003 995 1004 fibril_mutex_lock(&open_nodes_lock); 996 1005 997 1006 if (inst->open_nodes_count != 0) { 998 1007 fibril_mutex_unlock(&open_nodes_lock); 999 1008 return EBUSY; 1000 1009 } 1001 1010 1002 1011 /* Remove the instance from the list */ 1003 1012 fibril_mutex_lock(&instance_list_mutex); 1004 1013 list_remove(&inst->link); 1005 1014 fibril_mutex_unlock(&instance_list_mutex); 1006 1015 1007 1016 fibril_mutex_unlock(&open_nodes_lock); 1008 1017 1009 1018 return ext4_filesystem_fini(inst->filesystem); 1010 1019 } 1011 1020 1012 1013 1021 /** Read bytes from node. 1014 1022 * 1015 * @param service_id device to read data from1016 * @param index number of node to read from1017 * @param pos position where the read should be started1018 * @param rbytes output value, where the real size was returned1019 * @return error code1020 * /1021 static int ext4fs_read(service_id_t service_id, fs_index_t index, 1022 aoff64_t pos, size_t *rbytes) 1023 { 1024 int rc; 1025 1023 * @param service_id Device to read data from 1024 * @param index Number of node to read from 1025 * @param pos Position where the read should be started 1026 * @param rbytes Output value, where the real size was returned 1027 * 1028 * @return Error code 1029 * 1030 */ 1031 static int ext4fs_read(service_id_t service_id, fs_index_t index, aoff64_t pos, 1032 size_t *rbytes) 1033 { 1026 1034 /* 1027 1035 * Receive the read request. … … 1033 1041 return EINVAL; 1034 1042 } 1035 1043 1036 1044 ext4fs_instance_t *inst; 1037 rc = ext4fs_instance_get(service_id, &inst);1045 int rc = ext4fs_instance_get(service_id, &inst); 1038 1046 if (rc != EOK) { 1039 1047 async_answer_0(callid, rc); 1040 1048 return rc; 1041 1049 } 1042 1050 1043 1051 /* Load i-node */ 1044 1052 ext4_inode_ref_t *inode_ref; … … 1048 1056 return rc; 1049 1057 } 1050 1058 1051 1059 /* Read from i-node by type */ 1052 1060 if (ext4_inode_is_type(inst->filesystem->superblock, inode_ref->inode, 1053 EXT4_INODE_MODE_FILE)) {1061 EXT4_INODE_MODE_FILE)) { 1054 1062 rc = ext4fs_read_file(callid, pos, size, inst, inode_ref, 1055 rbytes);1063 rbytes); 1056 1064 } else if (ext4_inode_is_type(inst->filesystem->superblock, 1057 inode_ref->inode, EXT4_INODE_MODE_DIRECTORY)) {1065 inode_ref->inode, EXT4_INODE_MODE_DIRECTORY)) { 1058 1066 rc = ext4fs_read_directory(callid, pos, size, inst, inode_ref, 1059 rbytes);1067 rbytes); 1060 1068 } else { 1061 1069 /* Other inode types not supported */ … … 1063 1071 rc = ENOTSUP; 1064 1072 } 1065 1073 1066 1074 ext4_filesystem_put_inode_ref(inode_ref); 1067 1075 1068 1076 return rc; 1069 1077 } … … 1071 1079 /** Check if filename is dot or dotdot (reserved names). 1072 1080 * 1073 * @param name name to check 1074 * @param name_size length of string name 1075 * @return result of the check 1081 * @param name Name to check 1082 * @param name_size Length of string name 1083 * 1084 * @return Result of the check 1085 * 1076 1086 */ 1077 1087 bool ext4fs_is_dots(const uint8_t *name, size_t name_size) 1078 1088 { 1079 if ( name_size == 1 && name[0] == '.') {1089 if ((name_size == 1) && (name[0] == '.')) 1080 1090 return true; 1081 } 1082 1083 if (name_size == 2 && name[0] == '.' && name[1] == '.') { 1091 1092 if ((name_size == 2) && (name[0] == '.') && (name[1] == '.')) 1084 1093 return true; 1085 } 1086 1094 1087 1095 return false; 1088 1096 } … … 1090 1098 /** Read data from directory. 1091 1099 * 1092 * @param callid IPC id of call (for communication) 1093 * @param pos position to start reading from 1094 * @param size how many bytes to read 1095 * @param inst filesystem instance 1096 * @param inode_ref node to read data from 1097 * @param rbytes output value to return real number of bytes was read 1098 * @return error code 1100 * @param callid IPC id of call (for communication) 1101 * @param pos Position to start reading from 1102 * @param size How many bytes to read 1103 * @param inst Filesystem instance 1104 * @param inode_ref Node to read data from 1105 * @param rbytes Output value to return real number of bytes was read 1106 * 1107 * @return Error code 1108 * 1099 1109 */ 1100 1110 int ext4fs_read_directory(ipc_callid_t callid, aoff64_t pos, size_t size, 1101 1111 ext4fs_instance_t *inst, ext4_inode_ref_t *inode_ref, size_t *rbytes) 1102 1112 { 1103 int rc;1104 1105 1113 ext4_directory_iterator_t it; 1106 rc = ext4_directory_iterator_init(&it, inode_ref, pos);1114 int rc = ext4_directory_iterator_init(&it, inode_ref, pos); 1107 1115 if (rc != EOK) { 1108 1116 async_answer_0(callid, rc); 1109 1117 return rc; 1110 1118 } 1111 1112 /* Find next interesting directory entry. 1119 1120 /* 1121 * Find next interesting directory entry. 1113 1122 * We want to skip . and .. entries 1114 1123 * as these are not used in HelenOS … … 1116 1125 bool found = false; 1117 1126 while (it.current != NULL) { 1118 1119 if (it.current->inode == 0) { 1127 if (it.current->inode == 0) 1120 1128 goto skip; 1121 } 1122 1129 1123 1130 uint16_t name_size = ext4_directory_entry_ll_get_name_length( 1124 1131 inst->filesystem->superblock, it.current); 1125 1126 /* skip . and .. */1127 if (ext4fs_is_dots(it.current->name, name_size)) {1132 1133 /* Skip . and .. */ 1134 if (ext4fs_is_dots(it.current->name, name_size)) 1128 1135 goto skip; 1129 }1130 1131 /* The on-disk entry does not contain \0 at the end1136 1137 /* 1138 * The on-disk entry does not contain \0 at the end 1132 1139 * end of entry name, so we copy it to new buffer 1133 1140 * and add the \0 at the end 1134 1141 */ 1135 uint8_t *buf = malloc(name_size +1);1142 uint8_t *buf = malloc(name_size + 1); 1136 1143 if (buf == NULL) { 1137 1144 ext4_directory_iterator_fini(&it); … … 1139 1146 return ENOMEM; 1140 1147 } 1148 1141 1149 memcpy(buf, &it.current->name, name_size); 1142 1150 *(buf + name_size) = 0; 1143 1151 found = true; 1152 1144 1153 (void) async_data_read_finalize(callid, buf, name_size + 1); 1145 1154 free(buf); 1146 1155 break; 1147 1156 1148 1157 skip: 1149 1158 rc = ext4_directory_iterator_next(&it); … … 1154 1163 } 1155 1164 } 1156 1165 1157 1166 uint64_t next; 1158 1167 if (found) { 1159 1168 rc = ext4_directory_iterator_next(&it); 1160 if (rc != EOK) {1169 if (rc != EOK) 1161 1170 return rc; 1162 }1171 1163 1172 next = it.current_offset; 1164 1173 } 1165 1174 1166 1175 rc = ext4_directory_iterator_fini(&it); 1167 if (rc != EOK) { 1168 return rc; 1169 } 1170 1176 if (rc != EOK) 1177 return rc; 1178 1171 1179 /* Prepare return values */ 1172 1180 if (found) { … … 1179 1187 } 1180 1188 1181 1182 1189 /** Read data from file. 1183 1190 * 1184 * @param callid IPC id of call (for communication) 1185 * @param pos position to start reading from 1186 * @param size how many bytes to read 1187 * @param inst filesystem instance 1188 * @param inode_ref node to read data from 1189 * @param rbytes output value to return real number of bytes was read 1190 * @return error code 1191 * @param callid IPC id of call (for communication) 1192 * @param pos Position to start reading from 1193 * @param size How many bytes to read 1194 * @param inst Filesystem instance 1195 * @param inode_ref Node to read data from 1196 * @param rbytes Output value to return real number of bytes was read 1197 * 1198 * @return Error code 1199 * 1191 1200 */ 1192 1201 int ext4fs_read_file(ipc_callid_t callid, aoff64_t pos, size_t size, 1193 1202 ext4fs_instance_t *inst, ext4_inode_ref_t *inode_ref, size_t *rbytes) 1194 1203 { 1195 int rc;1196 1197 1204 ext4_superblock_t *sb = inst->filesystem->superblock; 1198 1205 uint64_t file_size = ext4_inode_get_size(sb, inode_ref->inode); 1199 1206 1200 1207 if (pos >= file_size) { 1201 1208 /* Read 0 bytes successfully */ … … 1204 1211 return EOK; 1205 1212 } 1206 1213 1207 1214 /* For now, we only read data from one block at a time */ 1208 1215 uint32_t block_size = ext4_superblock_get_block_size(sb); … … 1210 1217 uint32_t offset_in_block = pos % block_size; 1211 1218 uint32_t bytes = min(block_size - offset_in_block, size); 1212 1219 1213 1220 /* Handle end of file */ 1214 if (pos + bytes > file_size) {1221 if (pos + bytes > file_size) 1215 1222 bytes = file_size - pos; 1216 } 1217 1223 1218 1224 /* Get the real block number */ 1219 1225 uint32_t fs_block; 1220 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, file_block, &fs_block); 1226 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 1227 file_block, &fs_block); 1221 1228 if (rc != EOK) { 1222 1229 async_answer_0(callid, rc); 1223 1230 return rc; 1224 1231 } 1225 1226 /* Check for sparse file 1232 1233 /* 1234 * Check for sparse file. 1227 1235 * If ext4_filesystem_get_inode_data_block_index returned 1228 1236 * fs_block == 0, it means that the given block is not allocated for the … … 1236 1244 return ENOMEM; 1237 1245 } 1238 1246 1239 1247 memset(buffer, 0, bytes); 1240 1248 1241 1249 async_data_read_finalize(callid, buffer, bytes); 1242 1250 *rbytes = bytes; 1243 1251 1244 1252 free(buffer); 1245 1246 1253 return EOK; 1247 1254 } 1248 1255 1249 1256 /* Usual case - we need to read a block from device */ 1250 1257 block_t *block; … … 1254 1261 return rc; 1255 1262 } 1256 1263 1257 1264 assert(offset_in_block + bytes <= block_size); 1258 1265 async_data_read_finalize(callid, block->data + offset_in_block, bytes); 1259 1266 1260 1267 rc = block_put(block); 1261 if (rc != EOK) { 1262 return rc; 1263 } 1264 1268 if (rc != EOK) 1269 return rc; 1270 1265 1271 *rbytes = bytes; 1266 1272 return EOK; 1267 1273 } 1268 1274 1269 1270 1275 /** Write bytes to file 1271 1276 * 1272 * @param service_id device identifier1273 * @param index i-node number of file1274 * @param pos position in file to start reading from1275 * @param wbytes output value - real number of written bytes1276 * @param nsize output value - new size of i-node1277 * @return error code1278 * /1279 static int ext4fs_write(service_id_t service_id, fs_index_t index, 1280 aoff64_t pos, size_t *wbytes, aoff64_t *nsize) 1281 { 1282 int rc; 1283 1277 * @param service_id Device identifier 1278 * @param index I-node number of file 1279 * @param pos Position in file to start reading from 1280 * @param wbytes Output value - real number of written bytes 1281 * @param nsize Output value - new size of i-node 1282 * 1283 * @return Error code 1284 * 1285 */ 1286 static int ext4fs_write(service_id_t service_id, fs_index_t index, aoff64_t pos, 1287 size_t *wbytes, aoff64_t *nsize) 1288 { 1284 1289 fs_node_t *fn; 1285 rc = ext4fs_node_get(&fn, service_id, index); 1286 if (rc != EOK) { 1287 return rc; 1288 } 1289 1290 int rc = ext4fs_node_get(&fn, service_id, index); 1291 if (rc != EOK) 1292 return rc; 1293 1290 1294 ipc_callid_t callid; 1291 1295 size_t len; 1292 1296 if (!async_data_write_receive(&callid, &len)) { 1293 rc = EINVAL; 1297 ext4fs_node_put(fn); 1298 async_answer_0(callid, EINVAL); 1299 return EINVAL; 1300 } 1301 1302 ext4fs_node_t *enode = EXT4FS_NODE(fn); 1303 ext4_filesystem_t *fs = enode->instance->filesystem; 1304 1305 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 1306 1307 /* Prevent writing to more than one block */ 1308 uint32_t bytes = min(len, block_size - (pos % block_size)); 1309 1310 int flags = BLOCK_FLAGS_NONE; 1311 if (bytes == block_size) 1312 flags = BLOCK_FLAGS_NOREAD; 1313 1314 uint32_t iblock = pos / block_size; 1315 uint32_t fblock; 1316 1317 /* Load inode */ 1318 ext4_inode_ref_t *inode_ref = enode->inode_ref; 1319 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, iblock, 1320 &fblock); 1321 if (rc != EOK) { 1294 1322 ext4fs_node_put(fn); 1295 1323 async_answer_0(callid, rc); 1296 1324 return rc; 1297 1325 } 1298 1299 1300 ext4fs_node_t *enode = EXT4FS_NODE(fn); 1301 ext4_filesystem_t *fs = enode->instance->filesystem; 1302 1303 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 1304 1305 /* Prevent writing to more than one block */ 1306 uint32_t bytes = min(len, block_size - (pos % block_size)); 1307 1308 int flags = BLOCK_FLAGS_NONE; 1309 if (bytes == block_size) { 1310 flags = BLOCK_FLAGS_NOREAD; 1311 } 1312 1313 uint32_t iblock = pos / block_size; 1314 uint32_t fblock; 1315 1316 /* Load inode */ 1317 ext4_inode_ref_t *inode_ref = enode->inode_ref; 1318 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, iblock, &fblock); 1319 if (rc != EOK) { 1320 ext4fs_node_put(fn); 1321 async_answer_0(callid, rc); 1322 return rc; 1323 } 1324 1326 1325 1327 /* Check for sparse file */ 1326 1328 if (fblock == 0) { 1327 1328 if (ext4_superblock_has_feature_incompatible( 1329 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 1330 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 1331 1332 uint32_t last_iblock = ext4_inode_get_size(fs->superblock, inode_ref->inode) / block_size; 1329 if ((ext4_superblock_has_feature_incompatible(fs->superblock, 1330 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 1331 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 1332 uint32_t last_iblock = 1333 ext4_inode_get_size(fs->superblock, inode_ref->inode) / 1334 block_size; 1335 1333 1336 while (last_iblock < iblock) { 1334 rc = ext4_extent_append_block(inode_ref, &last_iblock, &fblock, true); 1337 rc = ext4_extent_append_block(inode_ref, &last_iblock, 1338 &fblock, true); 1335 1339 if (rc != EOK) { 1336 1340 ext4fs_node_put(fn); … … 1339 1343 } 1340 1344 } 1341 1342 rc = ext4_extent_append_block(inode_ref, &last_iblock, &fblock, false); 1345 1346 rc = ext4_extent_append_block(inode_ref, &last_iblock, 1347 &fblock, false); 1343 1348 if (rc != EOK) { 1344 1349 ext4fs_node_put(fn); … … 1346 1351 return rc; 1347 1352 } 1348 1349 1353 } else { 1350 rc = ext4_balloc_alloc_block(inode_ref, &fblock);1354 rc = ext4_balloc_alloc_block(inode_ref, &fblock); 1351 1355 if (rc != EOK) { 1352 1356 ext4fs_node_put(fn); … … 1354 1358 return rc; 1355 1359 } 1356 1357 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, iblock, fblock); 1360 1361 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, 1362 iblock, fblock); 1358 1363 if (rc != EOK) { 1359 1364 ext4_balloc_free_block(inode_ref, fblock); … … 1363 1368 } 1364 1369 } 1365 1370 1366 1371 flags = BLOCK_FLAGS_NOREAD; 1367 1372 inode_ref->dirty = true; 1368 1373 } 1369 1374 1370 1375 /* Load target block */ 1371 1376 block_t *write_block; … … 1376 1381 return rc; 1377 1382 } 1378 1379 if (flags == BLOCK_FLAGS_NOREAD) {1383 1384 if (flags == BLOCK_FLAGS_NOREAD) 1380 1385 memset(write_block->data, 0, block_size); 1381 }1382 1383 rc = async_data_write_finalize(callid, write_block->data +(pos % block_size), bytes);1386 1387 rc = async_data_write_finalize(callid, write_block->data + 1388 (pos % block_size), bytes); 1384 1389 if (rc != EOK) { 1385 1390 ext4fs_node_put(fn); 1386 1391 return rc; 1387 1392 } 1388 1393 1389 1394 write_block->dirty = true; 1390 1395 1391 1396 rc = block_put(write_block); 1392 1397 if (rc != EOK) { … … 1394 1399 return rc; 1395 1400 } 1396 1401 1397 1402 /* Do some counting */ 1398 uint32_t old_inode_size = ext4_inode_get_size(fs->superblock, inode_ref->inode); 1403 uint32_t old_inode_size = ext4_inode_get_size(fs->superblock, 1404 inode_ref->inode); 1399 1405 if (pos + bytes > old_inode_size) { 1400 1406 ext4_inode_set_size(inode_ref->inode, pos + bytes); 1401 1407 inode_ref->dirty = true; 1402 1408 } 1403 1409 1404 1410 *nsize = ext4_inode_get_size(fs->superblock, inode_ref->inode); 1405 1411 *wbytes = bytes; 1406 1412 1407 1413 return ext4fs_node_put(fn); 1408 1414 } 1409 1415 1410 1411 1416 /** Truncate file. 1412 1417 * 1413 1418 * Only the direction to shorter file is supported. 1414 1419 * 1415 * @param service_id device identifier 1416 * @param index index if node to truncated 1417 * @param new_size new size of file 1418 * @return error code 1420 * @param service_id Device identifier 1421 * @param index Index if node to truncated 1422 * @param new_size New size of file 1423 * 1424 * @return Error code 1425 * 1419 1426 */ 1420 1427 static int ext4fs_truncate(service_id_t service_id, fs_index_t index, 1421 aoff64_t new_size) 1422 { 1423 int rc; 1424 1428 aoff64_t new_size) 1429 { 1425 1430 fs_node_t *fn; 1426 rc = ext4fs_node_get(&fn, service_id, index); 1427 if (rc != EOK) { 1428 return rc; 1429 } 1430 1431 int rc = ext4fs_node_get(&fn, service_id, index); 1432 if (rc != EOK) 1433 return rc; 1434 1431 1435 ext4fs_node_t *enode = EXT4FS_NODE(fn); 1432 1436 ext4_inode_ref_t *inode_ref = enode->inode_ref; 1433 1437 1434 1438 rc = ext4_filesystem_truncate_inode(inode_ref, new_size); 1435 1439 ext4fs_node_put(fn); 1436 1440 1437 1441 return rc; 1438 1442 } 1439 1443 1440 1441 1444 /** Close file. 1442 1445 * 1443 * @param service_id device identifier 1444 * @param index i-node number 1445 * @return error code 1446 * @param service_id Device identifier 1447 * @param index I-node number 1448 * 1449 * @return Error code 1450 * 1446 1451 */ 1447 1452 static int ext4fs_close(service_id_t service_id, fs_index_t index) … … 1450 1455 } 1451 1456 1452 1453 1457 /** Destroy node specified by index. 1454 1458 * 1455 * @param service_id device identifier 1456 * @param index number of i-node to destroy 1457 * @return error code 1459 * @param service_id Device identifier 1460 * @param index I-node to destroy 1461 * 1462 * @return Error code 1463 * 1458 1464 */ 1459 1465 static int ext4fs_destroy(service_id_t service_id, fs_index_t index) 1460 1466 { 1461 int rc;1462 1463 1467 fs_node_t *fn; 1464 rc = ext4fs_node_get(&fn, service_id, index); 1465 if (rc != EOK) { 1466 return rc; 1467 } 1468 1468 int rc = ext4fs_node_get(&fn, service_id, index); 1469 if (rc != EOK) 1470 return rc; 1471 1469 1472 /* Destroy the inode */ 1470 1473 return ext4fs_destroy_node(fn); 1471 1474 } 1472 1475 1473 /** Enforce inode synchronization (write) to device. 1474 * 1475 * @param service_id device identifier 1476 * @param index i-node number. 1476 /** Enforce inode synchronization (write) to device. 1477 * 1478 * @param service_id Device identifier 1479 * @param index I-node number. 1480 * 1477 1481 */ 1478 1482 static int ext4fs_sync(service_id_t service_id, fs_index_t index) 1479 1483 { 1480 int rc;1481 1482 1484 fs_node_t *fn; 1483 rc = ext4fs_node_get(&fn, service_id, index); 1484 if (rc != EOK) { 1485 return rc; 1486 } 1487 1485 int rc = ext4fs_node_get(&fn, service_id, index); 1486 if (rc != EOK) 1487 return rc; 1488 1488 1489 ext4fs_node_t *enode = EXT4FS_NODE(fn); 1489 1490 enode->inode_ref->dirty = true; 1490 1491 1491 1492 return ext4fs_node_put(fn); 1492 1493 } … … 1503 1504 .close = ext4fs_close, 1504 1505 .destroy = ext4fs_destroy, 1505 .sync = ext4fs_sync ,1506 .sync = ext4fs_sync 1506 1507 }; 1507 1508
Note:
See TracChangeset
for help on using the changeset viewer.
