Changeset 38542dc in mainline
- Timestamp:
- 2012-08-12T18:36:10Z (12 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
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 35 * @brief 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 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 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 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 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 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 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 154 ext4_balloc_get_bgid_of_block(sb, first); 157 155 uint32_t block_group_last = 158 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 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 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 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 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 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 382 383 uint32_t first_in_group_index = ext4_filesystem_blockaddr2_index_in_group(384 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 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 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 503 index_in_group = ext4_filesystem_blockaddr2_index_in_group(sb,504 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 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 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 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 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 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 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 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 35 * @brief 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 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 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 35 * @brief 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 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 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 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 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 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 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 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 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 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 41 ext4_superblock_t *); 42 42 extern void ext4_block_group_set_block_bitmap(ext4_block_group_t *, 43 43 ext4_superblock_t *, uint64_t); 44 44 extern uint64_t ext4_block_group_get_inode_bitmap(ext4_block_group_t *, 45 45 ext4_superblock_t *); 46 46 extern void ext4_block_group_set_inode_bitmap(ext4_block_group_t *, 47 47 ext4_superblock_t *, uint64_t); 48 48 extern uint64_t ext4_block_group_get_inode_table_first_block( 49 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 53 ext4_superblock_t *); 54 54 extern void ext4_block_group_set_free_blocks_count(ext4_block_group_t *, 55 55 ext4_superblock_t *, uint32_t); 56 56 extern uint32_t ext4_block_group_get_free_inodes_count(ext4_block_group_t *, 57 57 ext4_superblock_t *); 58 58 extern void ext4_block_group_set_free_inodes_count(ext4_block_group_t *, 59 59 ext4_superblock_t *, uint32_t); 60 60 extern void ext4_block_group_set_free_inodes_count(ext4_block_group_t *, 61 61 ext4_superblock_t *, uint32_t); 62 62 extern uint32_t ext4_block_group_get_used_dirs_count(ext4_block_group_t *, 63 63 ext4_superblock_t *); 64 64 extern void ext4_block_group_set_used_dirs_count(ext4_block_group_t *, 65 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 69 ext4_superblock_t *); 70 70 extern void ext4_block_group_set_itable_unused(ext4_block_group_t *, 71 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 35 * @brief 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 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 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, 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 103 }104 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 35 * @brief 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 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 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 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 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 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 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 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 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 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 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 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 41 extern uint16_t 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 48 ext4_directory_entry_ll_t *, uint16_t); 49 49 extern uint8_t ext4_directory_entry_ll_get_inode_type(ext4_superblock_t *, 50 50 ext4_directory_entry_ll_t *); 51 51 extern void ext4_directory_entry_ll_set_inode_type(ext4_superblock_t *, 52 52 ext4_directory_entry_ll_t *, uint8_t); 53 53 54 54 extern int ext4_directory_iterator_init(ext4_directory_iterator_t *, 55 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 61 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 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 35 * @brief 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 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 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 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 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 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 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 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 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 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 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 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 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 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 416 417 418 419 420 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 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 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 701 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 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 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 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 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 914 ext4_directory_dx_countlimit_get_limit(root_countlimit); 892 915 uint16_t root_count = 893 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 * 931 block_t *new_block; 911 932 rc = block_get(&new_block, inode_ref->fs->device, 912 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 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 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 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 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 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 1070 } 1071 1072 /* Check if there is needed to split index node1073 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 39 ext4_directory_dx_root_info_t *); 40 40 extern void ext4_directory_dx_root_info_set_hash_version( 41 41 ext4_directory_dx_root_info_t *, uint8_t); 42 42 extern uint8_t ext4_directory_dx_root_info_get_info_length( 43 43 ext4_directory_dx_root_info_t *); 44 44 extern void ext4_directory_dx_root_info_set_info_length( 45 45 ext4_directory_dx_root_info_t *, uint8_t); 46 46 extern uint8_t ext4_directory_dx_root_info_get_indirect_levels( 47 47 ext4_directory_dx_root_info_t *); 48 48 extern void ext4_directory_dx_root_info_set_indirect_levels( 49 49 ext4_directory_dx_root_info_t *, uint8_t); 50 50 51 51 extern uint16_t ext4_directory_dx_countlimit_get_limit( 52 52 ext4_directory_dx_countlimit_t *); 53 53 extern void ext4_directory_dx_countlimit_set_limit( 54 54 ext4_directory_dx_countlimit_t *, uint16_t); 55 55 extern uint16_t ext4_directory_dx_countlimit_get_count( 56 56 ext4_directory_dx_countlimit_t *); 57 57 extern void ext4_directory_dx_countlimit_set_count( 58 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 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 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 35 * @brief 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 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 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 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 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 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 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 339 340 uint32_t block_size = ext4_superblock_get_block_size(341 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 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