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