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 block_dev_desc_t *ext4_dev_desc; 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_CMD_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->gd[i].bg_checksum = ext4fs_checksum_update(i); 214 put_ext4((uint64_t)(fs->gd[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->gd[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 *gd = 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 gd = (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 gd[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(gd[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, gd[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 *gd = 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 gd = (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 gd[bg_idx].free_blocks++; 367 fs->sb->free_blocks++; 368 /* journal backup */ 369 if (prev_bg_bmap_idx != bg_idx) { 370 status = ext4fs_devread(gd[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 gd[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 gd[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(gd[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 gd[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 *gd = 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 gd = (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 gd[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(gd[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 gd[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 gd[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(gd[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 gd[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 gd[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(gd[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 gd[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 *gd = 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 gd = (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 gd[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(gd[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 gd[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 gd[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(gd[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 gd[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(gd[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 gd[ibmap_idx].free_inodes++; 736 fs->sb->free_inodes++; 737 /* journal backup */ 738 memset(journal_buffer, '\0', fs->blksz); 739 status = ext4fs_devread(gd[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, gd[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->gd = (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->gd[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->gd[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->gd[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->gd = 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->gd[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->gd[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