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->gd[i].bg_checksum = ext4fs_checksum_update(i); 213 put_ext4((uint64_t)(fs->gd[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->gd[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 *gd = 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 gd = (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 gd[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(gd[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, gd[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 *gd = 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 gd = (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 gd[bg_idx].free_blocks++; 366 fs->sb->free_blocks++; 367 /* journal backup */ 368 if (prev_bg_bmap_idx != bg_idx) { 369 status = ext4fs_devread(gd[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 gd[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 gd[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(gd[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 gd[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 *gd = 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 gd = (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 gd[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(gd[bg_idx].block_id * 486 fs->sect_perblk, 0, 487 fs->blksz, 488 journal_buffer); 489 if (status == 0) 490 goto fail; 491 492 if (ext4fs_log_journal(journal_buffer, 493 gd[bg_idx]. 494 block_id)) 495 goto fail; 496 prev_bg_bmap_idx = bg_idx; 497 } 498 } 499 free(tipb_start_addr); 500 tipb_start_addr = NULL; 501 502 /* 503 * removing the grand parent blocks 504 * which is connected to inode 505 */ 506 if (fs->blksz != 1024) { 507 bg_idx = (*tigp_buffer) / blk_per_grp; 508 } else { 509 bg_idx = (*tigp_buffer) / blk_per_grp; 510 511 remainder = (*tigp_buffer) % blk_per_grp; 512 if (!remainder) 513 bg_idx--; 514 } 515 ext4fs_reset_block_bmap(*tigp_buffer, 516 fs->blk_bmaps[bg_idx], bg_idx); 517 518 tigp_buffer++; 519 gd[bg_idx].free_blocks++; 520 fs->sb->free_blocks++; 521 /* journal backup */ 522 if (prev_bg_bmap_idx != bg_idx) { 523 memset(journal_buffer, '\0', fs->blksz); 524 status = 525 ext4fs_devread(gd[bg_idx].block_id * 526 fs->sect_perblk, 0, 527 fs->blksz, journal_buffer); 528 if (status == 0) 529 goto fail; 530 531 if (ext4fs_log_journal(journal_buffer, 532 gd[bg_idx].block_id)) 533 goto fail; 534 prev_bg_bmap_idx = bg_idx; 535 } 536 } 537 538 /* removing the grand parent triple indirect block */ 539 blknr = inode->b.blocks.triple_indir_block; 540 if (fs->blksz != 1024) { 541 bg_idx = blknr / blk_per_grp; 542 } else { 543 bg_idx = blknr / blk_per_grp; 544 remainder = blknr % blk_per_grp; 545 if (!remainder) 546 bg_idx--; 547 } 548 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); 549 gd[bg_idx].free_blocks++; 550 fs->sb->free_blocks++; 551 /* journal backup */ 552 if (prev_bg_bmap_idx != bg_idx) { 553 memset(journal_buffer, '\0', fs->blksz); 554 status = ext4fs_devread(gd[bg_idx].block_id * 555 fs->sect_perblk, 0, fs->blksz, 556 journal_buffer); 557 if (status == 0) 558 goto fail; 559 560 if (ext4fs_log_journal(journal_buffer, 561 gd[bg_idx].block_id)) 562 goto fail; 563 prev_bg_bmap_idx = bg_idx; 564 } 565 debug("tigp buffer itself releasing %ld\n", blknr); 566 } 567 fail: 568 free(tib_start_addr); 569 free(tipb_start_addr); 570 free(journal_buffer); 571 } 572 573 static int ext4fs_delete_file(int inodeno) 574 { 575 struct ext2_inode inode; 576 short status; 577 int i; 578 int remainder; 579 long int blknr; 580 int bg_idx; 581 int ibmap_idx; 582 char *read_buffer = NULL; 583 char *start_block_address = NULL; 584 unsigned int no_blocks; 585 586 static int prev_bg_bmap_idx = -1; 587 unsigned int inodes_per_block; 588 long int blkno; 589 unsigned int blkoff; 590 unsigned int blk_per_grp = ext4fs_root->sblock.blocks_per_group; 591 unsigned int inode_per_grp = ext4fs_root->sblock.inodes_per_group; 592 struct ext2_inode *inode_buffer = NULL; 593 struct ext2_block_group *gd = NULL; 594 struct ext_filesystem *fs = get_fs(); 595 char *journal_buffer = zalloc(fs->blksz); 596 if (!journal_buffer) 597 return -ENOMEM; 598 /* get the block group descriptor table */ 599 gd = (struct ext2_block_group *)fs->gdtable; 600 status = ext4fs_read_inode(ext4fs_root, inodeno, &inode); 601 if (status == 0) 602 goto fail; 603 604 /* read the block no allocated to a file */ 605 no_blocks = inode.size / fs->blksz; 606 if (inode.size % fs->blksz) 607 no_blocks++; 608 609 if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) { 610 struct ext2fs_node *node_inode = 611 zalloc(sizeof(struct ext2fs_node)); 612 if (!node_inode) 613 goto fail; 614 node_inode->data = ext4fs_root; 615 node_inode->ino = inodeno; 616 node_inode->inode_read = 0; 617 memcpy(&(node_inode->inode), &inode, sizeof(struct ext2_inode)); 618 619 for (i = 0; i < no_blocks; i++) { 620 blknr = read_allocated_block(&(node_inode->inode), i); 621 if (fs->blksz != 1024) { 622 bg_idx = blknr / blk_per_grp; 623 } else { 624 bg_idx = blknr / blk_per_grp; 625 remainder = blknr % blk_per_grp; 626 if (!remainder) 627 bg_idx--; 628 } 629 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], 630 bg_idx); 631 debug("EXT4_EXTENTS Block releasing %ld: %d\n", 632 blknr, bg_idx); 633 634 gd[bg_idx].free_blocks++; 635 fs->sb->free_blocks++; 636 637 /* journal backup */ 638 if (prev_bg_bmap_idx != bg_idx) { 639 status = 640 ext4fs_devread(gd[bg_idx].block_id * 641 fs->sect_perblk, 0, 642 fs->blksz, journal_buffer); 643 if (status == 0) 644 goto fail; 645 if (ext4fs_log_journal(journal_buffer, 646 gd[bg_idx].block_id)) 647 goto fail; 648 prev_bg_bmap_idx = bg_idx; 649 } 650 } 651 if (node_inode) { 652 free(node_inode); 653 node_inode = NULL; 654 } 655 } else { 656 657 delete_single_indirect_block(&inode); 658 delete_double_indirect_block(&inode); 659 delete_triple_indirect_block(&inode); 660 661 /* read the block no allocated to a file */ 662 no_blocks = inode.size / fs->blksz; 663 if (inode.size % fs->blksz) 664 no_blocks++; 665 for (i = 0; i < no_blocks; i++) { 666 blknr = read_allocated_block(&inode, i); 667 if (fs->blksz != 1024) { 668 bg_idx = blknr / blk_per_grp; 669 } else { 670 bg_idx = blknr / blk_per_grp; 671 remainder = blknr % blk_per_grp; 672 if (!remainder) 673 bg_idx--; 674 } 675 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], 676 bg_idx); 677 debug("ActualB releasing %ld: %d\n", blknr, bg_idx); 678 679 gd[bg_idx].free_blocks++; 680 fs->sb->free_blocks++; 681 /* journal backup */ 682 if (prev_bg_bmap_idx != bg_idx) { 683 memset(journal_buffer, '\0', fs->blksz); 684 status = ext4fs_devread(gd[bg_idx].block_id 685 * fs->sect_perblk, 686 0, fs->blksz, 687 journal_buffer); 688 if (status == 0) 689 goto fail; 690 if (ext4fs_log_journal(journal_buffer, 691 gd[bg_idx].block_id)) 692 goto fail; 693 prev_bg_bmap_idx = bg_idx; 694 } 695 } 696 } 697 698 /* from the inode no to blockno */ 699 inodes_per_block = fs->blksz / fs->inodesz; 700 ibmap_idx = inodeno / inode_per_grp; 701 702 /* get the block no */ 703 inodeno--; 704 blkno = __le32_to_cpu(gd[ibmap_idx].inode_table_id) + 705 (inodeno % __le32_to_cpu(inode_per_grp)) / inodes_per_block; 706 707 /* get the offset of the inode */ 708 blkoff = ((inodeno) % inodes_per_block) * fs->inodesz; 709 710 /* read the block no containing the inode */ 711 read_buffer = zalloc(fs->blksz); 712 if (!read_buffer) 713 goto fail; 714 start_block_address = read_buffer; 715 status = ext4fs_devread(blkno * fs->sect_perblk, 716 0, fs->blksz, read_buffer); 717 if (status == 0) 718 goto fail; 719 720 if (ext4fs_log_journal(read_buffer, blkno)) 721 goto fail; 722 723 read_buffer = read_buffer + blkoff; 724 inode_buffer = (struct ext2_inode *)read_buffer; 725 memset(inode_buffer, '\0', sizeof(struct ext2_inode)); 726 727 /* write the inode to original position in inode table */ 728 if (ext4fs_put_metadata(start_block_address, blkno)) 729 goto fail; 730 731 /* update the respective inode bitmaps */ 732 inodeno++; 733 ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx); 734 gd[ibmap_idx].free_inodes++; 735 fs->sb->free_inodes++; 736 /* journal backup */ 737 memset(journal_buffer, '\0', fs->blksz); 738 status = ext4fs_devread(gd[ibmap_idx].inode_id * 739 fs->sect_perblk, 0, fs->blksz, journal_buffer); 740 if (status == 0) 741 goto fail; 742 if (ext4fs_log_journal(journal_buffer, gd[ibmap_idx].inode_id)) 743 goto fail; 744 745 ext4fs_update(); 746 ext4fs_deinit(); 747 748 if (ext4fs_init() != 0) { 749 printf("error in File System init\n"); 750 goto fail; 751 } 752 753 free(start_block_address); 754 free(journal_buffer); 755 756 return 0; 757 fail: 758 free(start_block_address); 759 free(journal_buffer); 760 761 return -1; 762 } 763 764 int ext4fs_init(void) 765 { 766 short status; 767 int i; 768 unsigned int real_free_blocks = 0; 769 struct ext_filesystem *fs = get_fs(); 770 771 /* populate fs */ 772 fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root); 773 fs->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root); 774 fs->sect_perblk = fs->blksz / SECTOR_SIZE; 775 776 /* get the superblock */ 777 fs->sb = zalloc(SUPERBLOCK_SIZE); 778 if (!fs->sb) 779 return -ENOMEM; 780 if (!ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, 781 (char *)fs->sb)) 782 goto fail; 783 784 /* init journal */ 785 if (ext4fs_init_journal()) 786 goto fail; 787 788 /* get total no of blockgroups */ 789 fs->no_blkgrp = (uint32_t)ext4fs_div_roundup( 790 (ext4fs_root->sblock.total_blocks - 791 ext4fs_root->sblock.first_data_block), 792 ext4fs_root->sblock.blocks_per_group); 793 794 /* get the block group descriptor table */ 795 fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1); 796 if (ext4fs_get_bgdtable() == -1) { 797 printf("Error in getting the block group descriptor table\n"); 798 goto fail; 799 } 800 fs->gd = (struct ext2_block_group *)fs->gdtable; 801 802 /* load all the available bitmap block of the partition */ 803 fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *)); 804 if (!fs->blk_bmaps) 805 goto fail; 806 for (i = 0; i < fs->no_blkgrp; i++) { 807 fs->blk_bmaps[i] = zalloc(fs->blksz); 808 if (!fs->blk_bmaps[i]) 809 goto fail; 810 } 811 812 for (i = 0; i < fs->no_blkgrp; i++) { 813 status = 814 ext4fs_devread(fs->gd[i].block_id * fs->sect_perblk, 0, 815 fs->blksz, (char *)fs->blk_bmaps[i]); 816 if (status == 0) 817 goto fail; 818 } 819 820 /* load all the available inode bitmap of the partition */ 821 fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *)); 822 if (!fs->inode_bmaps) 823 goto fail; 824 for (i = 0; i < fs->no_blkgrp; i++) { 825 fs->inode_bmaps[i] = zalloc(fs->blksz); 826 if (!fs->inode_bmaps[i]) 827 goto fail; 828 } 829 830 for (i = 0; i < fs->no_blkgrp; i++) { 831 status = ext4fs_devread(fs->gd[i].inode_id * fs->sect_perblk, 832 0, fs->blksz, 833 (char *)fs->inode_bmaps[i]); 834 if (status == 0) 835 goto fail; 836 } 837 838 /* 839 * check filesystem consistency with free blocks of file system 840 * some time we observed that superblock freeblocks does not match 841 * with the blockgroups freeblocks when improper 842 * reboot of a linux kernel 843 */ 844 for (i = 0; i < fs->no_blkgrp; i++) 845 real_free_blocks = real_free_blocks + fs->gd[i].free_blocks; 846 if (real_free_blocks != fs->sb->free_blocks) 847 fs->sb->free_blocks = real_free_blocks; 848 849 return 0; 850 fail: 851 ext4fs_deinit(); 852 853 return -1; 854 } 855 856 void ext4fs_deinit(void) 857 { 858 int i; 859 struct ext2_inode inode_journal; 860 struct journal_superblock_t *jsb; 861 long int blknr; 862 struct ext_filesystem *fs = get_fs(); 863 864 /* free journal */ 865 char *temp_buff = zalloc(fs->blksz); 866 if (temp_buff) { 867 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, 868 &inode_journal); 869 blknr = read_allocated_block(&inode_journal, 870 EXT2_JOURNAL_SUPERBLOCK); 871 ext4fs_devread(blknr * fs->sect_perblk, 0, fs->blksz, 872 temp_buff); 873 jsb = (struct journal_superblock_t *)temp_buff; 874 jsb->s_start = cpu_to_be32(0); 875 put_ext4((uint64_t) (blknr * fs->blksz), 876 (struct journal_superblock_t *)temp_buff, fs->blksz); 877 free(temp_buff); 878 } 879 ext4fs_free_journal(); 880 881 /* get the superblock */ 882 ext4fs_devread(SUPERBLOCK_SECTOR, 0, SUPERBLOCK_SIZE, (char *)fs->sb); 883 fs->sb->feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; 884 put_ext4((uint64_t)(SUPERBLOCK_SIZE), 885 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); 886 free(fs->sb); 887 fs->sb = NULL; 888 889 if (fs->blk_bmaps) { 890 for (i = 0; i < fs->no_blkgrp; i++) { 891 free(fs->blk_bmaps[i]); 892 fs->blk_bmaps[i] = NULL; 893 } 894 free(fs->blk_bmaps); 895 fs->blk_bmaps = NULL; 896 } 897 898 if (fs->inode_bmaps) { 899 for (i = 0; i < fs->no_blkgrp; i++) { 900 free(fs->inode_bmaps[i]); 901 fs->inode_bmaps[i] = NULL; 902 } 903 free(fs->inode_bmaps); 904 fs->inode_bmaps = NULL; 905 } 906 907 908 free(fs->gdtable); 909 fs->gdtable = NULL; 910 fs->gd = NULL; 911 /* 912 * reinitiliazed the global inode and 913 * block bitmap first execution check variables 914 */ 915 fs->first_pass_ibmap = 0; 916 fs->first_pass_bbmap = 0; 917 fs->curr_inode_no = 0; 918 fs->curr_blkno = 0; 919 } 920 921 static int ext4fs_write_file(struct ext2_inode *file_inode, 922 int pos, unsigned int len, char *buf) 923 { 924 int i; 925 int blockcnt; 926 int log2blocksize = LOG2_EXT2_BLOCK_SIZE(ext4fs_root); 927 unsigned int filesize = __le32_to_cpu(file_inode->size); 928 struct ext_filesystem *fs = get_fs(); 929 int previous_block_number = -1; 930 int delayed_start = 0; 931 int delayed_extent = 0; 932 int delayed_skipfirst = 0; 933 int delayed_next = 0; 934 char *delayed_buf = NULL; 935 936 /* Adjust len so it we can't read past the end of the file. */ 937 if (len > filesize) 938 len = filesize; 939 940 blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz; 941 942 for (i = pos / fs->blksz; i < blockcnt; i++) { 943 long int blknr; 944 int blockend = fs->blksz; 945 int skipfirst = 0; 946 blknr = read_allocated_block(file_inode, i); 947 if (blknr < 0) 948 return -1; 949 950 blknr = blknr << log2blocksize; 951 952 if (blknr) { 953 if (previous_block_number != -1) { 954 if (delayed_next == blknr) { 955 delayed_extent += blockend; 956 delayed_next += blockend >> SECTOR_BITS; 957 } else { /* spill */ 958 put_ext4((uint64_t) (delayed_start * 959 SECTOR_SIZE), 960 delayed_buf, 961 (uint32_t) delayed_extent); 962 previous_block_number = blknr; 963 delayed_start = blknr; 964 delayed_extent = blockend; 965 delayed_skipfirst = skipfirst; 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_skipfirst = skipfirst; 975 delayed_buf = buf; 976 delayed_next = blknr + 977 (blockend >> SECTOR_BITS); 978 } 979 } else { 980 if (previous_block_number != -1) { 981 /* spill */ 982 put_ext4((uint64_t) (delayed_start * 983 SECTOR_SIZE), delayed_buf, 984 (uint32_t) delayed_extent); 985 previous_block_number = -1; 986 } 987 memset(buf, 0, fs->blksz - skipfirst); 988 } 989 buf += fs->blksz - skipfirst; 990 } 991 if (previous_block_number != -1) { 992 /* spill */ 993 put_ext4((uint64_t) (delayed_start * SECTOR_SIZE), 994 delayed_buf, (uint32_t) delayed_extent); 995 previous_block_number = -1; 996 } 997 998 return len; 999 } 1000 1001 int ext4fs_write(const char *fname, unsigned char *buffer, 1002 unsigned long sizebytes) 1003 { 1004 int ret = 0; 1005 struct ext2_inode *file_inode = NULL; 1006 unsigned char *inode_buffer = NULL; 1007 int parent_inodeno; 1008 int inodeno; 1009 time_t timestamp = 0; 1010 1011 uint64_t bytes_reqd_for_file; 1012 unsigned int blks_reqd_for_file; 1013 unsigned int blocks_remaining; 1014 int existing_file_inodeno; 1015 char filename[256]; 1016 1017 char *temp_ptr = NULL; 1018 long int itable_blkno; 1019 long int parent_itable_blkno; 1020 long int blkoff; 1021 struct ext2_sblock *sblock = &(ext4fs_root->sblock); 1022 unsigned int inodes_per_block; 1023 unsigned int ibmap_idx; 1024 struct ext_filesystem *fs = get_fs(); 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 = bytes_reqd_for_file / fs->blksz; 1054 if (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->gd[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->gd[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