1 /* 2 * (C) Copyright 2011 - 2012 Samsung Electronics 3 * EXT4 filesystem implementation in Uboot by 4 * Uma Shankar <uma.shankar@samsung.com> 5 * Manjunatha C Achar <a.manjunatha@samsung.com> 6 * 7 * ext4ls and ext4load : Based on ext2 ls and load support in Uboot. 8 * Ext4 read optimization taken from Open-Moko 9 * Qi bootloader 10 * 11 * (C) Copyright 2004 12 * esd gmbh <www.esd-electronics.com> 13 * Reinhard Arlt <reinhard.arlt@esd-electronics.com> 14 * 15 * based on code from grub2 fs/ext2.c and fs/fshelp.c by 16 * GRUB -- GRand Unified Bootloader 17 * Copyright (C) 2003, 2004 Free Software Foundation, Inc. 18 * 19 * ext4write : Based on generic ext4 protocol. 20 * 21 * SPDX-License-Identifier: GPL-2.0+ 22 */ 23 24 25 #include <common.h> 26 #include <linux/stat.h> 27 #include <div64.h> 28 #include "ext4_common.h" 29 30 static void ext4fs_update(void) 31 { 32 short i; 33 ext4fs_update_journal(); 34 struct ext_filesystem *fs = get_fs(); 35 36 /* update super block */ 37 put_ext4((uint64_t)(SUPERBLOCK_SIZE), 38 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); 39 40 /* update block groups */ 41 for (i = 0; i < fs->no_blkgrp; i++) { 42 fs->bgd[i].bg_checksum = ext4fs_checksum_update(i); 43 put_ext4((uint64_t)(fs->bgd[i].block_id * fs->blksz), 44 fs->blk_bmaps[i], fs->blksz); 45 } 46 47 /* update inode table groups */ 48 for (i = 0; i < fs->no_blkgrp; i++) { 49 put_ext4((uint64_t) (fs->bgd[i].inode_id * fs->blksz), 50 fs->inode_bmaps[i], fs->blksz); 51 } 52 53 /* update the block group descriptor table */ 54 put_ext4((uint64_t)(fs->gdtable_blkno * fs->blksz), 55 (struct ext2_block_group *)fs->gdtable, 56 (fs->blksz * fs->no_blk_pergdt)); 57 58 ext4fs_dump_metadata(); 59 60 gindex = 0; 61 gd_index = 0; 62 } 63 64 int ext4fs_get_bgdtable(void) 65 { 66 int status; 67 int grp_desc_size; 68 struct ext_filesystem *fs = get_fs(); 69 grp_desc_size = sizeof(struct ext2_block_group); 70 fs->no_blk_pergdt = (fs->no_blkgrp * grp_desc_size) / fs->blksz; 71 if ((fs->no_blkgrp * grp_desc_size) % fs->blksz) 72 fs->no_blk_pergdt++; 73 74 /* allocate memory for gdtable */ 75 fs->gdtable = zalloc(fs->blksz * fs->no_blk_pergdt); 76 if (!fs->gdtable) 77 return -ENOMEM; 78 /* read the group descriptor table */ 79 status = ext4fs_devread((lbaint_t)fs->gdtable_blkno * fs->sect_perblk, 80 0, fs->blksz * fs->no_blk_pergdt, fs->gdtable); 81 if (status == 0) 82 goto fail; 83 84 if (ext4fs_log_gdt(fs->gdtable)) { 85 printf("Error in ext4fs_log_gdt\n"); 86 return -1; 87 } 88 89 return 0; 90 fail: 91 free(fs->gdtable); 92 fs->gdtable = NULL; 93 94 return -1; 95 } 96 97 static void delete_single_indirect_block(struct ext2_inode *inode) 98 { 99 struct ext2_block_group *bgd = NULL; 100 static int prev_bg_bmap_idx = -1; 101 long int blknr; 102 int remainder; 103 int bg_idx; 104 int status; 105 unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; 106 struct ext_filesystem *fs = get_fs(); 107 char *journal_buffer = zalloc(fs->blksz); 108 if (!journal_buffer) { 109 printf("No memory\n"); 110 return; 111 } 112 /* get block group descriptor table */ 113 bgd = (struct ext2_block_group *)fs->gdtable; 114 115 /* deleting the single indirect block associated with inode */ 116 if (inode->b.blocks.indir_block != 0) { 117 debug("SIPB releasing %u\n", inode->b.blocks.indir_block); 118 blknr = inode->b.blocks.indir_block; 119 if (fs->blksz != 1024) { 120 bg_idx = blknr / blk_per_grp; 121 } else { 122 bg_idx = blknr / blk_per_grp; 123 remainder = blknr % blk_per_grp; 124 if (!remainder) 125 bg_idx--; 126 } 127 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); 128 bgd[bg_idx].free_blocks++; 129 fs->sb->free_blocks++; 130 /* journal backup */ 131 if (prev_bg_bmap_idx != bg_idx) { 132 status = 133 ext4fs_devread((lbaint_t)bgd[bg_idx].block_id * 134 fs->sect_perblk, 0, fs->blksz, 135 journal_buffer); 136 if (status == 0) 137 goto fail; 138 if (ext4fs_log_journal 139 (journal_buffer, bgd[bg_idx].block_id)) 140 goto fail; 141 prev_bg_bmap_idx = bg_idx; 142 } 143 } 144 fail: 145 free(journal_buffer); 146 } 147 148 static void delete_double_indirect_block(struct ext2_inode *inode) 149 { 150 int i; 151 short status; 152 static int prev_bg_bmap_idx = -1; 153 long int blknr; 154 int remainder; 155 int bg_idx; 156 unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; 157 unsigned int *di_buffer = NULL; 158 unsigned int *DIB_start_addr = NULL; 159 struct ext2_block_group *bgd = NULL; 160 struct ext_filesystem *fs = get_fs(); 161 char *journal_buffer = zalloc(fs->blksz); 162 if (!journal_buffer) { 163 printf("No memory\n"); 164 return; 165 } 166 /* get the block group descriptor table */ 167 bgd = (struct ext2_block_group *)fs->gdtable; 168 169 if (inode->b.blocks.double_indir_block != 0) { 170 di_buffer = zalloc(fs->blksz); 171 if (!di_buffer) { 172 printf("No memory\n"); 173 return; 174 } 175 DIB_start_addr = (unsigned int *)di_buffer; 176 blknr = inode->b.blocks.double_indir_block; 177 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, 178 fs->blksz, (char *)di_buffer); 179 for (i = 0; i < fs->blksz / sizeof(int); i++) { 180 if (*di_buffer == 0) 181 break; 182 183 debug("DICB releasing %u\n", *di_buffer); 184 if (fs->blksz != 1024) { 185 bg_idx = (*di_buffer) / blk_per_grp; 186 } else { 187 bg_idx = (*di_buffer) / blk_per_grp; 188 remainder = (*di_buffer) % blk_per_grp; 189 if (!remainder) 190 bg_idx--; 191 } 192 ext4fs_reset_block_bmap(*di_buffer, 193 fs->blk_bmaps[bg_idx], bg_idx); 194 di_buffer++; 195 bgd[bg_idx].free_blocks++; 196 fs->sb->free_blocks++; 197 /* journal backup */ 198 if (prev_bg_bmap_idx != bg_idx) { 199 status = ext4fs_devread((lbaint_t) 200 bgd[bg_idx].block_id 201 * fs->sect_perblk, 0, 202 fs->blksz, 203 journal_buffer); 204 if (status == 0) 205 goto fail; 206 207 if (ext4fs_log_journal(journal_buffer, 208 bgd[bg_idx].block_id)) 209 goto fail; 210 prev_bg_bmap_idx = bg_idx; 211 } 212 } 213 214 /* removing the parent double indirect block */ 215 blknr = inode->b.blocks.double_indir_block; 216 if (fs->blksz != 1024) { 217 bg_idx = blknr / blk_per_grp; 218 } else { 219 bg_idx = blknr / blk_per_grp; 220 remainder = blknr % blk_per_grp; 221 if (!remainder) 222 bg_idx--; 223 } 224 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); 225 bgd[bg_idx].free_blocks++; 226 fs->sb->free_blocks++; 227 /* journal backup */ 228 if (prev_bg_bmap_idx != bg_idx) { 229 memset(journal_buffer, '\0', fs->blksz); 230 status = ext4fs_devread((lbaint_t)bgd[bg_idx].block_id * 231 fs->sect_perblk, 0, fs->blksz, 232 journal_buffer); 233 if (status == 0) 234 goto fail; 235 236 if (ext4fs_log_journal(journal_buffer, 237 bgd[bg_idx].block_id)) 238 goto fail; 239 prev_bg_bmap_idx = bg_idx; 240 } 241 debug("DIPB releasing %ld\n", blknr); 242 } 243 fail: 244 free(DIB_start_addr); 245 free(journal_buffer); 246 } 247 248 static void delete_triple_indirect_block(struct ext2_inode *inode) 249 { 250 int i, j; 251 short status; 252 static int prev_bg_bmap_idx = -1; 253 long int blknr; 254 int remainder; 255 int bg_idx; 256 unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; 257 unsigned int *tigp_buffer = NULL; 258 unsigned int *tib_start_addr = NULL; 259 unsigned int *tip_buffer = NULL; 260 unsigned int *tipb_start_addr = NULL; 261 struct ext2_block_group *bgd = NULL; 262 struct ext_filesystem *fs = get_fs(); 263 char *journal_buffer = zalloc(fs->blksz); 264 if (!journal_buffer) { 265 printf("No memory\n"); 266 return; 267 } 268 /* get block group descriptor table */ 269 bgd = (struct ext2_block_group *)fs->gdtable; 270 271 if (inode->b.blocks.triple_indir_block != 0) { 272 tigp_buffer = zalloc(fs->blksz); 273 if (!tigp_buffer) { 274 printf("No memory\n"); 275 return; 276 } 277 tib_start_addr = (unsigned int *)tigp_buffer; 278 blknr = inode->b.blocks.triple_indir_block; 279 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, 280 fs->blksz, (char *)tigp_buffer); 281 for (i = 0; i < fs->blksz / sizeof(int); i++) { 282 if (*tigp_buffer == 0) 283 break; 284 debug("tigp buffer releasing %u\n", *tigp_buffer); 285 286 tip_buffer = zalloc(fs->blksz); 287 if (!tip_buffer) 288 goto fail; 289 tipb_start_addr = (unsigned int *)tip_buffer; 290 status = ext4fs_devread((lbaint_t)(*tigp_buffer) * 291 fs->sect_perblk, 0, fs->blksz, 292 (char *)tip_buffer); 293 for (j = 0; j < fs->blksz / sizeof(int); j++) { 294 if (*tip_buffer == 0) 295 break; 296 if (fs->blksz != 1024) { 297 bg_idx = (*tip_buffer) / blk_per_grp; 298 } else { 299 bg_idx = (*tip_buffer) / blk_per_grp; 300 301 remainder = (*tip_buffer) % blk_per_grp; 302 if (!remainder) 303 bg_idx--; 304 } 305 306 ext4fs_reset_block_bmap(*tip_buffer, 307 fs->blk_bmaps[bg_idx], 308 bg_idx); 309 310 tip_buffer++; 311 bgd[bg_idx].free_blocks++; 312 fs->sb->free_blocks++; 313 /* journal backup */ 314 if (prev_bg_bmap_idx != bg_idx) { 315 status = 316 ext4fs_devread( 317 (lbaint_t) 318 bgd[bg_idx].block_id * 319 fs->sect_perblk, 0, 320 fs->blksz, 321 journal_buffer); 322 if (status == 0) 323 goto fail; 324 325 if (ext4fs_log_journal(journal_buffer, 326 bgd[bg_idx]. 327 block_id)) 328 goto fail; 329 prev_bg_bmap_idx = bg_idx; 330 } 331 } 332 free(tipb_start_addr); 333 tipb_start_addr = NULL; 334 335 /* 336 * removing the grand parent blocks 337 * which is connected to inode 338 */ 339 if (fs->blksz != 1024) { 340 bg_idx = (*tigp_buffer) / blk_per_grp; 341 } else { 342 bg_idx = (*tigp_buffer) / blk_per_grp; 343 344 remainder = (*tigp_buffer) % blk_per_grp; 345 if (!remainder) 346 bg_idx--; 347 } 348 ext4fs_reset_block_bmap(*tigp_buffer, 349 fs->blk_bmaps[bg_idx], bg_idx); 350 351 tigp_buffer++; 352 bgd[bg_idx].free_blocks++; 353 fs->sb->free_blocks++; 354 /* journal backup */ 355 if (prev_bg_bmap_idx != bg_idx) { 356 memset(journal_buffer, '\0', fs->blksz); 357 status = 358 ext4fs_devread((lbaint_t) 359 bgd[bg_idx].block_id * 360 fs->sect_perblk, 0, 361 fs->blksz, journal_buffer); 362 if (status == 0) 363 goto fail; 364 365 if (ext4fs_log_journal(journal_buffer, 366 bgd[bg_idx].block_id)) 367 goto fail; 368 prev_bg_bmap_idx = bg_idx; 369 } 370 } 371 372 /* removing the grand parent triple indirect block */ 373 blknr = inode->b.blocks.triple_indir_block; 374 if (fs->blksz != 1024) { 375 bg_idx = blknr / blk_per_grp; 376 } else { 377 bg_idx = blknr / blk_per_grp; 378 remainder = blknr % blk_per_grp; 379 if (!remainder) 380 bg_idx--; 381 } 382 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); 383 bgd[bg_idx].free_blocks++; 384 fs->sb->free_blocks++; 385 /* journal backup */ 386 if (prev_bg_bmap_idx != bg_idx) { 387 memset(journal_buffer, '\0', fs->blksz); 388 status = ext4fs_devread((lbaint_t)bgd[bg_idx].block_id * 389 fs->sect_perblk, 0, fs->blksz, 390 journal_buffer); 391 if (status == 0) 392 goto fail; 393 394 if (ext4fs_log_journal(journal_buffer, 395 bgd[bg_idx].block_id)) 396 goto fail; 397 prev_bg_bmap_idx = bg_idx; 398 } 399 debug("tigp buffer itself releasing %ld\n", blknr); 400 } 401 fail: 402 free(tib_start_addr); 403 free(tipb_start_addr); 404 free(journal_buffer); 405 } 406 407 static int ext4fs_delete_file(int inodeno) 408 { 409 struct ext2_inode inode; 410 short status; 411 int i; 412 int remainder; 413 long int blknr; 414 int bg_idx; 415 int ibmap_idx; 416 char *read_buffer = NULL; 417 char *start_block_address = NULL; 418 unsigned int no_blocks; 419 420 static int prev_bg_bmap_idx = -1; 421 unsigned int inodes_per_block; 422 long int blkno; 423 unsigned int blkoff; 424 unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; 425 unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group; 426 struct ext2_inode *inode_buffer = NULL; 427 struct ext2_block_group *bgd = NULL; 428 struct ext_filesystem *fs = get_fs(); 429 char *journal_buffer = zalloc(fs->blksz); 430 if (!journal_buffer) 431 return -ENOMEM; 432 /* get the block group descriptor table */ 433 bgd = (struct ext2_block_group *)fs->gdtable; 434 status = ext4fs_read_inode(ext4fs_root, inodeno, &inode); 435 if (status == 0) 436 goto fail; 437 438 /* read the block no allocated to a file */ 439 no_blocks = inode.size / fs->blksz; 440 if (inode.size % fs->blksz) 441 no_blocks++; 442 443 if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) { 444 struct ext2fs_node *node_inode = 445 zalloc(sizeof(struct ext2fs_node)); 446 if (!node_inode) 447 goto fail; 448 node_inode->data = ext4fs_root; 449 node_inode->ino = inodeno; 450 node_inode->inode_read = 0; 451 memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode)); 452 453 for (i = 0; i < no_blocks; i++) { 454 blknr = read_allocated_block(&(node_inode->inode), i); 455 if (fs->blksz != 1024) { 456 bg_idx = blknr / blk_per_grp; 457 } else { 458 bg_idx = blknr / blk_per_grp; 459 remainder = blknr % blk_per_grp; 460 if (!remainder) 461 bg_idx--; 462 } 463 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], 464 bg_idx); 465 debug("EXT4_EXTENTS Block releasing %ld: %d\n", 466 blknr, bg_idx); 467 468 bgd[bg_idx].free_blocks++; 469 fs->sb->free_blocks++; 470 471 /* journal backup */ 472 if (prev_bg_bmap_idx != bg_idx) { 473 status = 474 ext4fs_devread((lbaint_t) 475 bgd[bg_idx].block_id * 476 fs->sect_perblk, 0, 477 fs->blksz, journal_buffer); 478 if (status == 0) 479 goto fail; 480 if (ext4fs_log_journal(journal_buffer, 481 bgd[bg_idx].block_id)) 482 goto fail; 483 prev_bg_bmap_idx = bg_idx; 484 } 485 } 486 if (node_inode) { 487 free(node_inode); 488 node_inode = NULL; 489 } 490 } else { 491 492 delete_single_indirect_block(&inode); 493 delete_double_indirect_block(&inode); 494 delete_triple_indirect_block(&inode); 495 496 /* read the block no allocated to a file */ 497 no_blocks = inode.size / fs->blksz; 498 if (inode.size % fs->blksz) 499 no_blocks++; 500 for (i = 0; i < no_blocks; i++) { 501 blknr = read_allocated_block(&inode, i); 502 if (fs->blksz != 1024) { 503 bg_idx = blknr / blk_per_grp; 504 } else { 505 bg_idx = blknr / blk_per_grp; 506 remainder = blknr % blk_per_grp; 507 if (!remainder) 508 bg_idx--; 509 } 510 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], 511 bg_idx); 512 debug("ActualB releasing %ld: %d\n", blknr, bg_idx); 513 514 bgd[bg_idx].free_blocks++; 515 fs->sb->free_blocks++; 516 /* journal backup */ 517 if (prev_bg_bmap_idx != bg_idx) { 518 memset(journal_buffer, '\0', fs->blksz); 519 status = ext4fs_devread((lbaint_t) 520 bgd[bg_idx].block_id 521 * fs->sect_perblk, 522 0, fs->blksz, 523 journal_buffer); 524 if (status == 0) 525 goto fail; 526 if (ext4fs_log_journal(journal_buffer, 527 bgd[bg_idx].block_id)) 528 goto fail; 529 prev_bg_bmap_idx = bg_idx; 530 } 531 } 532 } 533 534 /* from the inode no to blockno */ 535 inodes_per_block = fs->blksz / fs->inodesz; 536 ibmap_idx = inodeno / inode_per_grp; 537 538 /* get the block no */ 539 inodeno--; 540 blkno = __le32_to_cpu(bgd[ibmap_idx].inode_table_id) + 541 (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block; 542 543 /* get the offset of the inode */ 544 blkoff = ((inodeno) % inodes_per_block) * fs->inodesz; 545 546 /* read the block no containing the inode */ 547 read_buffer = zalloc(fs->blksz); 548 if (!read_buffer) 549 goto fail; 550 start_block_address = read_buffer; 551 status = ext4fs_devread((lbaint_t)blkno * fs->sect_perblk, 552 0, fs->blksz, read_buffer); 553 if (status == 0) 554 goto fail; 555 556 if (ext4fs_log_journal(read_buffer, blkno)) 557 goto fail; 558 559 read_buffer = read_buffer + blkoff; 560 inode_buffer = (struct ext2_inode *)read_buffer; 561 memset(inode_buffer, '\0', sizeof(struct ext2_inode)); 562 563 /* write the inode to original position in inode table */ 564 if (ext4fs_put_metadata(start_block_address, blkno)) 565 goto fail; 566 567 /* update the respective inode bitmaps */ 568 inodeno++; 569 ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx); 570 bgd[ibmap_idx].free_inodes++; 571 fs->sb->free_inodes++; 572 /* journal backup */ 573 memset(journal_buffer, '\0', fs->blksz); 574 status = ext4fs_devread((lbaint_t)bgd[ibmap_idx].inode_id * 575 fs->sect_perblk, 0, fs->blksz, journal_buffer); 576 if (status == 0) 577 goto fail; 578 if (ext4fs_log_journal(journal_buffer, bgd[ibmap_idx].inode_id)) 579 goto fail; 580 581 ext4fs_update(); 582 ext4fs_deinit(); 583 584 if (ext4fs_init() != 0) { 585 printf("error in File System init\n"); 586 goto fail; 587 } 588 589 free(start_block_address); 590 free(journal_buffer); 591 592 return 0; 593 fail: 594 free(start_block_address); 595 free(journal_buffer); 596 597 return -1; 598 } 599 600 int ext4fs_init(void) 601 { 602 short status; 603 int i; 604 unsigned int real_free_blocks = 0; 605 struct ext_filesystem *fs = get_fs(); 606 607 /* populate fs */ 608 fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root); 609 fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root); 610 fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz; 611 612 /* get the superblock */ 613 fs->sb = zalloc(SUPERBLOCK_SIZE); 614 if (!fs->sb) 615 return -ENOMEM; 616 if (!ext4_read_superblock((char *)fs->sb)) 617 goto fail; 618 619 /* init journal */ 620 if (ext4fs_init_journal()) 621 goto fail; 622 623 /* get total no of blockgroups */ 624 fs->no_blkgrp = (uint32_t)ext4fs_div_roundup( 625 (ext4fs_root->sblock.total_blocks - 626 ext4fs_root->sblock.first_data_block), 627 ext4fs_root->sblock.blocks_per_group); 628 629 /* get the block group descriptor table */ 630 fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1); 631 if (ext4fs_get_bgdtable() == -1) { 632 printf("Error in getting the block group descriptor table\n"); 633 goto fail; 634 } 635 fs->bgd = (struct ext2_block_group *)fs->gdtable; 636 637 /* load all the available bitmap block of the partition */ 638 fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *)); 639 if (!fs->blk_bmaps) 640 goto fail; 641 for (i = 0; i < fs->no_blkgrp; i++) { 642 fs->blk_bmaps[i] = zalloc(fs->blksz); 643 if (!fs->blk_bmaps[i]) 644 goto fail; 645 } 646 647 for (i = 0; i < fs->no_blkgrp; i++) { 648 status = 649 ext4fs_devread((lbaint_t)fs->bgd[i].block_id * 650 fs->sect_perblk, 0, 651 fs->blksz, (char *)fs->blk_bmaps[i]); 652 if (status == 0) 653 goto fail; 654 } 655 656 /* load all the available inode bitmap of the partition */ 657 fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *)); 658 if (!fs->inode_bmaps) 659 goto fail; 660 for (i = 0; i < fs->no_blkgrp; i++) { 661 fs->inode_bmaps[i] = zalloc(fs->blksz); 662 if (!fs->inode_bmaps[i]) 663 goto fail; 664 } 665 666 for (i = 0; i < fs->no_blkgrp; i++) { 667 status = ext4fs_devread((lbaint_t)fs->bgd[i].inode_id * 668 fs->sect_perblk, 669 0, fs->blksz, 670 (char *)fs->inode_bmaps[i]); 671 if (status == 0) 672 goto fail; 673 } 674 675 /* 676 * check filesystem consistency with free blocks of file system 677 * some time we observed that superblock freeblocks does not match 678 * with the blockgroups freeblocks when improper 679 * reboot of a linux kernel 680 */ 681 for (i = 0; i < fs->no_blkgrp; i++) 682 real_free_blocks = real_free_blocks + fs->bgd[i].free_blocks; 683 if (real_free_blocks != fs->sb->free_blocks) 684 fs->sb->free_blocks = real_free_blocks; 685 686 return 0; 687 fail: 688 ext4fs_deinit(); 689 690 return -1; 691 } 692 693 void ext4fs_deinit(void) 694 { 695 int i; 696 struct ext2_inode inode_journal; 697 struct journal_superblock_t *jsb; 698 long int blknr; 699 struct ext_filesystem *fs = get_fs(); 700 701 /* free journal */ 702 char *temp_buff = zalloc(fs->blksz); 703 if (temp_buff) { 704 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, 705 &inode_journal); 706 blknr = read_allocated_block(&inode_journal, 707 EXT2_JOURNAL_SUPERBLOCK); 708 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, 709 temp_buff); 710 jsb = (struct journal_superblock_t *)temp_buff; 711 jsb->s_start = cpu_to_be32(0); 712 put_ext4((uint64_t) (blknr * fs->blksz), 713 (struct journal_superblock_t *)temp_buff, fs->blksz); 714 free(temp_buff); 715 } 716 ext4fs_free_journal(); 717 718 /* get the superblock */ 719 ext4_read_superblock((char *)fs->sb); 720 fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; 721 put_ext4((uint64_t)(SUPERBLOCK_SIZE), 722 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); 723 free(fs->sb); 724 fs->sb = NULL; 725 726 if (fs->blk_bmaps) { 727 for (i = 0; i < fs->no_blkgrp; i++) { 728 free(fs->blk_bmaps[i]); 729 fs->blk_bmaps[i] = NULL; 730 } 731 free(fs->blk_bmaps); 732 fs->blk_bmaps = NULL; 733 } 734 735 if (fs->inode_bmaps) { 736 for (i = 0; i < fs->no_blkgrp; i++) { 737 free(fs->inode_bmaps[i]); 738 fs->inode_bmaps[i] = NULL; 739 } 740 free(fs->inode_bmaps); 741 fs->inode_bmaps = NULL; 742 } 743 744 745 free(fs->gdtable); 746 fs->gdtable = NULL; 747 fs->bgd = NULL; 748 /* 749 * reinitiliazed the global inode and 750 * block bitmap first execution check variables 751 */ 752 fs->first_pass_ibmap = 0; 753 fs->first_pass_bbmap = 0; 754 fs->curr_inode_no = 0; 755 fs->curr_blkno = 0; 756 } 757 758 static int ext4fs_write_file(struct ext2_inode *file_inode, 759 int pos, unsigned int len, char *buf) 760 { 761 int i; 762 int blockcnt; 763 unsigned int filesize = __le32_to_cpu(file_inode->size); 764 struct ext_filesystem *fs = get_fs(); 765 int log2blksz = fs->dev_desc->log2blksz; 766 int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz; 767 int previous_block_number = -1; 768 int delayed_start = 0; 769 int delayed_extent = 0; 770 int delayed_next = 0; 771 char *delayed_buf = NULL; 772 773 /* Adjust len so it we can't read past the end of the file. */ 774 if (len > filesize) 775 len = filesize; 776 777 blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz; 778 779 for (i = pos / fs->blksz; i < blockcnt; i++) { 780 long int blknr; 781 int blockend = fs->blksz; 782 int skipfirst = 0; 783 blknr = read_allocated_block(file_inode, i); 784 if (blknr < 0) 785 return -1; 786 787 blknr = blknr << log2_fs_blocksize; 788 789 if (blknr) { 790 if (previous_block_number != -1) { 791 if (delayed_next == blknr) { 792 delayed_extent += blockend; 793 delayed_next += blockend >> log2blksz; 794 } else { /* spill */ 795 put_ext4((uint64_t) 796 (delayed_start << log2blksz), 797 delayed_buf, 798 (uint32_t) delayed_extent); 799 previous_block_number = blknr; 800 delayed_start = blknr; 801 delayed_extent = blockend; 802 delayed_buf = buf; 803 delayed_next = blknr + 804 (blockend >> log2blksz); 805 } 806 } else { 807 previous_block_number = blknr; 808 delayed_start = blknr; 809 delayed_extent = blockend; 810 delayed_buf = buf; 811 delayed_next = blknr + 812 (blockend >> log2blksz); 813 } 814 } else { 815 if (previous_block_number != -1) { 816 /* spill */ 817 put_ext4((uint64_t) (delayed_start << 818 log2blksz), 819 delayed_buf, 820 (uint32_t) delayed_extent); 821 previous_block_number = -1; 822 } 823 memset(buf, 0, fs->blksz - skipfirst); 824 } 825 buf += fs->blksz - skipfirst; 826 } 827 if (previous_block_number != -1) { 828 /* spill */ 829 put_ext4((uint64_t) (delayed_start << log2blksz), 830 delayed_buf, (uint32_t) delayed_extent); 831 previous_block_number = -1; 832 } 833 834 return len; 835 } 836 837 int ext4fs_write(const char *fname, unsigned char *buffer, 838 unsigned long sizebytes) 839 { 840 int ret = 0; 841 struct ext2_inode *file_inode = NULL; 842 unsigned char *inode_buffer = NULL; 843 int parent_inodeno; 844 int inodeno; 845 time_t timestamp = 0; 846 847 uint64_t bytes_reqd_for_file; 848 unsigned int blks_reqd_for_file; 849 unsigned int blocks_remaining; 850 int existing_file_inodeno; 851 char *temp_ptr = NULL; 852 long int itable_blkno; 853 long int parent_itable_blkno; 854 long int blkoff; 855 struct ext2_sblock *sblock = &(ext4fs_root->sblock); 856 unsigned int inodes_per_block; 857 unsigned int ibmap_idx; 858 struct ext_filesystem *fs = get_fs(); 859 ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256); 860 memset(filename, 0x00, sizeof(filename)); 861 862 g_parent_inode = zalloc(sizeof(struct ext2_inode)); 863 if (!g_parent_inode) 864 goto fail; 865 866 if (ext4fs_init() != 0) { 867 printf("error in File System init\n"); 868 return -1; 869 } 870 inodes_per_block = fs->blksz / fs->inodesz; 871 parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE); 872 if (parent_inodeno == -1) 873 goto fail; 874 if (ext4fs_iget(parent_inodeno, g_parent_inode)) 875 goto fail; 876 /* check if the filename is already present in root */ 877 existing_file_inodeno = ext4fs_filename_check(filename); 878 if (existing_file_inodeno != -1) { 879 ret = ext4fs_delete_file(existing_file_inodeno); 880 fs->first_pass_bbmap = 0; 881 fs->curr_blkno = 0; 882 883 fs->first_pass_ibmap = 0; 884 fs->curr_inode_no = 0; 885 if (ret) 886 goto fail; 887 } 888 /* calucalate how many blocks required */ 889 bytes_reqd_for_file = sizebytes; 890 blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz); 891 if (do_div(bytes_reqd_for_file, fs->blksz) != 0) { 892 blks_reqd_for_file++; 893 debug("total bytes for a file %u\n", blks_reqd_for_file); 894 } 895 blocks_remaining = blks_reqd_for_file; 896 /* test for available space in partition */ 897 if (fs->sb->free_blocks < blks_reqd_for_file) { 898 printf("Not enough space on partition !!!\n"); 899 goto fail; 900 } 901 902 ext4fs_update_parent_dentry(filename, &inodeno, FILETYPE_REG); 903 /* prepare file inode */ 904 inode_buffer = zalloc(fs->inodesz); 905 if (!inode_buffer) 906 goto fail; 907 file_inode = (struct ext2_inode *)inode_buffer; 908 file_inode->mode = S_IFREG | S_IRWXU | 909 S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH; 910 /* ToDo: Update correct time */ 911 file_inode->mtime = timestamp; 912 file_inode->atime = timestamp; 913 file_inode->ctime = timestamp; 914 file_inode->nlinks = 1; 915 file_inode->size = sizebytes; 916 917 /* Allocate data blocks */ 918 ext4fs_allocate_blocks(file_inode, blocks_remaining, 919 &blks_reqd_for_file); 920 file_inode->blockcnt = (blks_reqd_for_file * fs->blksz) >> 921 fs->dev_desc->log2blksz; 922 923 temp_ptr = zalloc(fs->blksz); 924 if (!temp_ptr) 925 goto fail; 926 ibmap_idx = inodeno / ext4fs_root->sblock.inodes_per_group; 927 inodeno--; 928 itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + 929 (inodeno % __le32_to_cpu(sblock->inodes_per_group)) / 930 inodes_per_block; 931 blkoff = (inodeno % inodes_per_block) * fs->inodesz; 932 ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz, 933 temp_ptr); 934 if (ext4fs_log_journal(temp_ptr, itable_blkno)) 935 goto fail; 936 937 memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz); 938 if (ext4fs_put_metadata(temp_ptr, itable_blkno)) 939 goto fail; 940 /* copy the file content into data blocks */ 941 if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) { 942 printf("Error in copying content\n"); 943 goto fail; 944 } 945 ibmap_idx = parent_inodeno / ext4fs_root->sblock.inodes_per_group; 946 parent_inodeno--; 947 parent_itable_blkno = __le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + 948 (parent_inodeno % 949 __le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; 950 blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz; 951 if (parent_itable_blkno != itable_blkno) { 952 memset(temp_ptr, '\0', fs->blksz); 953 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk, 954 0, fs->blksz, temp_ptr); 955 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno)) 956 goto fail; 957 958 memcpy(temp_ptr + blkoff, g_parent_inode, 959 sizeof(struct ext2_inode)); 960 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno)) 961 goto fail; 962 free(temp_ptr); 963 } else { 964 /* 965 * If parent and child fall in same inode table block 966 * both should be kept in 1 buffer 967 */ 968 memcpy(temp_ptr + blkoff, g_parent_inode, 969 sizeof(struct ext2_inode)); 970 gd_index--; 971 if (ext4fs_put_metadata(temp_ptr, itable_blkno)) 972 goto fail; 973 free(temp_ptr); 974 } 975 ext4fs_update(); 976 ext4fs_deinit(); 977 978 fs->first_pass_bbmap = 0; 979 fs->curr_blkno = 0; 980 fs->first_pass_ibmap = 0; 981 fs->curr_inode_no = 0; 982 free(inode_buffer); 983 free(g_parent_inode); 984 g_parent_inode = NULL; 985 986 return 0; 987 fail: 988 ext4fs_deinit(); 989 free(inode_buffer); 990 free(g_parent_inode); 991 g_parent_inode = NULL; 992 993 return -1; 994 } 995