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->inodesz = INODE_SIZE_FILESYSTEM(ext4fs_root); 613 fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz; 614 615 /* get the superblock */ 616 fs->sb = zalloc(SUPERBLOCK_SIZE); 617 if (!fs->sb) 618 return -ENOMEM; 619 if (!ext4_read_superblock((char *)fs->sb)) 620 goto fail; 621 622 /* init journal */ 623 if (ext4fs_init_journal()) 624 goto fail; 625 626 /* get total no of blockgroups */ 627 fs->no_blkgrp = (uint32_t)ext4fs_div_roundup( 628 le32_to_cpu(ext4fs_root->sblock.total_blocks) 629 - le32_to_cpu(ext4fs_root->sblock.first_data_block), 630 le32_to_cpu(ext4fs_root->sblock.blocks_per_group)); 631 632 /* get the block group descriptor table */ 633 fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1); 634 if (ext4fs_get_bgdtable() == -1) { 635 printf("Error in getting the block group descriptor table\n"); 636 goto fail; 637 } 638 fs->bgd = (struct ext2_block_group *)fs->gdtable; 639 640 /* load all the available bitmap block of the partition */ 641 fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *)); 642 if (!fs->blk_bmaps) 643 goto fail; 644 for (i = 0; i < fs->no_blkgrp; i++) { 645 fs->blk_bmaps[i] = zalloc(fs->blksz); 646 if (!fs->blk_bmaps[i]) 647 goto fail; 648 } 649 650 for (i = 0; i < fs->no_blkgrp; i++) { 651 status = 652 ext4fs_devread( 653 (lbaint_t)le32_to_cpu(fs->bgd[i].block_id) * 654 fs->sect_perblk, 0, 655 fs->blksz, (char *)fs->blk_bmaps[i]); 656 if (status == 0) 657 goto fail; 658 } 659 660 /* load all the available inode bitmap of the partition */ 661 fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *)); 662 if (!fs->inode_bmaps) 663 goto fail; 664 for (i = 0; i < fs->no_blkgrp; i++) { 665 fs->inode_bmaps[i] = zalloc(fs->blksz); 666 if (!fs->inode_bmaps[i]) 667 goto fail; 668 } 669 670 for (i = 0; i < fs->no_blkgrp; i++) { 671 status = ext4fs_devread( 672 (lbaint_t)le32_to_cpu(fs->bgd[i].inode_id) * 673 fs->sect_perblk, 674 0, fs->blksz, 675 (char *)fs->inode_bmaps[i]); 676 if (status == 0) 677 goto fail; 678 } 679 680 /* 681 * check filesystem consistency with free blocks of file system 682 * some time we observed that superblock freeblocks does not match 683 * with the blockgroups freeblocks when improper 684 * reboot of a linux kernel 685 */ 686 for (i = 0; i < fs->no_blkgrp; i++) 687 real_free_blocks = real_free_blocks + le16_to_cpu(fs->bgd[i].free_blocks); 688 if (real_free_blocks != le32_to_cpu(fs->sb->free_blocks)) 689 fs->sb->free_blocks = cpu_to_le32(real_free_blocks); 690 691 return 0; 692 fail: 693 ext4fs_deinit(); 694 695 return -1; 696 } 697 698 void ext4fs_deinit(void) 699 { 700 int i; 701 struct ext2_inode inode_journal; 702 struct journal_superblock_t *jsb; 703 uint32_t blknr; 704 struct ext_filesystem *fs = get_fs(); 705 uint32_t new_feature_incompat; 706 707 /* free journal */ 708 char *temp_buff = zalloc(fs->blksz); 709 if (temp_buff) { 710 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, 711 &inode_journal); 712 blknr = read_allocated_block(&inode_journal, 713 EXT2_JOURNAL_SUPERBLOCK); 714 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, 715 temp_buff); 716 jsb = (struct journal_superblock_t *)temp_buff; 717 jsb->s_start = 0; 718 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), 719 (struct journal_superblock_t *)temp_buff, fs->blksz); 720 free(temp_buff); 721 } 722 ext4fs_free_journal(); 723 724 /* get the superblock */ 725 ext4_read_superblock((char *)fs->sb); 726 new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat); 727 new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; 728 fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat); 729 put_ext4((uint64_t)(SUPERBLOCK_SIZE), 730 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); 731 free(fs->sb); 732 fs->sb = NULL; 733 734 if (fs->blk_bmaps) { 735 for (i = 0; i < fs->no_blkgrp; i++) { 736 free(fs->blk_bmaps[i]); 737 fs->blk_bmaps[i] = NULL; 738 } 739 free(fs->blk_bmaps); 740 fs->blk_bmaps = NULL; 741 } 742 743 if (fs->inode_bmaps) { 744 for (i = 0; i < fs->no_blkgrp; i++) { 745 free(fs->inode_bmaps[i]); 746 fs->inode_bmaps[i] = NULL; 747 } 748 free(fs->inode_bmaps); 749 fs->inode_bmaps = NULL; 750 } 751 752 753 free(fs->gdtable); 754 fs->gdtable = NULL; 755 fs->bgd = NULL; 756 /* 757 * reinitiliazed the global inode and 758 * block bitmap first execution check variables 759 */ 760 fs->first_pass_ibmap = 0; 761 fs->first_pass_bbmap = 0; 762 fs->curr_inode_no = 0; 763 fs->curr_blkno = 0; 764 } 765 766 static int ext4fs_write_file(struct ext2_inode *file_inode, 767 int pos, unsigned int len, char *buf) 768 { 769 int i; 770 int blockcnt; 771 uint32_t filesize = le32_to_cpu(file_inode->size); 772 struct ext_filesystem *fs = get_fs(); 773 int log2blksz = fs->dev_desc->log2blksz; 774 int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz; 775 int previous_block_number = -1; 776 int delayed_start = 0; 777 int delayed_extent = 0; 778 int delayed_next = 0; 779 char *delayed_buf = NULL; 780 781 /* Adjust len so it we can't read past the end of the file. */ 782 if (len > filesize) 783 len = filesize; 784 785 blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz; 786 787 for (i = pos / fs->blksz; i < blockcnt; i++) { 788 long int blknr; 789 int blockend = fs->blksz; 790 int skipfirst = 0; 791 blknr = read_allocated_block(file_inode, i); 792 if (blknr < 0) 793 return -1; 794 795 blknr = blknr << log2_fs_blocksize; 796 797 if (blknr) { 798 if (previous_block_number != -1) { 799 if (delayed_next == blknr) { 800 delayed_extent += blockend; 801 delayed_next += blockend >> log2blksz; 802 } else { /* spill */ 803 put_ext4((uint64_t) 804 ((uint64_t)delayed_start << log2blksz), 805 delayed_buf, 806 (uint32_t) delayed_extent); 807 previous_block_number = blknr; 808 delayed_start = blknr; 809 delayed_extent = blockend; 810 delayed_buf = buf; 811 delayed_next = blknr + 812 (blockend >> log2blksz); 813 } 814 } else { 815 previous_block_number = blknr; 816 delayed_start = blknr; 817 delayed_extent = blockend; 818 delayed_buf = buf; 819 delayed_next = blknr + 820 (blockend >> log2blksz); 821 } 822 } else { 823 if (previous_block_number != -1) { 824 /* spill */ 825 put_ext4((uint64_t) ((uint64_t)delayed_start << 826 log2blksz), 827 delayed_buf, 828 (uint32_t) delayed_extent); 829 previous_block_number = -1; 830 } 831 memset(buf, 0, fs->blksz - skipfirst); 832 } 833 buf += fs->blksz - skipfirst; 834 } 835 if (previous_block_number != -1) { 836 /* spill */ 837 put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz), 838 delayed_buf, (uint32_t) delayed_extent); 839 previous_block_number = -1; 840 } 841 842 return len; 843 } 844 845 int ext4fs_write(const char *fname, unsigned char *buffer, 846 unsigned long sizebytes) 847 { 848 int ret = 0; 849 struct ext2_inode *file_inode = NULL; 850 unsigned char *inode_buffer = NULL; 851 int parent_inodeno; 852 int inodeno; 853 time_t timestamp = 0; 854 855 uint64_t bytes_reqd_for_file; 856 unsigned int blks_reqd_for_file; 857 unsigned int blocks_remaining; 858 int existing_file_inodeno; 859 char *temp_ptr = NULL; 860 long int itable_blkno; 861 long int parent_itable_blkno; 862 long int blkoff; 863 struct ext2_sblock *sblock = &(ext4fs_root->sblock); 864 unsigned int inodes_per_block; 865 unsigned int ibmap_idx; 866 struct ext_filesystem *fs = get_fs(); 867 ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256); 868 memset(filename, 0x00, 256); 869 870 g_parent_inode = zalloc(sizeof(struct ext2_inode)); 871 if (!g_parent_inode) 872 goto fail; 873 874 if (ext4fs_init() != 0) { 875 printf("error in File System init\n"); 876 return -1; 877 } 878 inodes_per_block = fs->blksz / fs->inodesz; 879 parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE); 880 if (parent_inodeno == -1) 881 goto fail; 882 if (ext4fs_iget(parent_inodeno, g_parent_inode)) 883 goto fail; 884 /* check if the filename is already present in root */ 885 existing_file_inodeno = ext4fs_filename_unlink(filename); 886 if (existing_file_inodeno != -1) { 887 ret = ext4fs_delete_file(existing_file_inodeno); 888 fs->first_pass_bbmap = 0; 889 fs->curr_blkno = 0; 890 891 fs->first_pass_ibmap = 0; 892 fs->curr_inode_no = 0; 893 if (ret) 894 goto fail; 895 } 896 /* calucalate how many blocks required */ 897 bytes_reqd_for_file = sizebytes; 898 blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz); 899 if (do_div(bytes_reqd_for_file, fs->blksz) != 0) { 900 blks_reqd_for_file++; 901 debug("total bytes for a file %u\n", blks_reqd_for_file); 902 } 903 blocks_remaining = blks_reqd_for_file; 904 /* test for available space in partition */ 905 if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) { 906 printf("Not enough space on partition !!!\n"); 907 goto fail; 908 } 909 910 inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG); 911 if (inodeno == -1) 912 goto fail; 913 /* prepare file inode */ 914 inode_buffer = zalloc(fs->inodesz); 915 if (!inode_buffer) 916 goto fail; 917 file_inode = (struct ext2_inode *)inode_buffer; 918 file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | 919 S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH); 920 /* ToDo: Update correct time */ 921 file_inode->mtime = cpu_to_le32(timestamp); 922 file_inode->atime = cpu_to_le32(timestamp); 923 file_inode->ctime = cpu_to_le32(timestamp); 924 file_inode->nlinks = cpu_to_le16(1); 925 file_inode->size = cpu_to_le32(sizebytes); 926 927 /* Allocate data blocks */ 928 ext4fs_allocate_blocks(file_inode, blocks_remaining, 929 &blks_reqd_for_file); 930 file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >> 931 fs->dev_desc->log2blksz); 932 933 temp_ptr = zalloc(fs->blksz); 934 if (!temp_ptr) 935 goto fail; 936 ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group); 937 inodeno--; 938 itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + 939 (inodeno % le32_to_cpu(sblock->inodes_per_group)) / 940 inodes_per_block; 941 blkoff = (inodeno % inodes_per_block) * fs->inodesz; 942 ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz, 943 temp_ptr); 944 if (ext4fs_log_journal(temp_ptr, itable_blkno)) 945 goto fail; 946 947 memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz); 948 if (ext4fs_put_metadata(temp_ptr, itable_blkno)) 949 goto fail; 950 /* copy the file content into data blocks */ 951 if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) { 952 printf("Error in copying content\n"); 953 goto fail; 954 } 955 ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group); 956 parent_inodeno--; 957 parent_itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + 958 (parent_inodeno % 959 le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; 960 blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz; 961 if (parent_itable_blkno != itable_blkno) { 962 memset(temp_ptr, '\0', fs->blksz); 963 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk, 964 0, fs->blksz, temp_ptr); 965 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno)) 966 goto fail; 967 968 memcpy(temp_ptr + blkoff, g_parent_inode, 969 sizeof(struct ext2_inode)); 970 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno)) 971 goto fail; 972 free(temp_ptr); 973 } else { 974 /* 975 * If parent and child fall in same inode table block 976 * both should be kept in 1 buffer 977 */ 978 memcpy(temp_ptr + blkoff, g_parent_inode, 979 sizeof(struct ext2_inode)); 980 gd_index--; 981 if (ext4fs_put_metadata(temp_ptr, itable_blkno)) 982 goto fail; 983 free(temp_ptr); 984 } 985 ext4fs_update(); 986 ext4fs_deinit(); 987 988 fs->first_pass_bbmap = 0; 989 fs->curr_blkno = 0; 990 fs->first_pass_ibmap = 0; 991 fs->curr_inode_no = 0; 992 free(inode_buffer); 993 free(g_parent_inode); 994 g_parent_inode = NULL; 995 996 return 0; 997 fail: 998 ext4fs_deinit(); 999 free(inode_buffer); 1000 free(g_parent_inode); 1001 g_parent_inode = NULL; 1002 1003 return -1; 1004 } 1005 1006 int ext4_write_file(const char *filename, void *buf, loff_t offset, 1007 loff_t len, loff_t *actwrite) 1008 { 1009 int ret; 1010 1011 if (offset != 0) { 1012 printf("** Cannot support non-zero offset **\n"); 1013 return -1; 1014 } 1015 1016 ret = ext4fs_write(filename, buf, len); 1017 if (ret) { 1018 printf("** Error ext4fs_write() **\n"); 1019 goto fail; 1020 } 1021 1022 *actwrite = len; 1023 1024 return 0; 1025 1026 fail: 1027 *actwrite = 0; 1028 1029 return -1; 1030 } 1031