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 /* FIXME delete extent index blocks, i.e. eh_depth >= 1 */ 451 struct ext4_extent_header *eh = 452 (struct ext4_extent_header *) 453 inode.b.blocks.dir_blocks; 454 debug("del: dep=%d entries=%d\n", eh->eh_depth, eh->eh_entries); 455 } else { 456 delete_single_indirect_block(&inode); 457 delete_double_indirect_block(&inode); 458 delete_triple_indirect_block(&inode); 459 } 460 461 /* release data blocks */ 462 for (i = 0; i < no_blocks; i++) { 463 blknr = read_allocated_block(&inode, i); 464 bg_idx = blknr / blk_per_grp; 465 if (fs->blksz == 1024) { 466 remainder = blknr % blk_per_grp; 467 if (!remainder) 468 bg_idx--; 469 } 470 ext4fs_reset_block_bmap(blknr, fs->blk_bmaps[bg_idx], 471 bg_idx); 472 debug("EXT4 Block releasing %ld: %d\n", blknr, bg_idx); 473 474 ext4fs_bg_free_blocks_inc(&bgd[bg_idx]); 475 ext4fs_sb_free_blocks_inc(fs->sb); 476 /* journal backup */ 477 if (prev_bg_bmap_idx != bg_idx) { 478 uint32_t bgd_blknr = le32_to_cpu(bgd[bg_idx].block_id); 479 status = ext4fs_devread((lbaint_t)bgd_blknr * 480 fs->sect_perblk, 481 0, fs->blksz, 482 journal_buffer); 483 if (status == 0) 484 goto fail; 485 if (ext4fs_log_journal(journal_buffer, bgd_blknr)) 486 goto fail; 487 prev_bg_bmap_idx = bg_idx; 488 } 489 } 490 491 /* release inode */ 492 /* from the inode no to blockno */ 493 inodes_per_block = fs->blksz / fs->inodesz; 494 ibmap_idx = inodeno / inode_per_grp; 495 496 /* get the block no */ 497 inodeno--; 498 blkno = le32_to_cpu(bgd[ibmap_idx].inode_table_id) + 499 (inodeno % inode_per_grp) / inodes_per_block; 500 501 /* get the offset of the inode */ 502 blkoff = ((inodeno) % inodes_per_block) * fs->inodesz; 503 504 /* read the block no containing the inode */ 505 read_buffer = zalloc(fs->blksz); 506 if (!read_buffer) 507 goto fail; 508 start_block_address = read_buffer; 509 status = ext4fs_devread((lbaint_t)blkno * fs->sect_perblk, 510 0, fs->blksz, read_buffer); 511 if (status == 0) 512 goto fail; 513 514 if (ext4fs_log_journal(read_buffer, blkno)) 515 goto fail; 516 517 read_buffer = read_buffer + blkoff; 518 inode_buffer = (struct ext2_inode *)read_buffer; 519 memset(inode_buffer, '\0', fs->inodesz); 520 521 /* write the inode to original position in inode table */ 522 if (ext4fs_put_metadata(start_block_address, blkno)) 523 goto fail; 524 525 /* update the respective inode bitmaps */ 526 inodeno++; 527 ext4fs_reset_inode_bmap(inodeno, fs->inode_bmaps[ibmap_idx], ibmap_idx); 528 ext4fs_bg_free_inodes_inc(&bgd[ibmap_idx]); 529 ext4fs_sb_free_inodes_inc(fs->sb); 530 /* journal backup */ 531 memset(journal_buffer, '\0', fs->blksz); 532 status = ext4fs_devread((lbaint_t)le32_to_cpu(bgd[ibmap_idx].inode_id) * 533 fs->sect_perblk, 0, fs->blksz, journal_buffer); 534 if (status == 0) 535 goto fail; 536 if (ext4fs_log_journal(journal_buffer, le32_to_cpu(bgd[ibmap_idx].inode_id))) 537 goto fail; 538 539 ext4fs_update(); 540 ext4fs_deinit(); 541 ext4fs_reinit_global(); 542 543 if (ext4fs_init() != 0) { 544 printf("error in File System init\n"); 545 goto fail; 546 } 547 548 free(start_block_address); 549 free(journal_buffer); 550 551 return 0; 552 fail: 553 free(start_block_address); 554 free(journal_buffer); 555 556 return -1; 557 } 558 559 int ext4fs_init(void) 560 { 561 short status; 562 int i; 563 uint32_t real_free_blocks = 0; 564 struct ext_filesystem *fs = get_fs(); 565 566 /* populate fs */ 567 fs->blksz = EXT2_BLOCK_SIZE(ext4fs_root); 568 fs->sect_perblk = fs->blksz >> fs->dev_desc->log2blksz; 569 570 /* get the superblock */ 571 fs->sb = zalloc(SUPERBLOCK_SIZE); 572 if (!fs->sb) 573 return -ENOMEM; 574 if (!ext4_read_superblock((char *)fs->sb)) 575 goto fail; 576 577 /* init journal */ 578 if (ext4fs_init_journal()) 579 goto fail; 580 581 /* get total no of blockgroups */ 582 fs->no_blkgrp = (uint32_t)ext4fs_div_roundup( 583 le32_to_cpu(ext4fs_root->sblock.total_blocks) 584 - le32_to_cpu(ext4fs_root->sblock.first_data_block), 585 le32_to_cpu(ext4fs_root->sblock.blocks_per_group)); 586 587 /* get the block group descriptor table */ 588 fs->gdtable_blkno = ((EXT2_MIN_BLOCK_SIZE == fs->blksz) + 1); 589 if (ext4fs_get_bgdtable() == -1) { 590 printf("Error in getting the block group descriptor table\n"); 591 goto fail; 592 } 593 fs->bgd = (struct ext2_block_group *)fs->gdtable; 594 595 /* load all the available bitmap block of the partition */ 596 fs->blk_bmaps = zalloc(fs->no_blkgrp * sizeof(char *)); 597 if (!fs->blk_bmaps) 598 goto fail; 599 for (i = 0; i < fs->no_blkgrp; i++) { 600 fs->blk_bmaps[i] = zalloc(fs->blksz); 601 if (!fs->blk_bmaps[i]) 602 goto fail; 603 } 604 605 for (i = 0; i < fs->no_blkgrp; i++) { 606 status = 607 ext4fs_devread( 608 (lbaint_t)le32_to_cpu(fs->bgd[i].block_id) * 609 fs->sect_perblk, 0, 610 fs->blksz, (char *)fs->blk_bmaps[i]); 611 if (status == 0) 612 goto fail; 613 } 614 615 /* load all the available inode bitmap of the partition */ 616 fs->inode_bmaps = zalloc(fs->no_blkgrp * sizeof(unsigned char *)); 617 if (!fs->inode_bmaps) 618 goto fail; 619 for (i = 0; i < fs->no_blkgrp; i++) { 620 fs->inode_bmaps[i] = zalloc(fs->blksz); 621 if (!fs->inode_bmaps[i]) 622 goto fail; 623 } 624 625 for (i = 0; i < fs->no_blkgrp; i++) { 626 status = ext4fs_devread( 627 (lbaint_t)le32_to_cpu(fs->bgd[i].inode_id) * 628 fs->sect_perblk, 629 0, fs->blksz, 630 (char *)fs->inode_bmaps[i]); 631 if (status == 0) 632 goto fail; 633 } 634 635 /* 636 * check filesystem consistency with free blocks of file system 637 * some time we observed that superblock freeblocks does not match 638 * with the blockgroups freeblocks when improper 639 * reboot of a linux kernel 640 */ 641 for (i = 0; i < fs->no_blkgrp; i++) 642 real_free_blocks = real_free_blocks + le16_to_cpu(fs->bgd[i].free_blocks); 643 if (real_free_blocks != le32_to_cpu(fs->sb->free_blocks)) 644 fs->sb->free_blocks = cpu_to_le32(real_free_blocks); 645 646 return 0; 647 fail: 648 ext4fs_deinit(); 649 650 return -1; 651 } 652 653 void ext4fs_deinit(void) 654 { 655 int i; 656 struct ext2_inode inode_journal; 657 struct journal_superblock_t *jsb; 658 uint32_t blknr; 659 struct ext_filesystem *fs = get_fs(); 660 uint32_t new_feature_incompat; 661 662 /* free journal */ 663 char *temp_buff = zalloc(fs->blksz); 664 if (temp_buff) { 665 ext4fs_read_inode(ext4fs_root, EXT2_JOURNAL_INO, 666 &inode_journal); 667 blknr = read_allocated_block(&inode_journal, 668 EXT2_JOURNAL_SUPERBLOCK); 669 ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0, fs->blksz, 670 temp_buff); 671 jsb = (struct journal_superblock_t *)temp_buff; 672 jsb->s_start = 0; 673 put_ext4((uint64_t) ((uint64_t)blknr * (uint64_t)fs->blksz), 674 (struct journal_superblock_t *)temp_buff, fs->blksz); 675 free(temp_buff); 676 } 677 ext4fs_free_journal(); 678 679 /* get the superblock */ 680 ext4_read_superblock((char *)fs->sb); 681 new_feature_incompat = le32_to_cpu(fs->sb->feature_incompat); 682 new_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; 683 fs->sb->feature_incompat = cpu_to_le32(new_feature_incompat); 684 put_ext4((uint64_t)(SUPERBLOCK_SIZE), 685 (struct ext2_sblock *)fs->sb, (uint32_t)SUPERBLOCK_SIZE); 686 free(fs->sb); 687 fs->sb = NULL; 688 689 if (fs->blk_bmaps) { 690 for (i = 0; i < fs->no_blkgrp; i++) { 691 free(fs->blk_bmaps[i]); 692 fs->blk_bmaps[i] = NULL; 693 } 694 free(fs->blk_bmaps); 695 fs->blk_bmaps = NULL; 696 } 697 698 if (fs->inode_bmaps) { 699 for (i = 0; i < fs->no_blkgrp; i++) { 700 free(fs->inode_bmaps[i]); 701 fs->inode_bmaps[i] = NULL; 702 } 703 free(fs->inode_bmaps); 704 fs->inode_bmaps = NULL; 705 } 706 707 708 free(fs->gdtable); 709 fs->gdtable = NULL; 710 fs->bgd = NULL; 711 /* 712 * reinitiliazed the global inode and 713 * block bitmap first execution check variables 714 */ 715 fs->first_pass_ibmap = 0; 716 fs->first_pass_bbmap = 0; 717 fs->curr_inode_no = 0; 718 fs->curr_blkno = 0; 719 } 720 721 static int ext4fs_write_file(struct ext2_inode *file_inode, 722 int pos, unsigned int len, char *buf) 723 { 724 int i; 725 int blockcnt; 726 uint32_t filesize = le32_to_cpu(file_inode->size); 727 struct ext_filesystem *fs = get_fs(); 728 int log2blksz = fs->dev_desc->log2blksz; 729 int log2_fs_blocksize = LOG2_BLOCK_SIZE(ext4fs_root) - log2blksz; 730 int previous_block_number = -1; 731 int delayed_start = 0; 732 int delayed_extent = 0; 733 int delayed_next = 0; 734 char *delayed_buf = NULL; 735 736 /* Adjust len so it we can't read past the end of the file. */ 737 if (len > filesize) 738 len = filesize; 739 740 blockcnt = ((len + pos) + fs->blksz - 1) / fs->blksz; 741 742 for (i = pos / fs->blksz; i < blockcnt; i++) { 743 long int blknr; 744 int blockend = fs->blksz; 745 int skipfirst = 0; 746 blknr = read_allocated_block(file_inode, i); 747 if (blknr < 0) 748 return -1; 749 750 blknr = blknr << log2_fs_blocksize; 751 752 if (blknr) { 753 if (previous_block_number != -1) { 754 if (delayed_next == blknr) { 755 delayed_extent += blockend; 756 delayed_next += blockend >> log2blksz; 757 } else { /* spill */ 758 put_ext4((uint64_t) 759 ((uint64_t)delayed_start << log2blksz), 760 delayed_buf, 761 (uint32_t) delayed_extent); 762 previous_block_number = blknr; 763 delayed_start = blknr; 764 delayed_extent = blockend; 765 delayed_buf = buf; 766 delayed_next = blknr + 767 (blockend >> log2blksz); 768 } 769 } else { 770 previous_block_number = blknr; 771 delayed_start = blknr; 772 delayed_extent = blockend; 773 delayed_buf = buf; 774 delayed_next = blknr + 775 (blockend >> log2blksz); 776 } 777 } else { 778 if (previous_block_number != -1) { 779 /* spill */ 780 put_ext4((uint64_t) ((uint64_t)delayed_start << 781 log2blksz), 782 delayed_buf, 783 (uint32_t) delayed_extent); 784 previous_block_number = -1; 785 } 786 memset(buf, 0, fs->blksz - skipfirst); 787 } 788 buf += fs->blksz - skipfirst; 789 } 790 if (previous_block_number != -1) { 791 /* spill */ 792 put_ext4((uint64_t) ((uint64_t)delayed_start << log2blksz), 793 delayed_buf, (uint32_t) delayed_extent); 794 previous_block_number = -1; 795 } 796 797 return len; 798 } 799 800 int ext4fs_write(const char *fname, unsigned char *buffer, 801 unsigned long sizebytes) 802 { 803 int ret = 0; 804 struct ext2_inode *file_inode = NULL; 805 unsigned char *inode_buffer = NULL; 806 int parent_inodeno; 807 int inodeno; 808 time_t timestamp = 0; 809 810 uint64_t bytes_reqd_for_file; 811 unsigned int blks_reqd_for_file; 812 unsigned int blocks_remaining; 813 int existing_file_inodeno; 814 char *temp_ptr = NULL; 815 long int itable_blkno; 816 long int parent_itable_blkno; 817 long int blkoff; 818 struct ext2_sblock *sblock = &(ext4fs_root->sblock); 819 unsigned int inodes_per_block; 820 unsigned int ibmap_idx; 821 struct ext_filesystem *fs = get_fs(); 822 ALLOC_CACHE_ALIGN_BUFFER(char, filename, 256); 823 memset(filename, 0x00, 256); 824 825 g_parent_inode = zalloc(fs->inodesz); 826 if (!g_parent_inode) 827 goto fail; 828 829 if (ext4fs_init() != 0) { 830 printf("error in File System init\n"); 831 return -1; 832 } 833 inodes_per_block = fs->blksz / fs->inodesz; 834 parent_inodeno = ext4fs_get_parent_inode_num(fname, filename, F_FILE); 835 if (parent_inodeno == -1) 836 goto fail; 837 if (ext4fs_iget(parent_inodeno, g_parent_inode)) 838 goto fail; 839 /* do not mess up a directory using hash trees */ 840 if (le32_to_cpu(g_parent_inode->flags) & EXT4_INDEX_FL) { 841 printf("hash tree directory\n"); 842 goto fail; 843 } 844 /* check if the filename is already present in root */ 845 existing_file_inodeno = ext4fs_filename_unlink(filename); 846 if (existing_file_inodeno != -1) { 847 ret = ext4fs_delete_file(existing_file_inodeno); 848 fs->first_pass_bbmap = 0; 849 fs->curr_blkno = 0; 850 851 fs->first_pass_ibmap = 0; 852 fs->curr_inode_no = 0; 853 if (ret) 854 goto fail; 855 } 856 /* calucalate how many blocks required */ 857 bytes_reqd_for_file = sizebytes; 858 blks_reqd_for_file = lldiv(bytes_reqd_for_file, fs->blksz); 859 if (do_div(bytes_reqd_for_file, fs->blksz) != 0) { 860 blks_reqd_for_file++; 861 debug("total bytes for a file %u\n", blks_reqd_for_file); 862 } 863 blocks_remaining = blks_reqd_for_file; 864 /* test for available space in partition */ 865 if (le32_to_cpu(fs->sb->free_blocks) < blks_reqd_for_file) { 866 printf("Not enough space on partition !!!\n"); 867 goto fail; 868 } 869 870 inodeno = ext4fs_update_parent_dentry(filename, FILETYPE_REG); 871 if (inodeno == -1) 872 goto fail; 873 /* prepare file inode */ 874 inode_buffer = zalloc(fs->inodesz); 875 if (!inode_buffer) 876 goto fail; 877 file_inode = (struct ext2_inode *)inode_buffer; 878 file_inode->mode = cpu_to_le16(S_IFREG | S_IRWXU | 879 S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH); 880 /* ToDo: Update correct time */ 881 file_inode->mtime = cpu_to_le32(timestamp); 882 file_inode->atime = cpu_to_le32(timestamp); 883 file_inode->ctime = cpu_to_le32(timestamp); 884 file_inode->nlinks = cpu_to_le16(1); 885 file_inode->size = cpu_to_le32(sizebytes); 886 887 /* Allocate data blocks */ 888 ext4fs_allocate_blocks(file_inode, blocks_remaining, 889 &blks_reqd_for_file); 890 file_inode->blockcnt = cpu_to_le32((blks_reqd_for_file * fs->blksz) >> 891 fs->dev_desc->log2blksz); 892 893 temp_ptr = zalloc(fs->blksz); 894 if (!temp_ptr) 895 goto fail; 896 ibmap_idx = inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group); 897 inodeno--; 898 itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + 899 (inodeno % le32_to_cpu(sblock->inodes_per_group)) / 900 inodes_per_block; 901 blkoff = (inodeno % inodes_per_block) * fs->inodesz; 902 ext4fs_devread((lbaint_t)itable_blkno * fs->sect_perblk, 0, fs->blksz, 903 temp_ptr); 904 if (ext4fs_log_journal(temp_ptr, itable_blkno)) 905 goto fail; 906 907 memcpy(temp_ptr + blkoff, inode_buffer, fs->inodesz); 908 if (ext4fs_put_metadata(temp_ptr, itable_blkno)) 909 goto fail; 910 /* copy the file content into data blocks */ 911 if (ext4fs_write_file(file_inode, 0, sizebytes, (char *)buffer) == -1) { 912 printf("Error in copying content\n"); 913 goto fail; 914 } 915 ibmap_idx = parent_inodeno / le32_to_cpu(ext4fs_root->sblock.inodes_per_group); 916 parent_inodeno--; 917 parent_itable_blkno = le32_to_cpu(fs->bgd[ibmap_idx].inode_table_id) + 918 (parent_inodeno % 919 le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block; 920 blkoff = (parent_inodeno % inodes_per_block) * fs->inodesz; 921 if (parent_itable_blkno != itable_blkno) { 922 memset(temp_ptr, '\0', fs->blksz); 923 ext4fs_devread((lbaint_t)parent_itable_blkno * fs->sect_perblk, 924 0, fs->blksz, temp_ptr); 925 if (ext4fs_log_journal(temp_ptr, parent_itable_blkno)) 926 goto fail; 927 928 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz); 929 if (ext4fs_put_metadata(temp_ptr, parent_itable_blkno)) 930 goto fail; 931 } else { 932 /* 933 * If parent and child fall in same inode table block 934 * both should be kept in 1 buffer 935 */ 936 memcpy(temp_ptr + blkoff, g_parent_inode, fs->inodesz); 937 gd_index--; 938 if (ext4fs_put_metadata(temp_ptr, itable_blkno)) 939 goto fail; 940 } 941 ext4fs_update(); 942 ext4fs_deinit(); 943 944 fs->first_pass_bbmap = 0; 945 fs->curr_blkno = 0; 946 fs->first_pass_ibmap = 0; 947 fs->curr_inode_no = 0; 948 free(inode_buffer); 949 free(g_parent_inode); 950 free(temp_ptr); 951 g_parent_inode = NULL; 952 953 return 0; 954 fail: 955 ext4fs_deinit(); 956 free(inode_buffer); 957 free(g_parent_inode); 958 free(temp_ptr); 959 g_parent_inode = NULL; 960 961 return -1; 962 } 963 964 int ext4_write_file(const char *filename, void *buf, loff_t offset, 965 loff_t len, loff_t *actwrite) 966 { 967 int ret; 968 969 if (offset != 0) { 970 printf("** Cannot support non-zero offset **\n"); 971 return -1; 972 } 973 974 ret = ext4fs_write(filename, buf, len); 975 if (ret) { 976 printf("** Error ext4fs_write() **\n"); 977 goto fail; 978 } 979 980 *actwrite = len; 981 982 return 0; 983 984 fail: 985 *actwrite = 0; 986 987 return -1; 988 } 989