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