Changeset 38542dc in mainline for uspace/lib/ext4/libext4_directory.c
- 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
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
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 }
Note:
See TracChangeset
for help on using the changeset viewer.