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