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