Changeset 38542dc in mainline for uspace/srv/fs/ext4fs/ext4fs_ops.c
- Timestamp:
- 2012-08-12T18:36:10Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 49505fe
- Parents:
- b08e7970
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/fs/ext4fs/ext4fs_ops.c
rb08e7970 r38542dc 29 29 /** @addtogroup fs 30 30 * @{ 31 */ 32 31 */ 33 32 /** 34 * @file 35 * @brief VFS operations for EXT4 filesystem.33 * @file ext4fs_ops.c 34 * @brief VFS operations for ext4 filesystem. 36 35 */ 37 36 … … 42 41 #include <macros.h> 43 42 #include <malloc.h> 44 #include <string.h>45 43 #include <adt/hash_table.h> 46 44 #include <ipc/loc.h> … … 48 46 #include "../../vfs/vfs.h" 49 47 50 #define EXT4FS_NODE(node) ((node) ? (ext4fs_node_t *) (node)->data : NULL) 51 52 #define OPEN_NODES_KEYS 2 53 #define OPEN_NODES_DEV_HANDLE_KEY 0 54 #define OPEN_NODES_INODE_KEY 1 55 #define OPEN_NODES_BUCKETS 256 48 #define EXT4FS_NODE(node) \ 49 ((node) ? (ext4fs_node_t *) (node)->data : NULL) 50 51 #define OPEN_NODES_KEYS 2 52 53 #define OPEN_NODES_DEV_HANDLE_KEY 0 54 #define OPEN_NODES_INODE_KEY 1 55 56 #define OPEN_NODES_BUCKETS 256 56 57 57 58 /** … … 87 88 static int ext4fs_node_put_core(ext4fs_node_t *); 88 89 89 /* Forward declarations of EXT4 libfs operations. */90 /* Forward declarations of ext4 libfs operations. */ 90 91 91 92 static int ext4fs_root_get(fs_node_t **, service_id_t); … … 122 123 /** Compare given item with values in hash table. 123 124 * 124 * @return bool result of compare operation125 125 */ 126 126 static int open_nodes_compare(unsigned long key[], hash_count_t keys, 127 127 link_t *item) 128 128 { 129 ext4fs_node_t *enode = hash_table_get_instance(item, ext4fs_node_t, link);130 129 assert(keys > 0); 130 131 ext4fs_node_t *enode = 132 hash_table_get_instance(item, ext4fs_node_t, link); 133 131 134 if (enode->instance->service_id != 132 ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {135 ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) 133 136 return false; 134 }135 if (keys == 1) {137 138 if (keys == 1) 136 139 return true; 137 }140 138 141 assert(keys == 2); 142 139 143 return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]); 140 144 } … … 154 158 }; 155 159 156 157 160 /** Basic initialization of the driver. 158 161 * 159 * There is only needed to create hash table for storing open nodes. 160 * 161 * @return error code 162 * This is only needed to create the hash table 163 * for storing open nodes. 164 * 165 * @return Error code 166 * 162 167 */ 163 168 int ext4fs_global_init(void) 164 169 { 165 170 if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS, 166 OPEN_NODES_KEYS, &open_nodes_ops)) {171 OPEN_NODES_KEYS, &open_nodes_ops)) 167 172 return ENOMEM; 168 }173 169 174 return EOK; 170 175 } … … 172 177 /* Finalization of the driver. 173 178 * 174 * Th ere is only needed to destroyhash table.175 * 176 * @return error code179 * This is only needed to destroy the hash table. 180 * 181 * @return Error code 177 182 */ 178 183 int ext4fs_global_fini(void) … … 182 187 } 183 188 184 185 189 /* 186 * E XT4 libfs operations.190 * Ext4 libfs operations. 187 191 */ 188 192 189 193 /** Get instance from internal table by service_id. 190 194 * 191 * @param service_id device identifier 192 * @param inst output instance if successful operation 193 * @return error code 195 * @param service_id Device identifier 196 * @param inst Output instance if successful operation 197 * 198 * @return Error code 199 * 194 200 */ 195 201 int ext4fs_instance_get(service_id_t service_id, ext4fs_instance_t **inst) 196 202 { 197 203 fibril_mutex_lock(&instance_list_mutex); 198 204 199 205 if (list_empty(&instance_list)) { 200 206 fibril_mutex_unlock(&instance_list_mutex); 201 207 return EINVAL; 202 208 } 203 204 ext4fs_instance_t *tmp; 209 205 210 list_foreach(instance_list, link) { 206 tmp = list_get_instance(link, ext4fs_instance_t, link); 207 211 ext4fs_instance_t *tmp = 212 list_get_instance(link, ext4fs_instance_t, link); 213 208 214 if (tmp->service_id == service_id) { 209 215 *inst = tmp; … … 212 218 } 213 219 } 214 220 215 221 fibril_mutex_unlock(&instance_list_mutex); 216 222 return EINVAL; 217 223 } 218 224 219 220 225 /** Get root node of filesystem specified by service_id. 221 226 * 222 * @param rfn output pointer to loaded node 223 * @param service_id device to load root node from 224 * @return error code 227 * @param rfn Output pointer to loaded node 228 * @param service_id Device to load root node from 229 * 230 * @return Error code 231 * 225 232 */ 226 233 int ext4fs_root_get(fs_node_t **rfn, service_id_t service_id) … … 233 240 * If match is found, load and return matching node. 234 241 * 235 * @param rfn output pointer to node if operation successful 236 * @param pfn parent directory node 237 * @param component name to check directory for 238 * @return error code 242 * @param rfn Output pointer to node if operation successful 243 * @param pfn Parent directory node 244 * @param component Name to check directory for 245 * 246 * @return Error code 247 * 239 248 */ 240 249 int ext4fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component) 241 250 { 242 int rc;243 244 251 ext4fs_node_t *eparent = EXT4FS_NODE(pfn); 245 252 ext4_filesystem_t *fs = eparent->instance->filesystem; 246 253 247 254 if (!ext4_inode_is_type(fs->superblock, eparent->inode_ref->inode, 248 EXT4_INODE_MODE_DIRECTORY)) {255 EXT4_INODE_MODE_DIRECTORY)) 249 256 return ENOTDIR; 250 } 251 257 252 258 /* Try to find entry */ 253 259 ext4_directory_search_result_t result; 254 rc = ext4_directory_find_entry(&result, eparent->inode_ref, component); 260 int rc = ext4_directory_find_entry(&result, eparent->inode_ref, 261 component); 255 262 if (rc != EOK) { 256 263 if (rc == ENOENT) { … … 258 265 return EOK; 259 266 } 260 return rc; 261 } 262 267 268 return rc; 269 } 270 263 271 /* Load node from search result */ 264 272 uint32_t inode = ext4_directory_entry_ll_get_inode(result.dentry); 265 273 rc = ext4fs_node_get_core(rfn, eparent->instance, inode); 266 if (rc != EOK) { 267 return rc; 268 } 269 274 if (rc != EOK) 275 return rc; 276 270 277 /* Destroy search result structure */ 271 rc = ext4_directory_destroy_result(&result); 272 if (rc != EOK) { 273 return rc; 274 } 275 276 return EOK; 278 return ext4_directory_destroy_result(&result); 277 279 } 278 280 … … 281 283 * It's wrapper for node_put_core operation 282 284 * 283 * @param rfn output pointer to loaded node if operation successful 284 * @param service_id device identifier 285 * @param index node index (here i-node number) 286 * @return error code 285 * @param rfn Output pointer to loaded node if operation successful 286 * @param service_id Device identifier 287 * @param index Node index (here i-node number) 288 * 289 * @return Error code 290 * 287 291 */ 288 292 int ext4fs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index) 289 293 { 290 int rc;291 292 294 ext4fs_instance_t *inst; 293 rc = ext4fs_instance_get(service_id, &inst); 294 if (rc != EOK) { 295 return rc; 296 } 297 295 int rc = ext4fs_instance_get(service_id, &inst); 296 if (rc != EOK) 297 return rc; 298 298 299 return ext4fs_node_get_core(rfn, inst, index); 299 300 } … … 301 302 /** Main function for getting node from the filesystem. 302 303 * 303 * @param rfn output point to loaded node if operation successful 304 * @param inst instance of filesystem 305 * @param index index of node (i-node number) 306 * @return error code 304 * @param rfn Output point to loaded node if operation successful 305 * @param inst Instance of filesystem 306 * @param index Index of node (i-node number) 307 * 308 * @return Error code 309 * 307 310 */ 308 311 int ext4fs_node_get_core(fs_node_t **rfn, ext4fs_instance_t *inst, 309 fs_index_t index) 310 { 311 int rc; 312 312 fs_index_t index) 313 { 313 314 fibril_mutex_lock(&open_nodes_lock); 314 315 315 316 /* Check if the node is not already open */ 316 317 unsigned long key[] = { 317 318 [OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id, 318 [OPEN_NODES_INODE_KEY] = index ,319 [OPEN_NODES_INODE_KEY] = index 319 320 }; 320 321 321 322 link_t *already_open = hash_table_find(&open_nodes, key); 322 323 ext4fs_node_t *enode = NULL; … … 325 326 *rfn = enode->fs_node; 326 327 enode->references++; 327 328 328 329 fibril_mutex_unlock(&open_nodes_lock); 329 330 return EOK; 330 331 } 331 332 332 333 /* Prepare new enode */ 333 334 enode = malloc(sizeof(ext4fs_node_t)); … … 336 337 return ENOMEM; 337 338 } 338 339 339 340 /* Prepare new fs_node and initialize */ 340 341 fs_node_t *fs_node = malloc(sizeof(fs_node_t)); … … 344 345 return ENOMEM; 345 346 } 347 346 348 fs_node_initialize(fs_node); 347 349 348 350 /* Load i-node from filesystem */ 349 351 ext4_inode_ref_t *inode_ref; 350 rc = ext4_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref); 352 int rc = ext4_filesystem_get_inode_ref(inst->filesystem, index, 353 &inode_ref); 351 354 if (rc != EOK) { 352 355 free(enode); … … 355 358 return rc; 356 359 } 357 360 358 361 /* Initialize enode */ 359 362 enode->inode_ref = inode_ref; … … 362 365 enode->fs_node = fs_node; 363 366 link_initialize(&enode->link); 364 367 365 368 fs_node->data = enode; 366 369 *rfn = fs_node; 367 370 368 371 hash_table_insert(&open_nodes, key, &enode->link); 369 372 inst->open_nodes_count++; 370 373 371 374 fibril_mutex_unlock(&open_nodes_lock); 372 375 373 376 return EOK; 374 377 } … … 376 379 /** Put previously loaded node. 377 380 * 378 * @param enode node to put back 379 * @return error code 381 * @param enode Node to put back 382 * 383 * @return Error code 384 * 380 385 */ 381 386 int ext4fs_node_put_core(ext4fs_node_t *enode) 382 387 { 383 int rc;384 388 unsigned long key[] = { 385 389 [OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id, 386 [OPEN_NODES_INODE_KEY] = enode->inode_ref->index ,390 [OPEN_NODES_INODE_KEY] = enode->inode_ref->index 387 391 }; 388 392 389 393 hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS); 390 394 assert(enode->instance->open_nodes_count > 0); 391 395 enode->instance->open_nodes_count--; 392 396 393 397 /* Put inode back in filesystem */ 394 rc = ext4_filesystem_put_inode_ref(enode->inode_ref); 395 if (rc != EOK) { 396 return rc; 397 } 398 398 int rc = ext4_filesystem_put_inode_ref(enode->inode_ref); 399 if (rc != EOK) 400 return rc; 401 399 402 /* Destroy data structure */ 400 403 free(enode->fs_node); 401 404 free(enode); 402 405 403 406 return EOK; 404 407 } 405 408 406 407 409 /** Open node. 408 410 * 409 411 * This operation is stateless in this driver. 410 412 * 411 * @param fn node to open 412 * @return error code (EOK) 413 * @param fn Node to open 414 * 415 * @return EOK 416 * 413 417 */ 414 418 int ext4fs_node_open(fs_node_t *fn) … … 418 422 } 419 423 420 421 424 /** Put previously loaded node. 422 425 * 423 * It's wrapper for node_put_core operation 424 * 425 * @param fn node to put back 426 * @return error code 426 * A wrapper for node_put_core operation 427 * 428 * @param fn Node to put back 429 * @return Error code 430 * 427 431 */ 428 432 int ext4fs_node_put(fs_node_t *fn) 429 433 { 430 int rc;431 432 434 fibril_mutex_lock(&open_nodes_lock); 433 435 434 436 ext4fs_node_t *enode = EXT4FS_NODE(fn); 435 437 assert(enode->references > 0); 436 438 enode->references--; 437 439 if (enode->references == 0) { 438 rc = ext4fs_node_put_core(enode);440 int rc = ext4fs_node_put_core(enode); 439 441 if (rc != EOK) { 440 442 fibril_mutex_unlock(&open_nodes_lock); … … 442 444 } 443 445 } 444 446 445 447 fibril_mutex_unlock(&open_nodes_lock); 446 448 447 449 return EOK; 448 450 } 449 451 450 451 452 /** Create new node in filesystem. 452 453 * 453 * @param rfn output pointer to newly created node if successful 454 * @param service_id device identifier, where the filesystem is 455 * @param flags flags for specification of new node parameters 456 * @return error code 454 * @param rfn Output pointer to newly created node if successful 455 * @param service_id Device identifier, where the filesystem is 456 * @param flags Flags for specification of new node parameters 457 * 458 * @return Error code 459 * 457 460 */ 458 461 int ext4fs_create_node(fs_node_t **rfn, service_id_t service_id, int flags) 459 462 { 460 int rc;461 462 463 /* Allocate enode */ 463 464 ext4fs_node_t *enode; 464 465 enode = malloc(sizeof(ext4fs_node_t)); 465 if (enode == NULL) {466 if (enode == NULL) 466 467 return ENOMEM; 467 } 468 468 469 469 /* Allocate fs_node */ 470 470 fs_node_t *fs_node; … … 474 474 return ENOMEM; 475 475 } 476 476 477 477 /* Load instance */ 478 478 ext4fs_instance_t *inst; 479 rc = ext4fs_instance_get(service_id, &inst);479 int rc = ext4fs_instance_get(service_id, &inst); 480 480 if (rc != EOK) { 481 481 free(enode); … … 483 483 return rc; 484 484 } 485 485 486 486 /* Allocate new i-node in filesystem */ 487 487 ext4_inode_ref_t *inode_ref; … … 492 492 return rc; 493 493 } 494 494 495 495 /* Do some interconnections in references */ 496 496 enode->inode_ref = inode_ref; 497 497 enode->instance = inst; 498 498 enode->references = 1; 499 499 500 500 link_initialize(&enode->link); 501 501 502 502 unsigned long key[] = { 503 503 [OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id, 504 [OPEN_NODES_INODE_KEY] = inode_ref->index ,504 [OPEN_NODES_INODE_KEY] = inode_ref->index 505 505 }; 506 506 507 507 fibril_mutex_lock(&open_nodes_lock); 508 508 hash_table_insert(&open_nodes, key, &enode->link); 509 509 fibril_mutex_unlock(&open_nodes_lock); 510 510 inst->open_nodes_count++; 511 511 512 512 enode->inode_ref->dirty = true; 513 513 514 514 fs_node_initialize(fs_node); 515 515 fs_node->data = enode; 516 516 enode->fs_node = fs_node; 517 517 *rfn = fs_node; 518 518 519 519 return EOK; 520 520 } 521 521 522 523 522 /** Destroy existing node. 524 523 * 525 * @param fs node to destroy 526 * @return error code 524 * @param fs Node to destroy 525 * 526 * @return Error code 527 * 527 528 */ 528 529 int ext4fs_destroy_node(fs_node_t *fn) 529 530 { 530 int rc;531 532 531 /* If directory, check for children */ 533 532 bool has_children; 534 rc = ext4fs_has_children(&has_children, fn);533 int rc = ext4fs_has_children(&has_children, fn); 535 534 if (rc != EOK) { 536 535 ext4fs_node_put(fn); 537 536 return rc; 538 537 } 539 538 540 539 if (has_children) { 541 540 ext4fs_node_put(fn); 542 541 return EINVAL; 543 542 } 544 543 545 544 ext4fs_node_t *enode = EXT4FS_NODE(fn); 546 545 ext4_inode_ref_t *inode_ref = enode->inode_ref; 547 546 548 547 /* Release data blocks */ 549 548 rc = ext4_filesystem_truncate_inode(inode_ref, 0); … … 552 551 return rc; 553 552 } 554 555 // TODO set real deletion time when it will be supported, temporary set fake time 556 // time_t now = time(NULL); 553 554 /* 555 * TODO: Sset real deletion time when it will be supported. 556 * Temporary set fake deletion time. 557 */ 557 558 ext4_inode_set_deletion_time(inode_ref->inode, 0xdeadbeef); 558 559 inode_ref->dirty = true; 559 560 560 561 /* Free inode */ 561 562 rc = ext4_filesystem_free_inode(inode_ref); … … 564 565 return rc; 565 566 } 566 567 567 568 return ext4fs_node_put(fn); 568 569 } 569 570 570 571 571 /** Link the specfied node to directory. 572 572 * 573 * @param pfn parent node to link in 574 * @param cfn node to be linked 575 * @param name name which will be assigned to directory entry 576 * @return error code 573 * @param pfn Parent node to link in 574 * @param cfn Node to be linked 575 * @param name Name which will be assigned to directory entry 576 * 577 * @return Error code 578 * 577 579 */ 578 580 int ext4fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name) 579 581 { 580 int rc;581 582 582 /* Check maximum name length */ 583 if (str len(name) > EXT4_DIRECTORY_FILENAME_LEN) {583 if (str_size(name) > EXT4_DIRECTORY_FILENAME_LEN) 584 584 return ENAMETOOLONG; 585 }585 586 586 ext4fs_node_t *parent = EXT4FS_NODE(pfn); 587 587 ext4fs_node_t *child = EXT4FS_NODE(cfn); 588 588 ext4_filesystem_t *fs = parent->instance->filesystem; 589 589 590 590 /* Add entry to parent directory */ 591 rc = ext4_directory_add_entry(parent->inode_ref, name, child->inode_ref);592 if (rc != EOK) {593 return rc;594 }595 591 int rc = ext4_directory_add_entry(parent->inode_ref, name, 592 child->inode_ref); 593 if (rc != EOK) 594 return rc; 595 596 596 /* Fill new dir -> add '.' and '..' entries */ 597 if (ext4_inode_is_type(fs->superblock, child->inode_ref->inode, EXT4_INODE_MODE_DIRECTORY)) { 598 599 rc = ext4_directory_add_entry(child->inode_ref, ".", child->inode_ref); 597 if (ext4_inode_is_type(fs->superblock, child->inode_ref->inode, 598 EXT4_INODE_MODE_DIRECTORY)) { 599 rc = ext4_directory_add_entry(child->inode_ref, ".", 600 child->inode_ref); 600 601 if (rc != EOK) { 601 602 ext4_directory_remove_entry(parent->inode_ref, name); 602 603 return rc; 603 604 } 604 605 rc = ext4_directory_add_entry(child->inode_ref, "..", parent->inode_ref); 605 606 rc = ext4_directory_add_entry(child->inode_ref, "..", 607 parent->inode_ref); 606 608 if (rc != EOK) { 607 609 ext4_directory_remove_entry(parent->inode_ref, name); … … 609 611 return rc; 610 612 } 611 613 612 614 /* Initialize directory index if supported */ 613 if (ext4_superblock_has_feature_compatible( 614 fs->superblock, EXT4_FEATURE_COMPAT_DIR_INDEX)) { 615 615 if (ext4_superblock_has_feature_compatible(fs->superblock, 616 EXT4_FEATURE_COMPAT_DIR_INDEX)) { 616 617 rc = ext4_directory_dx_init(child->inode_ref); 617 if (rc != EOK) {618 if (rc != EOK) 618 619 return rc; 619 }620 621 ext4_inode_set_flag(child->inode_ref->inode,EXT4_INODE_FLAG_INDEX);620 621 ext4_inode_set_flag(child->inode_ref->inode, 622 EXT4_INODE_FLAG_INDEX); 622 623 child->inode_ref->dirty = true; 623 624 } 624 625 uint16_t parent_links = ext4_inode_get_links_count(parent->inode_ref->inode); 625 626 uint16_t parent_links = 627 ext4_inode_get_links_count(parent->inode_ref->inode); 626 628 parent_links++; 627 629 ext4_inode_set_links_count(parent->inode_ref->inode, parent_links); 628 630 629 631 parent->inode_ref->dirty = true; 630 631 }632 633 uint16_t child_links =ext4_inode_get_links_count(child->inode_ref->inode);632 } 633 634 uint16_t child_links = 635 ext4_inode_get_links_count(child->inode_ref->inode); 634 636 child_links++; 635 637 ext4_inode_set_links_count(child->inode_ref->inode, child_links); 636 638 637 639 child->inode_ref->dirty = true; 638 640 639 641 return EOK; 640 642 } 641 643 642 643 644 /** Unlink node from specified directory. 644 645 * 645 * @param pfn parent node to delete node from 646 * @param cfn child node to be unlinked from directory 647 * @param name name of entry that will be removed 648 * @return error code 646 * @param pfn Parent node to delete node from 647 * @param cfn Child node to be unlinked from directory 648 * @param name Name of entry that will be removed 649 * 650 * @return Error code 651 * 649 652 */ 650 653 int ext4fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *name) 651 654 { 652 int rc;653 654 655 bool has_children; 655 rc = ext4fs_has_children(&has_children, cfn); 656 if (rc != EOK) { 657 return rc; 658 } 659 656 int rc = ext4fs_has_children(&has_children, cfn); 657 if (rc != EOK) 658 return rc; 659 660 660 /* Cannot unlink non-empty node */ 661 if (has_children) {661 if (has_children) 662 662 return ENOTEMPTY; 663 } 664 663 665 664 /* Remove entry from parent directory */ 666 665 ext4_inode_ref_t *parent = EXT4FS_NODE(pfn)->inode_ref; 667 666 rc = ext4_directory_remove_entry(parent, name); 668 if (rc != EOK) { 669 return rc; 670 } 671 667 if (rc != EOK) 668 return rc; 669 672 670 /* Decrement links count */ 673 ext4_inode_ref_t * child_inode_ref = EXT4FS_NODE(cfn)->inode_ref; 674 675 uint32_t lnk_count = ext4_inode_get_links_count(child_inode_ref->inode); 671 ext4_inode_ref_t *child_inode_ref = EXT4FS_NODE(cfn)->inode_ref; 672 673 uint32_t lnk_count = 674 ext4_inode_get_links_count(child_inode_ref->inode); 676 675 lnk_count--; 677 676 678 677 /* If directory - handle links from parent */ 679 if (lnk_count <= 1 && ext4fs_is_directory(cfn)) { 680 678 if ((lnk_count <= 1) && (ext4fs_is_directory(cfn))) { 681 679 assert(lnk_count == 1); 680 682 681 lnk_count--; 683 682 684 683 ext4_inode_ref_t *parent_inode_ref = EXT4FS_NODE(pfn)->inode_ref; 685 684 686 685 uint32_t parent_lnk_count = ext4_inode_get_links_count( 687 688 686 parent_inode_ref->inode); 687 689 688 parent_lnk_count--; 690 689 ext4_inode_set_links_count(parent_inode_ref->inode, parent_lnk_count); 691 690 692 691 parent->dirty = true; 693 692 } 694 693 695 // TODO set timestamps for parent (when we have wall-clock time) 696 // time_t now = time(NULL); 697 // ext4_inode_set_change_inode_time(parent->inode, (uint32_t)now); 698 // ext4_inode_set_modification_time(parent->inode, (uint32_t)now); 699 // parent->dirty = true; 700 701 // TODO set timestamp for inode 702 // ext4_inode_set_change_inode_time(child_inode_ref->inode, (uint32_t)now); 694 /* 695 * TODO: Update timestamps of the parent 696 * (when we have wall-clock time). 697 * 698 * ext4_inode_set_change_inode_time(parent->inode, (uint32_t) now); 699 * ext4_inode_set_modification_time(parent->inode, (uint32_t) now); 700 * parent->dirty = true; 701 */ 702 703 /* 704 * TODO: Update timestamp for inode. 705 * 706 * ext4_inode_set_change_inode_time(child_inode_ref->inode, 707 * (uint32_t) now); 708 */ 709 703 710 ext4_inode_set_links_count(child_inode_ref->inode, lnk_count); 704 711 child_inode_ref->dirty = true; 705 712 706 713 return EOK; 707 714 } 708 715 709 710 716 /** Check if specified node has children. 711 * 717 * 712 718 * For files is response allways false and check is executed only for directories. 713 719 * 714 * @param has_children output value for response 715 * @param fn node to check 716 * @return error code 720 * @param has_children Output value for response 721 * @param fn Node to check 722 * 723 * @return Error code 724 * 717 725 */ 718 726 int ext4fs_has_children(bool *has_children, fs_node_t *fn) 719 727 { 720 int rc;721 722 728 ext4fs_node_t *enode = EXT4FS_NODE(fn); 723 729 ext4_filesystem_t *fs = enode->instance->filesystem; 724 730 725 731 /* Check if node is directory */ 726 732 if (!ext4_inode_is_type(fs->superblock, enode->inode_ref->inode, … … 729 735 return EOK; 730 736 } 731 737 732 738 ext4_directory_iterator_t it; 733 rc = ext4_directory_iterator_init(&it, enode->inode_ref, 0); 734 if (rc != EOK) { 735 return rc; 736 } 737 739 int rc = ext4_directory_iterator_init(&it, enode->inode_ref, 0); 740 if (rc != EOK) 741 return rc; 742 738 743 /* Find a non-empty directory entry */ 739 744 bool found = false; 740 745 while (it.current != NULL) { 741 746 if (it.current->inode != 0) { 742 uint16_t name_size = ext4_directory_entry_ll_get_name_length(fs->superblock, 743 it.current); 747 uint16_t name_size = 748 ext4_directory_entry_ll_get_name_length(fs->superblock, 749 it.current); 744 750 if (!ext4fs_is_dots(it.current->name, name_size)) { 745 751 found = true; … … 747 753 } 748 754 } 749 755 750 756 rc = ext4_directory_iterator_next(&it); 751 757 if (rc != EOK) { … … 754 760 } 755 761 } 756 762 757 763 rc = ext4_directory_iterator_fini(&it); 758 if (rc != EOK) { 759 return rc; 760 } 761 764 if (rc != EOK) 765 return rc; 766 762 767 *has_children = found; 763 768 764 769 return EOK; 765 770 } 766 771 767 768 772 /** Unpack index number from node. 769 * 770 * @param fn node to load index from 771 * @return index number of i-node 773 * 774 * @param fn Node to load index from 775 * 776 * @return Index number of i-node 777 * 772 778 */ 773 779 fs_index_t ext4fs_index_get(fs_node_t *fn) … … 777 783 } 778 784 779 780 785 /** Get real size of file / directory. 781 786 * 782 * @param fn node to get size of 783 * @return real size of node 787 * @param fn Node to get size of 788 * 789 * @return Real size of node 790 * 784 791 */ 785 792 aoff64_t ext4fs_size_get(fs_node_t *fn) … … 790 797 } 791 798 792 793 799 /** Get number of links to specified node. 794 800 * 795 * @param fn node to get links to 796 * @return number of links 801 * @param fn Node to get links to 802 * 803 * @return Number of links 804 * 797 805 */ 798 806 unsigned ext4fs_lnkcnt_get(fs_node_t *fn) … … 800 808 ext4fs_node_t *enode = EXT4FS_NODE(fn); 801 809 uint32_t lnkcnt = ext4_inode_get_links_count(enode->inode_ref->inode); 802 810 803 811 if (ext4fs_is_directory(fn)) { 804 if (lnkcnt > 1) {812 if (lnkcnt > 1) 805 813 return 1; 806 } else {814 else 807 815 return 0; 808 } 809 } 810 816 } 817 811 818 /* For regular files return real links count */ 812 819 return lnkcnt; 813 820 } 814 821 815 816 822 /** Check if node is directory. 817 823 * 818 * @param fn node to check 819 * @return result of check 824 * @param fn Node to check 825 * 826 * @return Result of check 827 * 820 828 */ 821 829 bool ext4fs_is_directory(fs_node_t *fn) … … 823 831 ext4fs_node_t *enode = EXT4FS_NODE(fn); 824 832 ext4_superblock_t *sb = enode->instance->filesystem->superblock; 825 return ext4_inode_is_type(826 sb, enode->inode_ref->inode, EXT4_INODE_MODE_DIRECTORY);827 } 828 833 834 return ext4_inode_is_type(sb, enode->inode_ref->inode, 835 EXT4_INODE_MODE_DIRECTORY); 836 } 829 837 830 838 /** Check if node is regular file. 831 839 * 832 * @param fn node to check 833 * @return result of check 840 * @param fn Node to check 841 * 842 * @return Result of check 843 * 834 844 */ 835 845 bool ext4fs_is_file(fs_node_t *fn) … … 837 847 ext4fs_node_t *enode = EXT4FS_NODE(fn); 838 848 ext4_superblock_t *sb = enode->instance->filesystem->superblock; 839 return ext4_inode_is_type( 840 sb, enode->inode_ref->inode, EXT4_INODE_MODE_FILE); 849 850 return ext4_inode_is_type(sb, enode->inode_ref->inode, 851 EXT4_INODE_MODE_FILE); 841 852 } 842 853 843 854 /** Extract device identifier from node. 844 855 * 845 * @param node node to extract id from 846 * @return id of device, where is the filesystem 856 * @param node Node to extract id from 857 * 858 * @return id of device, where is the filesystem 859 * 847 860 */ 848 861 service_id_t ext4fs_service_get(fs_node_t *fn) … … 874 887 }; 875 888 876 877 889 /* 878 890 * VFS operations. 879 891 */ 880 892 881 /** Mount operation. 893 /** Mount operation. 882 894 * 883 895 * Try to mount specified filesystem from device. 884 * 885 * @param service_id identifier of device 886 * @param opts mount options 887 * @param index output value - index of root node 888 * @param size output value - size of root node 889 * @param lnkcnt output value - link count of root node 890 * @return error code 896 * 897 * @param service_id Identifier of device 898 * @param opts Mount options 899 * @param index Output value - index of root node 900 * @param size Output value - size of root node 901 * @param lnkcnt Output value - link count of root node 902 * 903 * @return Error code 904 * 891 905 */ 892 906 static int ext4fs_mounted(service_id_t service_id, const char *opts, 893 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt) 894 { 895 int rc; 896 907 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt) 908 { 897 909 /* Allocate libext4 filesystem structure */ 898 ext4_filesystem_t *fs ;899 fs = (ext4_filesystem_t *)malloc(sizeof(ext4_filesystem_t));900 if (fs == NULL) {910 ext4_filesystem_t *fs = (ext4_filesystem_t *) 911 malloc(sizeof(ext4_filesystem_t)); 912 if (fs == NULL) 901 913 return ENOMEM; 902 } 903 914 904 915 /* Allocate instance structure */ 905 ext4fs_instance_t *inst ;906 inst = (ext4fs_instance_t *)malloc(sizeof(ext4fs_instance_t));916 ext4fs_instance_t *inst = (ext4fs_instance_t *) 917 malloc(sizeof(ext4fs_instance_t)); 907 918 if (inst == NULL) { 908 919 free(fs); 909 920 return ENOMEM; 910 921 } 911 922 912 923 enum cache_mode cmode; 913 if (str_cmp(opts, "wtcache") == 0) {924 if (str_cmp(opts, "wtcache") == 0) 914 925 cmode = CACHE_MODE_WT; 915 } else {926 else 916 927 cmode = CACHE_MODE_WB; 917 } 918 928 919 929 /* Initialize the filesystem */ 920 rc = ext4_filesystem_init(fs, service_id, cmode);930 int rc = ext4_filesystem_init(fs, service_id, cmode); 921 931 if (rc != EOK) { 922 932 free(fs); … … 924 934 return rc; 925 935 } 926 936 927 937 /* Do some sanity checking */ 928 938 rc = ext4_filesystem_check_sanity(fs); … … 933 943 return rc; 934 944 } 935 945 936 946 /* Check flags */ 937 947 bool read_only; … … 943 953 return rc; 944 954 } 945 955 946 956 /* Initialize instance */ 947 957 link_initialize(&inst->link); … … 949 959 inst->filesystem = fs; 950 960 inst->open_nodes_count = 0; 951 961 952 962 /* Read root node */ 953 963 fs_node_t *root_node; … … 959 969 return rc; 960 970 } 961 971 962 972 /* Add instance to the list */ 963 973 fibril_mutex_lock(&instance_list_mutex); 964 974 list_append(&inst->link, &instance_list); 965 975 fibril_mutex_unlock(&instance_list_mutex); 966 976 967 977 ext4fs_node_t *enode = EXT4FS_NODE(root_node); 968 978 969 979 *index = EXT4_INODE_ROOT_INDEX; 970 980 *size = ext4_inode_get_size(fs->superblock, enode->inode_ref->inode); 971 981 *lnkcnt = 1; 972 982 973 983 ext4fs_node_put(root_node); 974 984 975 985 return EOK; 976 986 } … … 980 990 * Correctly release the filesystem. 981 991 * 982 * @param service_id device to be unmounted 983 * @return error code 992 * @param service_id Device to be unmounted 993 * 994 * @return Error code 995 * 984 996 */ 985 997 static int ext4fs_unmounted(service_id_t service_id) 986 998 { 987 int rc;988 989 999 ext4fs_instance_t *inst; 990 rc = ext4fs_instance_get(service_id, &inst); 991 if (rc != EOK) { 992 return rc; 993 } 994 1000 int rc = ext4fs_instance_get(service_id, &inst); 1001 if (rc != EOK) 1002 return rc; 1003 995 1004 fibril_mutex_lock(&open_nodes_lock); 996 1005 997 1006 if (inst->open_nodes_count != 0) { 998 1007 fibril_mutex_unlock(&open_nodes_lock); 999 1008 return EBUSY; 1000 1009 } 1001 1010 1002 1011 /* Remove the instance from the list */ 1003 1012 fibril_mutex_lock(&instance_list_mutex); 1004 1013 list_remove(&inst->link); 1005 1014 fibril_mutex_unlock(&instance_list_mutex); 1006 1015 1007 1016 fibril_mutex_unlock(&open_nodes_lock); 1008 1017 1009 1018 return ext4_filesystem_fini(inst->filesystem); 1010 1019 } 1011 1020 1012 1013 1021 /** Read bytes from node. 1014 1022 * 1015 * @param service_id device to read data from1016 * @param index number of node to read from1017 * @param pos position where the read should be started1018 * @param rbytes output value, where the real size was returned1019 * @return error code1020 * /1021 static int ext4fs_read(service_id_t service_id, fs_index_t index, 1022 aoff64_t pos, size_t *rbytes) 1023 { 1024 int rc; 1025 1023 * @param service_id Device to read data from 1024 * @param index Number of node to read from 1025 * @param pos Position where the read should be started 1026 * @param rbytes Output value, where the real size was returned 1027 * 1028 * @return Error code 1029 * 1030 */ 1031 static int ext4fs_read(service_id_t service_id, fs_index_t index, aoff64_t pos, 1032 size_t *rbytes) 1033 { 1026 1034 /* 1027 1035 * Receive the read request. … … 1033 1041 return EINVAL; 1034 1042 } 1035 1043 1036 1044 ext4fs_instance_t *inst; 1037 rc = ext4fs_instance_get(service_id, &inst);1045 int rc = ext4fs_instance_get(service_id, &inst); 1038 1046 if (rc != EOK) { 1039 1047 async_answer_0(callid, rc); 1040 1048 return rc; 1041 1049 } 1042 1050 1043 1051 /* Load i-node */ 1044 1052 ext4_inode_ref_t *inode_ref; … … 1048 1056 return rc; 1049 1057 } 1050 1058 1051 1059 /* Read from i-node by type */ 1052 1060 if (ext4_inode_is_type(inst->filesystem->superblock, inode_ref->inode, 1053 1061 EXT4_INODE_MODE_FILE)) { 1054 1062 rc = ext4fs_read_file(callid, pos, size, inst, inode_ref, 1055 1063 rbytes); 1056 1064 } else if (ext4_inode_is_type(inst->filesystem->superblock, 1057 1065 inode_ref->inode, EXT4_INODE_MODE_DIRECTORY)) { 1058 1066 rc = ext4fs_read_directory(callid, pos, size, inst, inode_ref, 1059 1067 rbytes); 1060 1068 } else { 1061 1069 /* Other inode types not supported */ … … 1063 1071 rc = ENOTSUP; 1064 1072 } 1065 1073 1066 1074 ext4_filesystem_put_inode_ref(inode_ref); 1067 1075 1068 1076 return rc; 1069 1077 } … … 1071 1079 /** Check if filename is dot or dotdot (reserved names). 1072 1080 * 1073 * @param name name to check 1074 * @param name_size length of string name 1075 * @return result of the check 1081 * @param name Name to check 1082 * @param name_size Length of string name 1083 * 1084 * @return Result of the check 1085 * 1076 1086 */ 1077 1087 bool ext4fs_is_dots(const uint8_t *name, size_t name_size) 1078 1088 { 1079 if ( name_size == 1 && name[0] == '.') {1089 if ((name_size == 1) && (name[0] == '.')) 1080 1090 return true; 1081 } 1082 1083 if (name_size == 2 && name[0] == '.' && name[1] == '.') { 1091 1092 if ((name_size == 2) && (name[0] == '.') && (name[1] == '.')) 1084 1093 return true; 1085 } 1086 1094 1087 1095 return false; 1088 1096 } … … 1090 1098 /** Read data from directory. 1091 1099 * 1092 * @param callid IPC id of call (for communication) 1093 * @param pos position to start reading from 1094 * @param size how many bytes to read 1095 * @param inst filesystem instance 1096 * @param inode_ref node to read data from 1097 * @param rbytes output value to return real number of bytes was read 1098 * @return error code 1100 * @param callid IPC id of call (for communication) 1101 * @param pos Position to start reading from 1102 * @param size How many bytes to read 1103 * @param inst Filesystem instance 1104 * @param inode_ref Node to read data from 1105 * @param rbytes Output value to return real number of bytes was read 1106 * 1107 * @return Error code 1108 * 1099 1109 */ 1100 1110 int ext4fs_read_directory(ipc_callid_t callid, aoff64_t pos, size_t size, 1101 1111 ext4fs_instance_t *inst, ext4_inode_ref_t *inode_ref, size_t *rbytes) 1102 1112 { 1103 int rc;1104 1105 1113 ext4_directory_iterator_t it; 1106 rc = ext4_directory_iterator_init(&it, inode_ref, pos);1114 int rc = ext4_directory_iterator_init(&it, inode_ref, pos); 1107 1115 if (rc != EOK) { 1108 1116 async_answer_0(callid, rc); 1109 1117 return rc; 1110 1118 } 1111 1112 /* Find next interesting directory entry. 1119 1120 /* 1121 * Find next interesting directory entry. 1113 1122 * We want to skip . and .. entries 1114 1123 * as these are not used in HelenOS … … 1116 1125 bool found = false; 1117 1126 while (it.current != NULL) { 1118 1119 if (it.current->inode == 0) { 1127 if (it.current->inode == 0) 1120 1128 goto skip; 1121 } 1122 1129 1123 1130 uint16_t name_size = ext4_directory_entry_ll_get_name_length( 1124 1131 inst->filesystem->superblock, it.current); 1125 1126 /* skip . and .. */1127 if (ext4fs_is_dots(it.current->name, name_size)) {1132 1133 /* Skip . and .. */ 1134 if (ext4fs_is_dots(it.current->name, name_size)) 1128 1135 goto skip; 1129 }1130 1131 /* The on-disk entry does not contain \0 at the end1136 1137 /* 1138 * The on-disk entry does not contain \0 at the end 1132 1139 * end of entry name, so we copy it to new buffer 1133 1140 * and add the \0 at the end 1134 1141 */ 1135 uint8_t *buf = malloc(name_size +1);1142 uint8_t *buf = malloc(name_size + 1); 1136 1143 if (buf == NULL) { 1137 1144 ext4_directory_iterator_fini(&it); … … 1139 1146 return ENOMEM; 1140 1147 } 1148 1141 1149 memcpy(buf, &it.current->name, name_size); 1142 1150 *(buf + name_size) = 0; 1143 1151 found = true; 1152 1144 1153 (void) async_data_read_finalize(callid, buf, name_size + 1); 1145 1154 free(buf); 1146 1155 break; 1147 1156 1148 1157 skip: 1149 1158 rc = ext4_directory_iterator_next(&it); … … 1154 1163 } 1155 1164 } 1156 1165 1157 1166 uint64_t next; 1158 1167 if (found) { 1159 1168 rc = ext4_directory_iterator_next(&it); 1160 if (rc != EOK) {1169 if (rc != EOK) 1161 1170 return rc; 1162 }1171 1163 1172 next = it.current_offset; 1164 1173 } 1165 1174 1166 1175 rc = ext4_directory_iterator_fini(&it); 1167 if (rc != EOK) { 1168 return rc; 1169 } 1170 1176 if (rc != EOK) 1177 return rc; 1178 1171 1179 /* Prepare return values */ 1172 1180 if (found) { … … 1179 1187 } 1180 1188 1181 1182 1189 /** Read data from file. 1183 1190 * 1184 * @param callid IPC id of call (for communication) 1185 * @param pos position to start reading from 1186 * @param size how many bytes to read 1187 * @param inst filesystem instance 1188 * @param inode_ref node to read data from 1189 * @param rbytes output value to return real number of bytes was read 1190 * @return error code 1191 * @param callid IPC id of call (for communication) 1192 * @param pos Position to start reading from 1193 * @param size How many bytes to read 1194 * @param inst Filesystem instance 1195 * @param inode_ref Node to read data from 1196 * @param rbytes Output value to return real number of bytes was read 1197 * 1198 * @return Error code 1199 * 1191 1200 */ 1192 1201 int ext4fs_read_file(ipc_callid_t callid, aoff64_t pos, size_t size, 1193 1202 ext4fs_instance_t *inst, ext4_inode_ref_t *inode_ref, size_t *rbytes) 1194 1203 { 1195 int rc;1196 1197 1204 ext4_superblock_t *sb = inst->filesystem->superblock; 1198 1205 uint64_t file_size = ext4_inode_get_size(sb, inode_ref->inode); 1199 1206 1200 1207 if (pos >= file_size) { 1201 1208 /* Read 0 bytes successfully */ … … 1204 1211 return EOK; 1205 1212 } 1206 1213 1207 1214 /* For now, we only read data from one block at a time */ 1208 1215 uint32_t block_size = ext4_superblock_get_block_size(sb); … … 1210 1217 uint32_t offset_in_block = pos % block_size; 1211 1218 uint32_t bytes = min(block_size - offset_in_block, size); 1212 1219 1213 1220 /* Handle end of file */ 1214 if (pos + bytes > file_size) {1221 if (pos + bytes > file_size) 1215 1222 bytes = file_size - pos; 1216 } 1217 1223 1218 1224 /* Get the real block number */ 1219 1225 uint32_t fs_block; 1220 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, file_block, &fs_block); 1226 int rc = ext4_filesystem_get_inode_data_block_index(inode_ref, 1227 file_block, &fs_block); 1221 1228 if (rc != EOK) { 1222 1229 async_answer_0(callid, rc); 1223 1230 return rc; 1224 1231 } 1225 1226 /* Check for sparse file 1232 1233 /* 1234 * Check for sparse file. 1227 1235 * If ext4_filesystem_get_inode_data_block_index returned 1228 1236 * fs_block == 0, it means that the given block is not allocated for the … … 1236 1244 return ENOMEM; 1237 1245 } 1238 1246 1239 1247 memset(buffer, 0, bytes); 1240 1248 1241 1249 async_data_read_finalize(callid, buffer, bytes); 1242 1250 *rbytes = bytes; 1243 1251 1244 1252 free(buffer); 1245 1246 1253 return EOK; 1247 1254 } 1248 1255 1249 1256 /* Usual case - we need to read a block from device */ 1250 1257 block_t *block; … … 1254 1261 return rc; 1255 1262 } 1256 1263 1257 1264 assert(offset_in_block + bytes <= block_size); 1258 1265 async_data_read_finalize(callid, block->data + offset_in_block, bytes); 1259 1266 1260 1267 rc = block_put(block); 1261 if (rc != EOK) { 1262 return rc; 1263 } 1264 1268 if (rc != EOK) 1269 return rc; 1270 1265 1271 *rbytes = bytes; 1266 1272 return EOK; 1267 1273 } 1268 1274 1269 1270 1275 /** Write bytes to file 1271 1276 * 1272 * @param service_id device identifier1273 * @param index i-node number of file1274 * @param pos position in file to start reading from1275 * @param wbytes output value - real number of written bytes1276 * @param nsize output value - new size of i-node1277 * @return error code1278 * /1279 static int ext4fs_write(service_id_t service_id, fs_index_t index, 1280 aoff64_t pos, size_t *wbytes, aoff64_t *nsize) 1281 { 1282 int rc; 1283 1277 * @param service_id Device identifier 1278 * @param index I-node number of file 1279 * @param pos Position in file to start reading from 1280 * @param wbytes Output value - real number of written bytes 1281 * @param nsize Output value - new size of i-node 1282 * 1283 * @return Error code 1284 * 1285 */ 1286 static int ext4fs_write(service_id_t service_id, fs_index_t index, aoff64_t pos, 1287 size_t *wbytes, aoff64_t *nsize) 1288 { 1284 1289 fs_node_t *fn; 1285 rc = ext4fs_node_get(&fn, service_id, index); 1286 if (rc != EOK) { 1287 return rc; 1288 } 1289 1290 int rc = ext4fs_node_get(&fn, service_id, index); 1291 if (rc != EOK) 1292 return rc; 1293 1290 1294 ipc_callid_t callid; 1291 1295 size_t len; 1292 1296 if (!async_data_write_receive(&callid, &len)) { 1293 rc = EINVAL; 1297 ext4fs_node_put(fn); 1298 async_answer_0(callid, EINVAL); 1299 return EINVAL; 1300 } 1301 1302 ext4fs_node_t *enode = EXT4FS_NODE(fn); 1303 ext4_filesystem_t *fs = enode->instance->filesystem; 1304 1305 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 1306 1307 /* Prevent writing to more than one block */ 1308 uint32_t bytes = min(len, block_size - (pos % block_size)); 1309 1310 int flags = BLOCK_FLAGS_NONE; 1311 if (bytes == block_size) 1312 flags = BLOCK_FLAGS_NOREAD; 1313 1314 uint32_t iblock = pos / block_size; 1315 uint32_t fblock; 1316 1317 /* Load inode */ 1318 ext4_inode_ref_t *inode_ref = enode->inode_ref; 1319 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, iblock, 1320 &fblock); 1321 if (rc != EOK) { 1294 1322 ext4fs_node_put(fn); 1295 1323 async_answer_0(callid, rc); 1296 1324 return rc; 1297 1325 } 1298 1299 1300 ext4fs_node_t *enode = EXT4FS_NODE(fn); 1301 ext4_filesystem_t *fs = enode->instance->filesystem; 1302 1303 uint32_t block_size = ext4_superblock_get_block_size(fs->superblock); 1304 1305 /* Prevent writing to more than one block */ 1306 uint32_t bytes = min(len, block_size - (pos % block_size)); 1307 1308 int flags = BLOCK_FLAGS_NONE; 1309 if (bytes == block_size) { 1310 flags = BLOCK_FLAGS_NOREAD; 1311 } 1312 1313 uint32_t iblock = pos / block_size; 1314 uint32_t fblock; 1315 1316 /* Load inode */ 1317 ext4_inode_ref_t *inode_ref = enode->inode_ref; 1318 rc = ext4_filesystem_get_inode_data_block_index(inode_ref, iblock, &fblock); 1319 if (rc != EOK) { 1320 ext4fs_node_put(fn); 1321 async_answer_0(callid, rc); 1322 return rc; 1323 } 1324 1326 1325 1327 /* Check for sparse file */ 1326 1328 if (fblock == 0) { 1327 1328 if (ext4_superblock_has_feature_incompatible( 1329 fs->superblock, EXT4_FEATURE_INCOMPAT_EXTENTS) && 1330 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 1331 1332 uint32_t last_iblock = ext4_inode_get_size(fs->superblock, inode_ref->inode) / block_size; 1329 if ((ext4_superblock_has_feature_incompatible(fs->superblock, 1330 EXT4_FEATURE_INCOMPAT_EXTENTS)) && 1331 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) { 1332 uint32_t last_iblock = 1333 ext4_inode_get_size(fs->superblock, inode_ref->inode) / 1334 block_size; 1335 1333 1336 while (last_iblock < iblock) { 1334 rc = ext4_extent_append_block(inode_ref, &last_iblock, &fblock, true); 1337 rc = ext4_extent_append_block(inode_ref, &last_iblock, 1338 &fblock, true); 1335 1339 if (rc != EOK) { 1336 1340 ext4fs_node_put(fn); … … 1339 1343 } 1340 1344 } 1341 1342 rc = ext4_extent_append_block(inode_ref, &last_iblock, &fblock, false); 1345 1346 rc = ext4_extent_append_block(inode_ref, &last_iblock, 1347 &fblock, false); 1343 1348 if (rc != EOK) { 1344 1349 ext4fs_node_put(fn); … … 1346 1351 return rc; 1347 1352 } 1348 1349 1353 } else { 1350 rc = 1354 rc = ext4_balloc_alloc_block(inode_ref, &fblock); 1351 1355 if (rc != EOK) { 1352 1356 ext4fs_node_put(fn); … … 1354 1358 return rc; 1355 1359 } 1356 1357 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, iblock, fblock); 1360 1361 rc = ext4_filesystem_set_inode_data_block_index(inode_ref, 1362 iblock, fblock); 1358 1363 if (rc != EOK) { 1359 1364 ext4_balloc_free_block(inode_ref, fblock); … … 1363 1368 } 1364 1369 } 1365 1370 1366 1371 flags = BLOCK_FLAGS_NOREAD; 1367 1372 inode_ref->dirty = true; 1368 1373 } 1369 1374 1370 1375 /* Load target block */ 1371 1376 block_t *write_block; … … 1376 1381 return rc; 1377 1382 } 1378 1379 if (flags == BLOCK_FLAGS_NOREAD) {1383 1384 if (flags == BLOCK_FLAGS_NOREAD) 1380 1385 memset(write_block->data, 0, block_size); 1381 }1382 1383 rc = async_data_write_finalize(callid, write_block->data +(pos % block_size), bytes);1386 1387 rc = async_data_write_finalize(callid, write_block->data + 1388 (pos % block_size), bytes); 1384 1389 if (rc != EOK) { 1385 1390 ext4fs_node_put(fn); 1386 1391 return rc; 1387 1392 } 1388 1393 1389 1394 write_block->dirty = true; 1390 1395 1391 1396 rc = block_put(write_block); 1392 1397 if (rc != EOK) { … … 1394 1399 return rc; 1395 1400 } 1396 1401 1397 1402 /* Do some counting */ 1398 uint32_t old_inode_size = ext4_inode_get_size(fs->superblock, inode_ref->inode); 1403 uint32_t old_inode_size = ext4_inode_get_size(fs->superblock, 1404 inode_ref->inode); 1399 1405 if (pos + bytes > old_inode_size) { 1400 1406 ext4_inode_set_size(inode_ref->inode, pos + bytes); 1401 1407 inode_ref->dirty = true; 1402 1408 } 1403 1409 1404 1410 *nsize = ext4_inode_get_size(fs->superblock, inode_ref->inode); 1405 1411 *wbytes = bytes; 1406 1412 1407 1413 return ext4fs_node_put(fn); 1408 1414 } 1409 1415 1410 1411 1416 /** Truncate file. 1412 1417 * 1413 1418 * Only the direction to shorter file is supported. 1414 1419 * 1415 * @param service_id device identifier 1416 * @param index index if node to truncated 1417 * @param new_size new size of file 1418 * @return error code 1420 * @param service_id Device identifier 1421 * @param index Index if node to truncated 1422 * @param new_size New size of file 1423 * 1424 * @return Error code 1425 * 1419 1426 */ 1420 1427 static int ext4fs_truncate(service_id_t service_id, fs_index_t index, 1421 aoff64_t new_size) 1422 { 1423 int rc; 1424 1428 aoff64_t new_size) 1429 { 1425 1430 fs_node_t *fn; 1426 rc = ext4fs_node_get(&fn, service_id, index); 1427 if (rc != EOK) { 1428 return rc; 1429 } 1430 1431 int rc = ext4fs_node_get(&fn, service_id, index); 1432 if (rc != EOK) 1433 return rc; 1434 1431 1435 ext4fs_node_t *enode = EXT4FS_NODE(fn); 1432 1436 ext4_inode_ref_t *inode_ref = enode->inode_ref; 1433 1437 1434 1438 rc = ext4_filesystem_truncate_inode(inode_ref, new_size); 1435 1439 ext4fs_node_put(fn); 1436 1440 1437 1441 return rc; 1438 1442 } 1439 1443 1440 1441 1444 /** Close file. 1442 1445 * 1443 * @param service_id device identifier 1444 * @param index i-node number 1445 * @return error code 1446 * @param service_id Device identifier 1447 * @param index I-node number 1448 * 1449 * @return Error code 1450 * 1446 1451 */ 1447 1452 static int ext4fs_close(service_id_t service_id, fs_index_t index) … … 1450 1455 } 1451 1456 1452 1453 1457 /** Destroy node specified by index. 1454 1458 * 1455 * @param service_id device identifier 1456 * @param index number of i-node to destroy 1457 * @return error code 1459 * @param service_id Device identifier 1460 * @param index I-node to destroy 1461 * 1462 * @return Error code 1463 * 1458 1464 */ 1459 1465 static int ext4fs_destroy(service_id_t service_id, fs_index_t index) 1460 1466 { 1461 int rc;1462 1463 1467 fs_node_t *fn; 1464 rc = ext4fs_node_get(&fn, service_id, index); 1465 if (rc != EOK) { 1466 return rc; 1467 } 1468 1468 int rc = ext4fs_node_get(&fn, service_id, index); 1469 if (rc != EOK) 1470 return rc; 1471 1469 1472 /* Destroy the inode */ 1470 1473 return ext4fs_destroy_node(fn); 1471 1474 } 1472 1475 1473 /** Enforce inode synchronization (write) to device. 1474 * 1475 * @param service_id device identifier 1476 * @param index i-node number. 1476 /** Enforce inode synchronization (write) to device. 1477 * 1478 * @param service_id Device identifier 1479 * @param index I-node number. 1480 * 1477 1481 */ 1478 1482 static int ext4fs_sync(service_id_t service_id, fs_index_t index) 1479 1483 { 1480 int rc;1481 1482 1484 fs_node_t *fn; 1483 rc = ext4fs_node_get(&fn, service_id, index); 1484 if (rc != EOK) { 1485 return rc; 1486 } 1487 1485 int rc = ext4fs_node_get(&fn, service_id, index); 1486 if (rc != EOK) 1487 return rc; 1488 1488 1489 ext4fs_node_t *enode = EXT4FS_NODE(fn); 1489 1490 enode->inode_ref->dirty = true; 1490 1491 1491 1492 return ext4fs_node_put(fn); 1492 1493 } … … 1503 1504 .close = ext4fs_close, 1504 1505 .destroy = ext4fs_destroy, 1505 .sync = ext4fs_sync ,1506 .sync = ext4fs_sync 1506 1507 }; 1507 1508
Note:
See TracChangeset
for help on using the changeset viewer.