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