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