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