"Das U-Boot" Source Tree
at master 1090 lines 30 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2011 - 2012 Samsung Electronics 4 * EXT4 filesystem implementation in Uboot by 5 * Uma Shankar <uma.shankar@samsung.com> 6 * Manjunatha C Achar <a.manjunatha@samsung.com> 7 * 8 * ext4ls and ext4load : Based on ext2 ls and load support in Uboot. 9 * Ext4 read optimization taken from Open-Moko 10 * Qi bootloader 11 * 12 * (C) Copyright 2004 13 * esd gmbh <www.esd-electronics.com> 14 * Reinhard Arlt <reinhard.arlt@esd-electronics.com> 15 * 16 * based on code from grub2 fs/ext2.c and fs/fshelp.c by 17 * GRUB -- GRand Unified Bootloader 18 * Copyright (C) 2003, 2004 Free Software Foundation, Inc. 19 * 20 * ext4write : Based on generic ext4 protocol. 21 */ 22 23#include <blk.h> 24#include <log.h> 25#include <malloc.h> 26#include <memalign.h> 27#include <part.h> 28#include <linux/stat.h> 29#include <div64.h> 30#include "ext4_common.h" 31 32static inline void ext4fs_sb_free_inodes_inc(struct ext2_sblock *sb) 33{ 34 sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) + 1); 35} 36 37static inline void ext4fs_sb_free_blocks_inc(struct ext2_sblock *sb) 38{ 39 sb->free_blocks = cpu_to_le32(le32_to_cpu(sb->free_blocks) + 1); 40} 41 42static inline void ext4fs_bg_free_inodes_inc 43 (struct ext2_block_group *bg, const struct ext_filesystem *fs) 44{ 45 uint32_t free_inodes = le16_to_cpu(bg->free_inodes); 46 if (fs->gdsize == 64) 47 free_inodes += le16_to_cpu(bg->free_inodes_high) << 16; 48 free_inodes++; 49 50 bg->free_inodes = cpu_to_le16(free_inodes & 0xffff); 51 if (fs->gdsize == 64) 52 bg->free_inodes_high = cpu_to_le16(free_inodes >> 16); 53} 54 55static inline void ext4fs_bg_free_blocks_inc 56 (struct ext2_block_group *bg, const struct ext_filesystem *fs) 57{ 58 uint32_t free_blocks = le16_to_cpu(bg->free_blocks); 59 if (fs->gdsize == 64) 60 free_blocks += le16_to_cpu(bg->free_blocks_high) << 16; 61 free_blocks++; 62 63 bg->free_blocks = cpu_to_le16(free_blocks & 0xffff); 64 if (fs->gdsize == 64) 65 bg->free_blocks_high = cpu_to_le16(free_blocks >> 16); 66} 67 68static void ext4fs_update(void) 69{ 70 short i; 71 ext4fs_update_journal(); 72 struct ext_filesystem *fs = get_fs(); 73 struct ext2_block_group *bgd = NULL; 74 75 /* update super block */ 76 put_ext4((uint64_t)(SUPERBLOCK_SIZE), 77 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); 78 79 /* update block bitmaps */ 80 for (i = 0; i < fs->no_blkgrp; i++) { 81 bgd = ext4fs_get_group_descriptor(fs, i); 82 bgd->bg_checksum = cpu_to_le16(ext4fs_checksum_update(i)); 83 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs); 84 put_ext4(b_bitmap_blk * fs->blksz, 85 fs->blk_bmaps[i], fs->blksz); 86 } 87 88 /* update inode bitmaps */ 89 for (i = 0; i < fs->no_blkgrp; i++) { 90 bgd = ext4fs_get_group_descriptor(fs, i); 91 uint64_t i_bitmap_blk = ext4fs_bg_get_inode_id(bgd, fs); 92 put_ext4(i_bitmap_blk * fs->blksz, 93 fs->inode_bmaps[i], fs->blksz); 94 } 95 96 /* update the block group descriptor table */ 97 put_ext4((uint64_t)((uint64_t)fs->gdtable_blkno * (uint64_t)fs->blksz), 98 (struct ext2_block_group *)fs->gdtable, 99 (fs->blksz * fs->no_blk_pergdt)); 100 101 ext4fs_dump_metadata(); 102 103 gindex = 0; 104 gd_index = 0; 105} 106 107int ext4fs_get_bgdtable(void) 108{ 109 int status; 110 struct ext_filesystem *fs = get_fs(); 111 int gdsize_total = ROUND(fs->no_blkgrp * fs->gdsize, fs->blksz); 112 fs->no_blk_pergdt = gdsize_total / fs->blksz; 113 114 /* allocate memory for gdtable */ 115 fs->gdtable = zalloc(gdsize_total); 116 if (!fs->gdtable) 117 return -ENOMEM; 118 /* read the group descriptor table */ 119 status = ext4fs_devread((lbaint_t)fs->gdtable_blkno * fs->sect_perblk, 120 0, fs->blksz * fs->no_blk_pergdt, fs->gdtable); 121 if (status == 0) 122 goto fail; 123 124 if (ext4fs_log_gdt(fs->gdtable)) { 125 printf("Error in ext4fs_log_gdt\n"); 126 return -1; 127 } 128 129 return 0; 130fail: 131 free(fs->gdtable); 132 fs->gdtable = NULL; 133 134 return -1; 135} 136 137static void delete_single_indirect_block(struct ext2_inode *inode) 138{ 139 struct ext2_block_group *bgd = NULL; 140 static int prev_bg_bmap_idx = -1; 141 uint32_t blknr; 142 int remainder; 143 int bg_idx; 144 int status; 145 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group); 146 struct ext_filesystem *fs = get_fs(); 147 char *journal_buffer = zalloc(fs->blksz); 148 if (!journal_buffer) { 149 printf("No memory\n"); 150 return; 151 } 152 153 /* deleting the single indirect block associated with inode */ 154 if (inode->b.blocks.indir_block != 0) { 155 blknr = le32_to_cpu(inode->b.blocks.indir_block); 156 debug("SIPB releasing %u\n", blknr); 157 bg_idx = blknr / blk_per_grp; 158 if (fs->blksz == 1024) { 159 remainder = blknr % blk_per_grp; 160 if (!remainder) 161 bg_idx--; 162 } 163 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); 164 /* get block group descriptor table */ 165 bgd = ext4fs_get_group_descriptor(fs, bg_idx); 166 ext4fs_bg_free_blocks_inc(bgd, fs); 167 ext4fs_sb_free_blocks_inc(fs->sb); 168 /* journal backup */ 169 if (prev_bg_bmap_idx != bg_idx) { 170 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs); 171 status = ext4fs_devread( 172 b_bitmap_blk * fs->sect_perblk, 173 0, fs->blksz, journal_buffer); 174 if (status == 0) 175 goto fail; 176 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk)) 177 goto fail; 178 prev_bg_bmap_idx = bg_idx; 179 } 180 } 181fail: 182 free(journal_buffer); 183} 184 185static void delete_double_indirect_block(struct ext2_inode *inode) 186{ 187 int i; 188 short status; 189 static int prev_bg_bmap_idx = -1; 190 uint32_t blknr; 191 int remainder; 192 int bg_idx; 193 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group); 194 __le32 *di_buffer = NULL; 195 void *dib_start_addr = NULL; 196 struct ext2_block_group *bgd = NULL; 197 struct ext_filesystem *fs = get_fs(); 198 char *journal_buffer = zalloc(fs->blksz); 199 if (!journal_buffer) { 200 printf("No memory\n"); 201 return; 202 } 203 204 if (inode->b.blocks.double_indir_block != 0) { 205 di_buffer = zalloc(fs->blksz); 206 if (!di_buffer) { 207 printf("No memory\n"); 208 return; 209 } 210 dib_start_addr = di_buffer; 211 blknr = le32_to_cpu(inode->b.blocks.double_indir_block); 212 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, 213 fs->blksz, (char *)di_buffer); 214 for (i = 0; i < fs->blksz / sizeof(int); i++) { 215 if (*di_buffer == 0) 216 break; 217 218 debug("DICB releasing %u\n", *di_buffer); 219 bg_idx = le32_to_cpu(*di_buffer) / blk_per_grp; 220 if (fs->blksz == 1024) { 221 remainder = le32_to_cpu(*di_buffer) % blk_per_grp; 222 if (!remainder) 223 bg_idx--; 224 } 225 /* get block group descriptor table */ 226 bgd = ext4fs_get_group_descriptor(fs, bg_idx); 227 ext4fs_reset_block_bmap(le32_to_cpu(*di_buffer), 228 fs->blk_bmaps[bg_idx], bg_idx); 229 di_buffer++; 230 ext4fs_bg_free_blocks_inc(bgd, fs); 231 ext4fs_sb_free_blocks_inc(fs->sb); 232 /* journal backup */ 233 if (prev_bg_bmap_idx != bg_idx) { 234 uint64_t b_bitmap_blk = 235 ext4fs_bg_get_block_id(bgd, fs); 236 status = ext4fs_devread(b_bitmap_blk 237 * fs->sect_perblk, 0, 238 fs->blksz, 239 journal_buffer); 240 if (status == 0) 241 goto fail; 242 243 if (ext4fs_log_journal(journal_buffer, 244 b_bitmap_blk)) 245 goto fail; 246 prev_bg_bmap_idx = bg_idx; 247 } 248 } 249 250 /* removing the parent double indirect block */ 251 blknr = le32_to_cpu(inode->b.blocks.double_indir_block); 252 bg_idx = blknr / blk_per_grp; 253 if (fs->blksz == 1024) { 254 remainder = blknr % blk_per_grp; 255 if (!remainder) 256 bg_idx--; 257 } 258 /* get block group descriptor table */ 259 bgd = ext4fs_get_group_descriptor(fs, bg_idx); 260 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); 261 ext4fs_bg_free_blocks_inc(bgd, fs); 262 ext4fs_sb_free_blocks_inc(fs->sb); 263 /* journal backup */ 264 if (prev_bg_bmap_idx != bg_idx) { 265 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs); 266 status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk, 267 0, fs->blksz, journal_buffer); 268 if (status == 0) 269 goto fail; 270 271 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk)) 272 goto fail; 273 prev_bg_bmap_idx = bg_idx; 274 } 275 debug("DIPB releasing %d\n", blknr); 276 } 277fail: 278 free(dib_start_addr); 279 free(journal_buffer); 280} 281 282static void delete_triple_indirect_block(struct ext2_inode *inode) 283{ 284 int i, j; 285 short status; 286 static int prev_bg_bmap_idx = -1; 287 uint32_t blknr; 288 int remainder; 289 int bg_idx; 290 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group); 291 __le32 *tigp_buffer = NULL; 292 void *tib_start_addr = NULL; 293 __le32 *tip_buffer = NULL; 294 void *tipb_start_addr = NULL; 295 struct ext2_block_group *bgd = NULL; 296 struct ext_filesystem *fs = get_fs(); 297 char *journal_buffer = zalloc(fs->blksz); 298 if (!journal_buffer) { 299 printf("No memory\n"); 300 return; 301 } 302 303 if (inode->b.blocks.triple_indir_block != 0) { 304 tigp_buffer = zalloc(fs->blksz); 305 if (!tigp_buffer) { 306 printf("No memory\n"); 307 return; 308 } 309 tib_start_addr = tigp_buffer; 310 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block); 311 status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, 312 fs->blksz, (char *)tigp_buffer); 313 for (i = 0; i < fs->blksz / sizeof(int); i++) { 314 if (*tigp_buffer == 0) 315 break; 316 debug("tigp buffer releasing %u\n", *tigp_buffer); 317 318 tip_buffer = zalloc(fs->blksz); 319 if (!tip_buffer) 320 goto fail; 321 tipb_start_addr = tip_buffer; 322 status = ext4fs_devread((lbaint_t)le32_to_cpu(*tigp_buffer) * 323 fs->sect_perblk, 0, fs->blksz, 324 (char *)tip_buffer); 325 for (j = 0; j < fs->blksz / sizeof(int); j++) { 326 if (le32_to_cpu(*tip_buffer) == 0) 327 break; 328 bg_idx = le32_to_cpu(*tip_buffer) / blk_per_grp; 329 if (fs->blksz == 1024) { 330 remainder = le32_to_cpu(*tip_buffer) % blk_per_grp; 331 if (!remainder) 332 bg_idx--; 333 } 334 335 ext4fs_reset_block_bmap(le32_to_cpu(*tip_buffer), 336 fs->blk_bmaps[bg_idx], 337 bg_idx); 338 339 tip_buffer++; 340 /* get block group descriptor table */ 341 bgd = ext4fs_get_group_descriptor(fs, bg_idx); 342 ext4fs_bg_free_blocks_inc(bgd, fs); 343 ext4fs_sb_free_blocks_inc(fs->sb); 344 /* journal backup */ 345 if (prev_bg_bmap_idx != bg_idx) { 346 uint64_t b_bitmap_blk = 347 ext4fs_bg_get_block_id(bgd, fs); 348 status = 349 ext4fs_devread( 350 b_bitmap_blk * 351 fs->sect_perblk, 0, 352 fs->blksz, 353 journal_buffer); 354 if (status == 0) 355 goto fail; 356 357 if (ext4fs_log_journal(journal_buffer, 358 b_bitmap_blk)) 359 goto fail; 360 prev_bg_bmap_idx = bg_idx; 361 } 362 } 363 free(tipb_start_addr); 364 tipb_start_addr = NULL; 365 366 /* 367 * removing the grand parent blocks 368 * which is connected to inode 369 */ 370 bg_idx = le32_to_cpu(*tigp_buffer) / blk_per_grp; 371 if (fs->blksz == 1024) { 372 remainder = le32_to_cpu(*tigp_buffer) % blk_per_grp; 373 if (!remainder) 374 bg_idx--; 375 } 376 ext4fs_reset_block_bmap(le32_to_cpu(*tigp_buffer), 377 fs->blk_bmaps[bg_idx], bg_idx); 378 379 tigp_buffer++; 380 /* get block group descriptor table */ 381 bgd = ext4fs_get_group_descriptor(fs, bg_idx); 382 ext4fs_bg_free_blocks_inc(bgd, fs); 383 ext4fs_sb_free_blocks_inc(fs->sb); 384 /* journal backup */ 385 if (prev_bg_bmap_idx != bg_idx) { 386 uint64_t b_bitmap_blk = 387 ext4fs_bg_get_block_id(bgd, fs); 388 memset(journal_buffer, '\0', fs->blksz); 389 status = ext4fs_devread(b_bitmap_blk * 390 fs->sect_perblk, 0, 391 fs->blksz, 392 journal_buffer); 393 if (status == 0) 394 goto fail; 395 396 if (ext4fs_log_journal(journal_buffer, 397 b_bitmap_blk)) 398 goto fail; 399 prev_bg_bmap_idx = bg_idx; 400 } 401 } 402 403 /* removing the grand parent triple indirect block */ 404 blknr = le32_to_cpu(inode->b.blocks.triple_indir_block); 405 bg_idx = blknr / blk_per_grp; 406 if (fs->blksz == 1024) { 407 remainder = blknr % blk_per_grp; 408 if (!remainder) 409 bg_idx--; 410 } 411 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], bg_idx); 412 /* get block group descriptor table */ 413 bgd = ext4fs_get_group_descriptor(fs, bg_idx); 414 ext4fs_bg_free_blocks_inc(bgd, fs); 415 ext4fs_sb_free_blocks_inc(fs->sb); 416 /* journal backup */ 417 if (prev_bg_bmap_idx != bg_idx) { 418 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs); 419 status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk, 420 0, fs->blksz, journal_buffer); 421 if (status == 0) 422 goto fail; 423 424 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk)) 425 goto fail; 426 prev_bg_bmap_idx = bg_idx; 427 } 428 debug("tigp buffer itself releasing %d\n", blknr); 429 } 430fail: 431 free(tib_start_addr); 432 free(tipb_start_addr); 433 free(journal_buffer); 434} 435 436static int ext4fs_delete_file(int inodeno) 437{ 438 struct ext2_inode inode; 439 short status; 440 int i; 441 int remainder; 442 long int blknr; 443 int bg_idx; 444 int ibmap_idx; 445 char *read_buffer = NULL; 446 char *start_block_address = NULL; 447 uint32_t no_blocks; 448 449 static int prev_bg_bmap_idx = -1; 450 unsigned int inodes_per_block; 451 uint32_t blkno; 452 unsigned int blkoff; 453 uint32_t blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group); 454 uint32_t inode_per_grp = le32_to_cpu(ext4fs_root->sblock.inodes_per_group); 455 struct ext2_inode *inode_buffer = NULL; 456 struct ext2_block_group *bgd = NULL; 457 struct ext_filesystem *fs = get_fs(); 458 char *journal_buffer = zalloc(fs->blksz); 459 if (!journal_buffer) 460 return -ENOMEM; 461 status = ext4fs_read_inode(ext4fs_root, inodeno, &inode); 462 if (status == 0) 463 goto fail; 464 465 /* read the block no allocated to a file */ 466 no_blocks = le32_to_cpu(inode.size) / fs->blksz; 467 if (le32_to_cpu(inode.size) % fs->blksz) 468 no_blocks++; 469 470 /* 471 * special case for symlinks whose target are small enough that 472 *it fits in struct ext2_inode.b.symlink: no block had been allocated 473 */ 474 if (S_ISLNK(le16_to_cpu(inode.mode)) && 475 le32_to_cpu(inode.size) <= sizeof(inode.b.symlink)) { 476 no_blocks = 0; 477 } 478 479 if (le32_to_cpu(inode.flags) & EXT4_EXTENTS_FL) { 480 /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */ 481 struct ext4_extent_header *eh = 482 (struct ext4_extent_header *) 483 inode.b.blocks.dir_blocks; 484 debug("del: dep=%d entries=%d\n", eh->eh_depth, eh->eh_entries); 485 } else { 486 delete_single_indirect_block(&inode); 487 delete_double_indirect_block(&inode); 488 delete_triple_indirect_block(&inode); 489 } 490 491 /* release data blocks */ 492 for (i = 0; i < no_blocks; i++) { 493 blknr = read_allocated_block(&inode, i, NULL); 494 if (blknr == 0) 495 continue; 496 if (blknr < 0) 497 goto fail; 498 bg_idx = blknr / blk_per_grp; 499 if (fs->blksz == 1024) { 500 remainder = blknr % blk_per_grp; 501 if (!remainder) 502 bg_idx--; 503 } 504 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], 505 bg_idx); 506 debug("EXT4 Block releasing %ld: %d\n", blknr, bg_idx); 507 508 /* get block group descriptor table */ 509 bgd = ext4fs_get_group_descriptor(fs, bg_idx); 510 ext4fs_bg_free_blocks_inc(bgd, fs); 511 ext4fs_sb_free_blocks_inc(fs->sb); 512 /* journal backup */ 513 if (prev_bg_bmap_idx != bg_idx) { 514 uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs); 515 status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk, 516 0, fs->blksz, 517 journal_buffer); 518 if (status == 0) 519 goto fail; 520 if (ext4fs_log_journal(journal_buffer, b_bitmap_blk)) 521 goto fail; 522 prev_bg_bmap_idx = bg_idx; 523 } 524 } 525 526 /* release inode */ 527 /* from the inode no to blockno */ 528 inodes_per_block = fs->blksz / fs->inodesz; 529 ibmap_idx = inodeno / inode_per_grp; 530 531 /* get the block no */ 532 inodeno--; 533 /* get block group descriptor table */ 534 bgd = ext4fs_get_group_descriptor(fs, ibmap_idx); 535 blkno = ext4fs_bg_get_inode_table_id(bgd, fs) + 536 (inodeno % inode_per_grp) / inodes_per_block; 537 538 /* get the offset of the inode */ 539 blkoff = ((inodeno) % inodes_per_block) * fs->inodesz; 540 541 /* read the block no containing the inode */ 542 read_buffer = zalloc(fs->blksz); 543 if (!read_buffer) 544 goto fail; 545 start_block_address = read_buffer; 546 status = ext4fs_devread((lbaint_t)blkno * fs->sect_perblk, 547 0, fs->blksz, read_buffer); 548 if (status == 0) 549 goto fail; 550 551 if (ext4fs_log_journal(read_buffer, blkno)) 552 goto fail; 553 554 read_buffer = read_buffer + blkoff; 555 inode_buffer = (struct ext2_inode *)read_buffer; 556 memset(inode_buffer, '\0', fs->inodesz); 557 558 /* write the inode to original position in inode table */ 559 if (ext4fs_put_metadata(start_block_address, blkno)) 560 goto fail; 561 562 /* update the respective inode bitmaps */ 563 inodeno++; 564 ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx); 565 ext4fs_bg_free_inodes_inc(bgd, fs); 566 ext4fs_sb_free_inodes_inc(fs->sb); 567 /* journal backup */ 568 memset(journal_buffer, '\0', fs->blksz); 569 status = ext4fs_devread(ext4fs_bg_get_inode_id(bgd, fs) * 570 fs->sect_perblk, 0, fs->blksz, journal_buffer); 571 if (status == 0) 572 goto fail; 573 if (ext4fs_log_journal(journal_buffer, ext4fs_bg_get_inode_id(bgd, fs))) 574 goto fail; 575 576 ext4fs_update(); 577 ext4fs_deinit(); 578 ext4fs_reinit_global(); 579 580 if (ext4fs_init() != 0) { 581 printf("error in File System init\n"); 582 goto fail; 583 } 584 585 free(start_block_address); 586 free(journal_buffer); 587 588 return 0; 589fail: 590 free(start_block_address); 591 free(journal_buffer); 592 593 return -1; 594} 595 596int ext4fs_init(void) 597{ 598 short status; 599 int i; 600 uint32_t real_free_blocks = 0; 601 struct ext_filesystem *fs = get_fs(); 602 603 /* populate fs */ 604 fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root); 605 fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz; 606 607 /* get the superblock */ 608 fs->sb = zalloc(SUPERBLOCK_SIZE); 609 if (!fs->sb) 610 return -ENOMEM; 611 if (!ext4_read_superblock((char *)fs->sb)) 612 goto fail; 613 614 /* init journal */ 615 if (ext4fs_init_journal()) 616 goto fail; 617 618 /* get total no of blockgroups */ 619 fs->no_blkgrp = (uint32_t)ext4fs_div_roundup( 620 le32_to_cpu(ext4fs_root->sblock.total_blocks) 621 - le32_to_cpu(ext4fs_root->sblock.first_data_block), 622 le32_to_cpu(ext4fs_root->sblock.blocks_per_group)); 623 624 /* get the block group descriptor table */ 625 fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1); 626 if (ext4fs_get_bgdtable() == -1) { 627 printf("Error in getting the block group descriptor table\n"); 628 goto fail; 629 } 630 631 /* load all the available bitmap block of the partition */ 632 fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *)); 633 if (!fs->blk_bmaps) 634 goto fail; 635 for (i = 0; i < fs->no_blkgrp; i++) { 636 fs->blk_bmaps[i] = zalloc(fs->blksz); 637 if (!fs->blk_bmaps[i]) 638 goto fail; 639 } 640 641 for (i = 0; i < fs->no_blkgrp; i++) { 642 struct ext2_block_group *bgd = 643 ext4fs_get_group_descriptor(fs, i); 644 status = ext4fs_devread(ext4fs_bg_get_block_id(bgd, fs) * 645 fs->sect_perblk, 0, 646 fs->blksz, (char *)fs->blk_bmaps[i]); 647 if (status == 0) 648 goto fail; 649 } 650 651 /* load all the available inode bitmap of the partition */ 652 fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *)); 653 if (!fs->inode_bmaps) 654 goto fail; 655 for (i = 0; i < fs->no_blkgrp; i++) { 656 fs->inode_bmaps[i] = zalloc(fs->blksz); 657 if (!fs->inode_bmaps[i]) 658 goto fail; 659 } 660 661 for (i = 0; i < fs->no_blkgrp; i++) { 662 struct ext2_block_group *bgd = 663 ext4fs_get_group_descriptor(fs, i); 664 status = ext4fs_devread(ext4fs_bg_get_inode_id(bgd, fs) * 665 fs->sect_perblk, 666 0, fs->blksz, 667 (char *)fs->inode_bmaps[i]); 668 if (status == 0) 669 goto fail; 670 } 671 672 /* 673 * check filesystem consistency with free blocks of file system 674 * some time we observed that superblock freeblocks does not match 675 * with the blockgroups freeblocks when improper 676 * reboot of a linux kernel 677 */ 678 for (i = 0; i < fs->no_blkgrp; i++) { 679 struct ext2_block_group *bgd = 680 ext4fs_get_group_descriptor(fs, i); 681 real_free_blocks = real_free_blocks + 682 ext4fs_bg_get_free_blocks(bgd, fs); 683 } 684 if (real_free_blocks != ext4fs_sb_get_free_blocks(fs->sb)) 685 ext4fs_sb_set_free_blocks(fs->sb, real_free_blocks); 686 687 return 0; 688fail: 689 ext4fs_deinit(); 690 691 return -1; 692} 693 694void ext4fs_deinit(void) 695{ 696 int i; 697 struct ext2_inode inode_journal; 698 struct journal_superblock_t *jsb; 699 uint32_t blknr; 700 struct ext_filesystem *fs = get_fs(); 701 uint32_t new_feature_incompat; 702 703 /* free journal */ 704 char *temp_buff = zalloc(fs->blksz); 705 if (temp_buff) { 706 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, 707 &inode_journal); 708 blknr = read_allocated_block(&inode_journal, 709 EXT2_JOURNAL_SUPERBLOCK, NULL); 710 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, 711 temp_buff); 712 jsb = (struct journal_superblock_t *)temp_buff; 713 jsb->s_start = 0; 714 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), 715 (struct journal_superblock_t *)temp_buff, fs->blksz); 716 free(temp_buff); 717 } 718 ext4fs_free_journal(); 719 720 /* get the superblock */ 721 ext4_read_superblock((char *)fs->sb); 722 new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat); 723 new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; 724 fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat); 725 put_ext4((uint64_t)(SUPERBLOCK_SIZE), 726 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); 727 free(fs->sb); 728 fs->sb = NULL; 729 730 if (fs->blk_bmaps) { 731 for (i = 0; i < fs->no_blkgrp; i++) { 732 free(fs->blk_bmaps[i]); 733 fs->blk_bmaps[i] = NULL; 734 } 735 free(fs->blk_bmaps); 736 fs->blk_bmaps = NULL; 737 } 738 739 if (fs->inode_bmaps) { 740 for (i = 0; i < fs->no_blkgrp; i++) { 741 free(fs->inode_bmaps[i]); 742 fs->inode_bmaps[i] = NULL; 743 } 744 free(fs->inode_bmaps); 745 fs->inode_bmaps = NULL; 746 } 747 748 free(fs->gdtable); 749 fs->gdtable = NULL; 750 /* 751 * reinitiliazed the global inode and 752 * block bitmap first execution check variables 753 */ 754 fs->first_pass_ibmap = 0; 755 fs->first_pass_bbmap = 0; 756 fs->curr_inode_no = 0; 757 fs->curr_blkno = 0; 758} 759 760/* 761 * Write data to filesystem blocks. Uses same optimization for 762 * contigous sectors as ext4fs_read_file 763 */ 764static int ext4fs_write_file(struct ext2_inode *file_inode, 765 int pos, unsigned int len, const char *buf) 766{ 767 int i; 768 int blockcnt; 769 uint32_t filesize = le32_to_cpu(file_inode->size); 770 struct ext_filesystem *fs = get_fs(); 771 int log2blksz = fs->dev_desc->log2blksz; 772 int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz; 773 int previous_block_number = -1; 774 int delayed_start = 0; 775 int delayed_extent = 0; 776 int delayed_next = 0; 777 const char *delayed_buf = NULL; 778 779 /* Adjust len so it we can't read past the end of the file. */ 780 if (len > filesize) 781 len = filesize; 782 783 blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz; 784 785 for (i = pos / fs->blksz; i < blockcnt; i++) { 786 long int blknr; 787 int blockend = fs->blksz; 788 int skipfirst = 0; 789 blknr = read_allocated_block(file_inode, i, NULL); 790 if (blknr <= 0) 791 return -1; 792 793 blknr = blknr << log2_fs_blocksize; 794 795 if (blknr) { 796 if (previous_block_number != -1) { 797 if (delayed_next == blknr) { 798 delayed_extent += blockend; 799 delayed_next += blockend >> log2blksz; 800 } else { /* spill */ 801 put_ext4((uint64_t) 802 ((uint64_t)delayed_start << log2blksz), 803 delayed_buf, 804 (uint32_t) delayed_extent); 805 previous_block_number = blknr; 806 delayed_start = blknr; 807 delayed_extent = blockend; 808 delayed_buf = buf; 809 delayed_next = blknr + 810 (blockend >> log2blksz); 811 } 812 } else { 813 previous_block_number = blknr; 814 delayed_start = blknr; 815 delayed_extent = blockend; 816 delayed_buf = buf; 817 delayed_next = blknr + 818 (blockend >> log2blksz); 819 } 820 } else { 821 if (previous_block_number != -1) { 822 /* spill */ 823 put_ext4((uint64_t) ((uint64_t)delayed_start << 824 log2blksz), 825 delayed_buf, 826 (uint32_t) delayed_extent); 827 previous_block_number = -1; 828 } 829 } 830 buf += fs->blksz - skipfirst; 831 } 832 if (previous_block_number != -1) { 833 /* spill */ 834 put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz), 835 delayed_buf, (uint32_t) delayed_extent); 836 previous_block_number = -1; 837 } 838 839 return len; 840} 841 842int ext4fs_write(const char *fname, const char *buffer, 843 unsigned long sizebytes, int type) 844{ 845 int ret = 0; 846 struct ext2_inode *file_inode = NULL; 847 struct ext2_inode *existing_file_inode = NULL; 848 unsigned char *inode_buffer = NULL; 849 int parent_inodeno; 850 int inodeno; 851 time_t timestamp = 0; 852 853 uint64_t bytes_reqd_for_file; 854 unsigned int blks_reqd_for_file; 855 unsigned int blocks_remaining; 856 int existing_file_inodeno; 857 char *temp_ptr = NULL; 858 long int itable_blkno; 859 long int parent_itable_blkno; 860 long int blkoff; 861 struct ext2_sblock *sblock = &(ext4fs_root->sblock); 862 unsigned int inodes_per_block; 863 unsigned int ibmap_idx; 864 struct ext2_block_group *bgd = NULL; 865 struct ext_filesystem *fs = get_fs(); 866 ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256); 867 bool store_link_in_inode = false; 868 memset(filename, 0x00, 256); 869 int missing_feat; 870 871 if (type != FILETYPE_REG && type != FILETYPE_SYMLINK) 872 return -1; 873 874 g_parent_inode = zalloc(fs->inodesz); 875 if (!g_parent_inode) 876 goto fail; 877 878 if (ext4fs_init() != 0) { 879 printf("error in File System init\n"); 880 return -1; 881 } 882 883 missing_feat = le32_to_cpu(fs->sb->feature_incompat) & ~EXT4_FEATURE_INCOMPAT_SUPP; 884 if (missing_feat) { 885 log_err("Unsupported features found %08x, not writing.\n", missing_feat); 886 return -1; 887 } 888 889 missing_feat = le32_to_cpu(fs->sb->feature_ro_compat) & ~EXT4_FEATURE_RO_COMPAT_SUPP; 890 if (missing_feat) { 891 log_err("Unsupported RO compat features found %08x, not writing.\n", missing_feat); 892 return -1; 893 } 894 895 inodes_per_block = fs->blksz / fs->inodesz; 896 parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE); 897 if (parent_inodeno == -1) 898 goto fail; 899 if (ext4fs_iget(parent_inodeno, g_parent_inode)) 900 goto fail; 901 /* do not mess up a directory using hash trees */ 902 if (le32_to_cpu(g_parent_inode->flags) & EXT4_INDEX_FL) { 903 printf("hash tree directory\n"); 904 goto fail; 905 } 906 /* check if the filename is already present in root */ 907 existing_file_inodeno = ext4fs_filename_unlink(filename); 908 if (existing_file_inodeno != -1) { 909 existing_file_inode = (struct ext2_inode *)zalloc(fs->inodesz); 910 if (!existing_file_inode) 911 goto fail; 912 ret = ext4fs_iget(existing_file_inodeno, existing_file_inode); 913 if (ret) { 914 free(existing_file_inode); 915 goto fail; 916 } 917 918 ret = ext4fs_delete_file(existing_file_inodeno); 919 fs->first_pass_bbmap = 0; 920 fs->curr_blkno = 0; 921 922 fs->first_pass_ibmap = 0; 923 fs->curr_inode_no = 0; 924 if (ret) 925 goto fail; 926 } 927 928 /* calculate how many blocks required */ 929 if (type == FILETYPE_SYMLINK && 930 sizebytes <= sizeof(file_inode->b.symlink)) { 931 store_link_in_inode = true; 932 bytes_reqd_for_file = 0; 933 } else { 934 bytes_reqd_for_file = sizebytes; 935 } 936 937 blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz); 938 if (do_div(bytes_reqd_for_file, fs->blksz) != 0) { 939 blks_reqd_for_file++; 940 debug("total bytes for a file %u\n", blks_reqd_for_file); 941 } 942 blocks_remaining = blks_reqd_for_file; 943 /* test for available space in partition */ 944 if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) { 945 printf("Not enough space on partition !!!\n"); 946 goto fail; 947 } 948 949 inodeno = ext4fs_update_parent_dentry(filename, type); 950 if (inodeno == -1) 951 goto fail; 952 /* prepare file inode */ 953 inode_buffer = zalloc(fs->inodesz); 954 if (!inode_buffer) 955 goto fail; 956 file_inode = (struct ext2_inode *)inode_buffer; 957 file_inode->size = cpu_to_le32(sizebytes); 958 if (type == FILETYPE_SYMLINK) { 959 file_inode->mode = cpu_to_le16(S_IFLNK | S_IRWXU | S_IRWXG | 960 S_IRWXO); 961 if (store_link_in_inode) { 962 strncpy(file_inode->b.symlink, buffer, sizebytes); 963 sizebytes = 0; 964 } 965 } else { 966 if (existing_file_inode) { 967 file_inode->mode = existing_file_inode->mode; 968 } else { 969 file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | S_IRGRP | 970 S_IROTH | S_IXGRP | S_IXOTH); 971 } 972 } 973 if (existing_file_inode) 974 free(existing_file_inode); 975 /* ToDo: Update correct time */ 976 file_inode->mtime = cpu_to_le32(timestamp); 977 file_inode->atime = cpu_to_le32(timestamp); 978 file_inode->ctime = cpu_to_le32(timestamp); 979 file_inode->nlinks = cpu_to_le16(1); 980 981 /* Allocate data blocks */ 982 ext4fs_allocate_blocks(file_inode, blocks_remaining, 983 &blks_reqd_for_file); 984 file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >> 985 LOG2_SECTOR_SIZE); 986 987 temp_ptr = zalloc(fs->blksz); 988 if (!temp_ptr) 989 goto fail; 990 ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group); 991 inodeno--; 992 bgd = ext4fs_get_group_descriptor(fs, ibmap_idx); 993 itable_blkno = ext4fs_bg_get_inode_table_id(bgd, fs) + 994 (inodeno % le32_to_cpu(sblock->inodes_per_group)) / 995 inodes_per_block; 996 blkoff = (inodeno % inodes_per_block) * fs->inodesz; 997 ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz, 998 temp_ptr); 999 if (ext4fs_log_journal(temp_ptr, itable_blkno)) 1000 goto fail; 1001 1002 memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz); 1003 if (ext4fs_put_metadata(temp_ptr, itable_blkno)) 1004 goto fail; 1005 /* copy the file content into data blocks */ 1006 if (ext4fs_write_file(file_inode, 0, sizebytes, buffer) == -1) { 1007 printf("Error in copying content\n"); 1008 /* FIXME: Deallocate data blocks */ 1009 goto fail; 1010 } 1011 ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group); 1012 parent_inodeno--; 1013 bgd = ext4fs_get_group_descriptor(fs, ibmap_idx); 1014 parent_itable_blkno = ext4fs_bg_get_inode_table_id(bgd, fs) + 1015 (parent_inodeno % 1016 le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; 1017 blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz; 1018 if (parent_itable_blkno != itable_blkno) { 1019 memset(temp_ptr, '\0', fs->blksz); 1020 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk, 1021 0, fs->blksz, temp_ptr); 1022 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno)) 1023 goto fail; 1024 1025 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz); 1026 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno)) 1027 goto fail; 1028 } else { 1029 /* 1030 * If parent and child fall in same inode table block 1031 * both should be kept in 1 buffer 1032 */ 1033 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz); 1034 gd_index--; 1035 if (ext4fs_put_metadata(temp_ptr, itable_blkno)) 1036 goto fail; 1037 } 1038 ext4fs_update(); 1039 ext4fs_deinit(); 1040 1041 fs->first_pass_bbmap = 0; 1042 fs->curr_blkno = 0; 1043 fs->first_pass_ibmap = 0; 1044 fs->curr_inode_no = 0; 1045 free(inode_buffer); 1046 free(g_parent_inode); 1047 free(temp_ptr); 1048 g_parent_inode = NULL; 1049 1050 return 0; 1051fail: 1052 ext4fs_deinit(); 1053 free(inode_buffer); 1054 free(g_parent_inode); 1055 free(temp_ptr); 1056 g_parent_inode = NULL; 1057 1058 return -1; 1059} 1060 1061int ext4_write_file(const char *filename, void *buf, loff_t offset, 1062 loff_t len, loff_t *actwrite) 1063{ 1064 int ret; 1065 1066 if (offset != 0) { 1067 printf("** Cannot support non-zero offset **\n"); 1068 return -1; 1069 } 1070 1071 ret = ext4fs_write(filename, buf, len, FILETYPE_REG); 1072 if (ret) { 1073 printf("** Error ext4fs_write() **\n"); 1074 goto fail; 1075 } 1076 1077 *actwrite = len; 1078 1079 return 0; 1080 1081fail: 1082 *actwrite = 0; 1083 1084 return -1; 1085} 1086 1087int ext4fs_create_link(const char *target, const char *fname) 1088{ 1089 return ext4fs_write(fname, target, strlen(target), FILETYPE_SYMLINK); 1090}