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