uboot/fs/ext4/ext4_common.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2011 - 2012 Samsung Electronics
   4 * EXT4 filesystem implementation in Uboot by
   5 * Uma Shankar <uma.shankar@samsung.com>
   6 * Manjunatha C Achar <a.manjunatha@samsung.com>
   7 *
   8 * ext4ls and ext4load : Based on ext2 ls load support in Uboot.
   9 *
  10 * (C) Copyright 2004
  11 * esd gmbh <www.esd-electronics.com>
  12 * Reinhard Arlt <reinhard.arlt@esd-electronics.com>
  13 *
  14 * based on code from grub2 fs/ext2.c and fs/fshelp.c by
  15 * GRUB  --  GRand Unified Bootloader
  16 * Copyright (C) 2003, 2004  Free Software Foundation, Inc.
  17 *
  18 * ext4write : Based on generic ext4 protocol.
  19 */
  20
  21#include <common.h>
  22#include <ext_common.h>
  23#include <ext4fs.h>
  24#include <malloc.h>
  25#include <memalign.h>
  26#include <stddef.h>
  27#include <linux/stat.h>
  28#include <linux/time.h>
  29#include <asm/byteorder.h>
  30#include "ext4_common.h"
  31
  32struct ext2_data *ext4fs_root;
  33struct ext2fs_node *ext4fs_file;
  34__le32 *ext4fs_indir1_block;
  35int ext4fs_indir1_size;
  36int ext4fs_indir1_blkno = -1;
  37__le32 *ext4fs_indir2_block;
  38int ext4fs_indir2_size;
  39int ext4fs_indir2_blkno = -1;
  40
  41__le32 *ext4fs_indir3_block;
  42int ext4fs_indir3_size;
  43int ext4fs_indir3_blkno = -1;
  44struct ext2_inode *g_parent_inode;
  45static int symlinknest;
  46
  47#if defined(CONFIG_EXT4_WRITE)
  48struct ext2_block_group *ext4fs_get_group_descriptor
  49        (const struct ext_filesystem *fs, uint32_t bg_idx)
  50{
  51        return (struct ext2_block_group *)(fs->gdtable + (bg_idx * fs->gdsize));
  52}
  53
  54static inline void ext4fs_sb_free_inodes_dec(struct ext2_sblock *sb)
  55{
  56        sb->free_inodes = cpu_to_le32(le32_to_cpu(sb->free_inodes) - 1);
  57}
  58
  59static inline void ext4fs_sb_free_blocks_dec(struct ext2_sblock *sb)
  60{
  61        uint64_t free_blocks = le32_to_cpu(sb->free_blocks);
  62        free_blocks += (uint64_t)le32_to_cpu(sb->free_blocks_high) << 32;
  63        free_blocks--;
  64
  65        sb->free_blocks = cpu_to_le32(free_blocks & 0xffffffff);
  66        sb->free_blocks_high = cpu_to_le16(free_blocks >> 32);
  67}
  68
  69static inline void ext4fs_bg_free_inodes_dec
  70        (struct ext2_block_group *bg, const struct ext_filesystem *fs)
  71{
  72        uint32_t free_inodes = le16_to_cpu(bg->free_inodes);
  73        if (fs->gdsize == 64)
  74                free_inodes += le16_to_cpu(bg->free_inodes_high) << 16;
  75        free_inodes--;
  76
  77        bg->free_inodes = cpu_to_le16(free_inodes & 0xffff);
  78        if (fs->gdsize == 64)
  79                bg->free_inodes_high = cpu_to_le16(free_inodes >> 16);
  80}
  81
  82static inline void ext4fs_bg_free_blocks_dec
  83        (struct ext2_block_group *bg, const struct ext_filesystem *fs)
  84{
  85        uint32_t free_blocks = le16_to_cpu(bg->free_blocks);
  86        if (fs->gdsize == 64)
  87                free_blocks += le16_to_cpu(bg->free_blocks_high) << 16;
  88        free_blocks--;
  89
  90        bg->free_blocks = cpu_to_le16(free_blocks & 0xffff);
  91        if (fs->gdsize == 64)
  92                bg->free_blocks_high = cpu_to_le16(free_blocks >> 16);
  93}
  94
  95static inline void ext4fs_bg_itable_unused_dec
  96        (struct ext2_block_group *bg, const struct ext_filesystem *fs)
  97{
  98        uint32_t free_inodes = le16_to_cpu(bg->bg_itable_unused);
  99        if (fs->gdsize == 64)
 100                free_inodes += le16_to_cpu(bg->bg_itable_unused_high) << 16;
 101        free_inodes--;
 102
 103        bg->bg_itable_unused = cpu_to_le16(free_inodes & 0xffff);
 104        if (fs->gdsize == 64)
 105                bg->bg_itable_unused_high = cpu_to_le16(free_inodes >> 16);
 106}
 107
 108uint64_t ext4fs_sb_get_free_blocks(const struct ext2_sblock *sb)
 109{
 110        uint64_t free_blocks = le32_to_cpu(sb->free_blocks);
 111        free_blocks += (uint64_t)le32_to_cpu(sb->free_blocks_high) << 32;
 112        return free_blocks;
 113}
 114
 115void ext4fs_sb_set_free_blocks(struct ext2_sblock *sb, uint64_t free_blocks)
 116{
 117        sb->free_blocks = cpu_to_le32(free_blocks & 0xffffffff);
 118        sb->free_blocks_high = cpu_to_le16(free_blocks >> 32);
 119}
 120
 121uint32_t ext4fs_bg_get_free_blocks(const struct ext2_block_group *bg,
 122                                   const struct ext_filesystem *fs)
 123{
 124        uint32_t free_blocks = le16_to_cpu(bg->free_blocks);
 125        if (fs->gdsize == 64)
 126                free_blocks += le16_to_cpu(bg->free_blocks_high) << 16;
 127        return free_blocks;
 128}
 129
 130static inline
 131uint32_t ext4fs_bg_get_free_inodes(const struct ext2_block_group *bg,
 132                                   const struct ext_filesystem *fs)
 133{
 134        uint32_t free_inodes = le16_to_cpu(bg->free_inodes);
 135        if (fs->gdsize == 64)
 136                free_inodes += le16_to_cpu(bg->free_inodes_high) << 16;
 137        return free_inodes;
 138}
 139
 140static inline uint16_t ext4fs_bg_get_flags(const struct ext2_block_group *bg)
 141{
 142        return le16_to_cpu(bg->bg_flags);
 143}
 144
 145static inline void ext4fs_bg_set_flags(struct ext2_block_group *bg,
 146                                       uint16_t flags)
 147{
 148        bg->bg_flags = cpu_to_le16(flags);
 149}
 150
 151/* Block number of the block bitmap */
 152uint64_t ext4fs_bg_get_block_id(const struct ext2_block_group *bg,
 153                                const struct ext_filesystem *fs)
 154{
 155        uint64_t block_nr = le32_to_cpu(bg->block_id);
 156        if (fs->gdsize == 64)
 157                block_nr += (uint64_t)le32_to_cpu(bg->block_id_high) << 32;
 158        return block_nr;
 159}
 160
 161/* Block number of the inode bitmap */
 162uint64_t ext4fs_bg_get_inode_id(const struct ext2_block_group *bg,
 163                                const struct ext_filesystem *fs)
 164{
 165        uint64_t block_nr = le32_to_cpu(bg->inode_id);
 166        if (fs->gdsize == 64)
 167                block_nr += (uint64_t)le32_to_cpu(bg->inode_id_high) << 32;
 168        return block_nr;
 169}
 170#endif
 171
 172/* Block number of the inode table */
 173uint64_t ext4fs_bg_get_inode_table_id(const struct ext2_block_group *bg,
 174                                      const struct ext_filesystem *fs)
 175{
 176        uint64_t block_nr = le32_to_cpu(bg->inode_table_id);
 177        if (fs->gdsize == 64)
 178                block_nr +=
 179                        (uint64_t)le32_to_cpu(bg->inode_table_id_high) << 32;
 180        return block_nr;
 181}
 182
 183#if defined(CONFIG_EXT4_WRITE)
 184uint32_t ext4fs_div_roundup(uint32_t size, uint32_t n)
 185{
 186        uint32_t res = size / n;
 187        if (res * n != size)
 188                res++;
 189
 190        return res;
 191}
 192
 193void put_ext4(uint64_t off, void *buf, uint32_t size)
 194{
 195        uint64_t startblock;
 196        uint64_t remainder;
 197        unsigned char *temp_ptr = NULL;
 198        struct ext_filesystem *fs = get_fs();
 199        int log2blksz = fs->dev_desc->log2blksz;
 200        ALLOC_CACHE_ALIGN_BUFFER(unsigned char, sec_buf, fs->dev_desc->blksz);
 201
 202        startblock = off >> log2blksz;
 203        startblock += part_offset;
 204        remainder = off & (uint64_t)(fs->dev_desc->blksz - 1);
 205
 206        if (fs->dev_desc == NULL)
 207                return;
 208
 209        if ((startblock + (size >> log2blksz)) >
 210            (part_offset + fs->total_sect)) {
 211                printf("part_offset is " LBAFU "\n", part_offset);
 212                printf("total_sector is %llu\n", fs->total_sect);
 213                printf("error: overflow occurs\n");
 214                return;
 215        }
 216
 217        if (remainder) {
 218                blk_dread(fs->dev_desc, startblock, 1, sec_buf);
 219                temp_ptr = sec_buf;
 220                memcpy((temp_ptr + remainder), (unsigned char *)buf, size);
 221                blk_dwrite(fs->dev_desc, startblock, 1, sec_buf);
 222        } else {
 223                if (size >> log2blksz != 0) {
 224                        blk_dwrite(fs->dev_desc, startblock, size >> log2blksz,
 225                                   (unsigned long *)buf);
 226                } else {
 227                        blk_dread(fs->dev_desc, startblock, 1, sec_buf);
 228                        temp_ptr = sec_buf;
 229                        memcpy(temp_ptr, buf, size);
 230                        blk_dwrite(fs->dev_desc, startblock, 1,
 231                                   (unsigned long *)sec_buf);
 232                }
 233        }
 234}
 235
 236static int _get_new_inode_no(unsigned char *buffer)
 237{
 238        struct ext_filesystem *fs = get_fs();
 239        unsigned char input;
 240        int operand, status;
 241        int count = 1;
 242        int j = 0;
 243
 244        /* get the blocksize of the filesystem */
 245        unsigned char *ptr = buffer;
 246        while (*ptr == 255) {
 247                ptr++;
 248                count += 8;
 249                if (count > le32_to_cpu(ext4fs_root->sblock.inodes_per_group))
 250                        return -1;
 251        }
 252
 253        for (j = 0; j < fs->blksz; j++) {
 254                input = *ptr;
 255                int i = 0;
 256                while (i <= 7) {
 257                        operand = 1 << i;
 258                        status = input & operand;
 259                        if (status) {
 260                                i++;
 261                                count++;
 262                        } else {
 263                                *ptr |= operand;
 264                                return count;
 265                        }
 266                }
 267                ptr = ptr + 1;
 268        }
 269
 270        return -1;
 271}
 272
 273static int _get_new_blk_no(unsigned char *buffer)
 274{
 275        int operand;
 276        int count = 0;
 277        int i;
 278        unsigned char *ptr = buffer;
 279        struct ext_filesystem *fs = get_fs();
 280
 281        while (*ptr == 255) {
 282                ptr++;
 283                count += 8;
 284                if (count == (fs->blksz * 8))
 285                        return -1;
 286        }
 287
 288        if (fs->blksz == 1024)
 289                count += 1;
 290
 291        for (i = 0; i <= 7; i++) {
 292                operand = 1 << i;
 293                if (*ptr & operand) {
 294                        count++;
 295                } else {
 296                        *ptr |= operand;
 297                        return count;
 298                }
 299        }
 300
 301        return -1;
 302}
 303
 304int ext4fs_set_block_bmap(long int blockno, unsigned char *buffer, int index)
 305{
 306        int i, remainder, status;
 307        unsigned char *ptr = buffer;
 308        unsigned char operand;
 309        i = blockno / 8;
 310        remainder = blockno % 8;
 311        int blocksize = EXT2_BLOCK_SIZE(ext4fs_root);
 312
 313        i = i - (index * blocksize);
 314        if (blocksize != 1024) {
 315                ptr = ptr + i;
 316                operand = 1 << remainder;
 317                status = *ptr & operand;
 318                if (status)
 319                        return -1;
 320
 321                *ptr = *ptr | operand;
 322                return 0;
 323        } else {
 324                if (remainder == 0) {
 325                        ptr = ptr + i - 1;
 326                        operand = (1 << 7);
 327                } else {
 328                        ptr = ptr + i;
 329                        operand = (1 << (remainder - 1));
 330                }
 331                status = *ptr & operand;
 332                if (status)
 333                        return -1;
 334
 335                *ptr = *ptr | operand;
 336                return 0;
 337        }
 338}
 339
 340void ext4fs_reset_block_bmap(long int blockno, unsigned char *buffer, int index)
 341{
 342        int i, remainder, status;
 343        unsigned char *ptr = buffer;
 344        unsigned char operand;
 345        i = blockno / 8;
 346        remainder = blockno % 8;
 347        int blocksize = EXT2_BLOCK_SIZE(ext4fs_root);
 348
 349        i = i - (index * blocksize);
 350        if (blocksize != 1024) {
 351                ptr = ptr + i;
 352                operand = (1 << remainder);
 353                status = *ptr & operand;
 354                if (status)
 355                        *ptr = *ptr & ~(operand);
 356        } else {
 357                if (remainder == 0) {
 358                        ptr = ptr + i - 1;
 359                        operand = (1 << 7);
 360                } else {
 361                        ptr = ptr + i;
 362                        operand = (1 << (remainder - 1));
 363                }
 364                status = *ptr & operand;
 365                if (status)
 366                        *ptr = *ptr & ~(operand);
 367        }
 368}
 369
 370int ext4fs_set_inode_bmap(int inode_no, unsigned char *buffer, int index)
 371{
 372        int i, remainder, status;
 373        unsigned char *ptr = buffer;
 374        unsigned char operand;
 375
 376        inode_no -= (index * le32_to_cpu(ext4fs_root->sblock.inodes_per_group));
 377        i = inode_no / 8;
 378        remainder = inode_no % 8;
 379        if (remainder == 0) {
 380                ptr = ptr + i - 1;
 381                operand = (1 << 7);
 382        } else {
 383                ptr = ptr + i;
 384                operand = (1 << (remainder - 1));
 385        }
 386        status = *ptr & operand;
 387        if (status)
 388                return -1;
 389
 390        *ptr = *ptr | operand;
 391
 392        return 0;
 393}
 394
 395void ext4fs_reset_inode_bmap(int inode_no, unsigned char *buffer, int index)
 396{
 397        int i, remainder, status;
 398        unsigned char *ptr = buffer;
 399        unsigned char operand;
 400
 401        inode_no -= (index * le32_to_cpu(ext4fs_root->sblock.inodes_per_group));
 402        i = inode_no / 8;
 403        remainder = inode_no % 8;
 404        if (remainder == 0) {
 405                ptr = ptr + i - 1;
 406                operand = (1 << 7);
 407        } else {
 408                ptr = ptr + i;
 409                operand = (1 << (remainder - 1));
 410        }
 411        status = *ptr & operand;
 412        if (status)
 413                *ptr = *ptr & ~(operand);
 414}
 415
 416uint16_t ext4fs_checksum_update(uint32_t i)
 417{
 418        struct ext2_block_group *desc;
 419        struct ext_filesystem *fs = get_fs();
 420        uint16_t crc = 0;
 421        __le32 le32_i = cpu_to_le32(i);
 422
 423        desc = ext4fs_get_group_descriptor(fs, i);
 424        if (le32_to_cpu(fs->sb->feature_ro_compat) & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) {
 425                int offset = offsetof(struct ext2_block_group, bg_checksum);
 426
 427                crc = ext2fs_crc16(~0, fs->sb->unique_id,
 428                                   sizeof(fs->sb->unique_id));
 429                crc = ext2fs_crc16(crc, &le32_i, sizeof(le32_i));
 430                crc = ext2fs_crc16(crc, desc, offset);
 431                offset += sizeof(desc->bg_checksum);    /* skip checksum */
 432                assert(offset == sizeof(*desc));
 433                if (offset < fs->gdsize) {
 434                        crc = ext2fs_crc16(crc, (__u8 *)desc + offset,
 435                                           fs->gdsize - offset);
 436                }
 437        }
 438
 439        return crc;
 440}
 441
 442static int check_void_in_dentry(struct ext2_dirent *dir, char *filename)
 443{
 444        int dentry_length;
 445        int sizeof_void_space;
 446        int new_entry_byte_reqd;
 447        short padding_factor = 0;
 448
 449        if (dir->namelen % 4 != 0)
 450                padding_factor = 4 - (dir->namelen % 4);
 451
 452        dentry_length = sizeof(struct ext2_dirent) +
 453                        dir->namelen + padding_factor;
 454        sizeof_void_space = le16_to_cpu(dir->direntlen) - dentry_length;
 455        if (sizeof_void_space == 0)
 456                return 0;
 457
 458        padding_factor = 0;
 459        if (strlen(filename) % 4 != 0)
 460                padding_factor = 4 - (strlen(filename) % 4);
 461
 462        new_entry_byte_reqd = strlen(filename) +
 463            sizeof(struct ext2_dirent) + padding_factor;
 464        if (sizeof_void_space >= new_entry_byte_reqd) {
 465                dir->direntlen = cpu_to_le16(dentry_length);
 466                return sizeof_void_space;
 467        }
 468
 469        return 0;
 470}
 471
 472int ext4fs_update_parent_dentry(char *filename, int file_type)
 473{
 474        unsigned int *zero_buffer = NULL;
 475        char *root_first_block_buffer = NULL;
 476        int blk_idx;
 477        long int first_block_no_of_root = 0;
 478        int totalbytes = 0;
 479        unsigned int new_entry_byte_reqd;
 480        int sizeof_void_space = 0;
 481        int templength = 0;
 482        int inodeno = -1;
 483        int status;
 484        struct ext_filesystem *fs = get_fs();
 485        /* directory entry */
 486        struct ext2_dirent *dir;
 487        char *temp_dir = NULL;
 488        uint32_t new_blk_no;
 489        uint32_t new_size;
 490        uint32_t new_blockcnt;
 491        uint32_t directory_blocks;
 492
 493        zero_buffer = zalloc(fs->blksz);
 494        if (!zero_buffer) {
 495                printf("No Memory\n");
 496                return -1;
 497        }
 498        root_first_block_buffer = zalloc(fs->blksz);
 499        if (!root_first_block_buffer) {
 500                free(zero_buffer);
 501                printf("No Memory\n");
 502                return -1;
 503        }
 504        new_entry_byte_reqd = ROUND(strlen(filename) +
 505                                    sizeof(struct ext2_dirent), 4);
 506restart:
 507        directory_blocks = le32_to_cpu(g_parent_inode->size) >>
 508                LOG2_BLOCK_SIZE(ext4fs_root);
 509        blk_idx = directory_blocks - 1;
 510
 511restart_read:
 512        /* read the block no allocated to a file */
 513        first_block_no_of_root = read_allocated_block(g_parent_inode, blk_idx);
 514        if (first_block_no_of_root <= 0)
 515                goto fail;
 516
 517        status = ext4fs_devread((lbaint_t)first_block_no_of_root
 518                                * fs->sect_perblk,
 519                                0, fs->blksz, root_first_block_buffer);
 520        if (status == 0)
 521                goto fail;
 522
 523        if (ext4fs_log_journal(root_first_block_buffer, first_block_no_of_root))
 524                goto fail;
 525        dir = (struct ext2_dirent *)root_first_block_buffer;
 526        totalbytes = 0;
 527
 528        while (le16_to_cpu(dir->direntlen) > 0) {
 529                unsigned short used_len = ROUND(dir->namelen +
 530                    sizeof(struct ext2_dirent), 4);
 531
 532                /* last entry of block */
 533                if (fs->blksz - totalbytes == le16_to_cpu(dir->direntlen)) {
 534
 535                        /* check if new entry fits */
 536                        if ((used_len + new_entry_byte_reqd) <=
 537                            le16_to_cpu(dir->direntlen)) {
 538                                dir->direntlen = cpu_to_le16(used_len);
 539                                break;
 540                        } else {
 541                                if (blk_idx > 0) {
 542                                        printf("Block full, trying previous\n");
 543                                        blk_idx--;
 544                                        goto restart_read;
 545                                }
 546                                printf("All blocks full: Allocate new\n");
 547
 548                                if (le32_to_cpu(g_parent_inode->flags) &
 549                                                EXT4_EXTENTS_FL) {
 550                                        printf("Directory uses extents\n");
 551                                        goto fail;
 552                                }
 553                                if (directory_blocks >= INDIRECT_BLOCKS) {
 554                                        printf("Directory exceeds limit\n");
 555                                        goto fail;
 556                                }
 557                                new_blk_no = ext4fs_get_new_blk_no();
 558                                if (new_blk_no == -1) {
 559                                        printf("no block left to assign\n");
 560                                        goto fail;
 561                                }
 562                                put_ext4((uint64_t)new_blk_no * fs->blksz, zero_buffer, fs->blksz);
 563                                g_parent_inode->b.blocks.
 564                                        dir_blocks[directory_blocks] =
 565                                        cpu_to_le32(new_blk_no);
 566
 567                                new_size = le32_to_cpu(g_parent_inode->size);
 568                                new_size += fs->blksz;
 569                                g_parent_inode->size = cpu_to_le32(new_size);
 570
 571                                new_blockcnt = le32_to_cpu(g_parent_inode->blockcnt);
 572                                new_blockcnt += fs->sect_perblk;
 573                                g_parent_inode->blockcnt = cpu_to_le32(new_blockcnt);
 574
 575                                if (ext4fs_put_metadata
 576                                    (root_first_block_buffer,
 577                                     first_block_no_of_root))
 578                                        goto fail;
 579                                goto restart;
 580                        }
 581                }
 582
 583                templength = le16_to_cpu(dir->direntlen);
 584                totalbytes = totalbytes + templength;
 585                sizeof_void_space = check_void_in_dentry(dir, filename);
 586                if (sizeof_void_space)
 587                        break;
 588
 589                dir = (struct ext2_dirent *)((char *)dir + templength);
 590        }
 591
 592        /* make a pointer ready for creating next directory entry */
 593        templength = le16_to_cpu(dir->direntlen);
 594        totalbytes = totalbytes + templength;
 595        dir = (struct ext2_dirent *)((char *)dir + templength);
 596
 597        /* get the next available inode number */
 598        inodeno = ext4fs_get_new_inode_no();
 599        if (inodeno == -1) {
 600                printf("no inode left to assign\n");
 601                goto fail;
 602        }
 603        dir->inode = cpu_to_le32(inodeno);
 604        if (sizeof_void_space)
 605                dir->direntlen = cpu_to_le16(sizeof_void_space);
 606        else
 607                dir->direntlen = cpu_to_le16(fs->blksz - totalbytes);
 608
 609        dir->namelen = strlen(filename);
 610        dir->filetype = FILETYPE_REG;   /* regular file */
 611        temp_dir = (char *)dir;
 612        temp_dir = temp_dir + sizeof(struct ext2_dirent);
 613        memcpy(temp_dir, filename, strlen(filename));
 614
 615        /* update or write  the 1st block of root inode */
 616        if (ext4fs_put_metadata(root_first_block_buffer,
 617                                first_block_no_of_root))
 618                goto fail;
 619
 620fail:
 621        free(zero_buffer);
 622        free(root_first_block_buffer);
 623
 624        return inodeno;
 625}
 626
 627static int search_dir(struct ext2_inode *parent_inode, char *dirname)
 628{
 629        int status;
 630        int inodeno = 0;
 631        int offset;
 632        int blk_idx;
 633        long int blknr;
 634        char *block_buffer = NULL;
 635        struct ext2_dirent *dir = NULL;
 636        struct ext_filesystem *fs = get_fs();
 637        uint32_t directory_blocks;
 638        char *direntname;
 639
 640        directory_blocks = le32_to_cpu(parent_inode->size) >>
 641                LOG2_BLOCK_SIZE(ext4fs_root);
 642
 643        block_buffer = zalloc(fs->blksz);
 644        if (!block_buffer)
 645                goto fail;
 646
 647        /* get the block no allocated to a file */
 648        for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
 649                blknr = read_allocated_block(parent_inode, blk_idx);
 650                if (blknr <= 0)
 651                        goto fail;
 652
 653                /* read the directory block */
 654                status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
 655                                        0, fs->blksz, (char *)block_buffer);
 656                if (status == 0)
 657                        goto fail;
 658
 659                offset = 0;
 660                do {
 661                        if (offset & 3) {
 662                                printf("Badly aligned ext2_dirent\n");
 663                                break;
 664                        }
 665
 666                        dir = (struct ext2_dirent *)(block_buffer + offset);
 667                        direntname = (char*)(dir) + sizeof(struct ext2_dirent);
 668
 669                        int direntlen = le16_to_cpu(dir->direntlen);
 670                        if (direntlen < sizeof(struct ext2_dirent))
 671                                break;
 672
 673                        if (dir->inode && (strlen(dirname) == dir->namelen) &&
 674                            (strncmp(dirname, direntname, dir->namelen) == 0)) {
 675                                inodeno = le32_to_cpu(dir->inode);
 676                                break;
 677                        }
 678
 679                        offset += direntlen;
 680
 681                } while (offset < fs->blksz);
 682
 683                if (inodeno > 0) {
 684                        free(block_buffer);
 685                        return inodeno;
 686                }
 687        }
 688
 689fail:
 690        free(block_buffer);
 691
 692        return -1;
 693}
 694
 695static int find_dir_depth(char *dirname)
 696{
 697        char *token = strtok(dirname, "/");
 698        int count = 0;
 699        while (token != NULL) {
 700                token = strtok(NULL, "/");
 701                count++;
 702        }
 703        return count + 1 + 1;
 704        /*
 705         * for example  for string /home/temp
 706         * depth=home(1)+temp(1)+1 extra for NULL;
 707         * so count is 4;
 708         */
 709}
 710
 711static int parse_path(char **arr, char *dirname)
 712{
 713        char *token = strtok(dirname, "/");
 714        int i = 0;
 715
 716        /* add root */
 717        arr[i] = zalloc(strlen("/") + 1);
 718        if (!arr[i])
 719                return -ENOMEM;
 720        memcpy(arr[i++], "/", strlen("/"));
 721
 722        /* add each path entry after root */
 723        while (token != NULL) {
 724                arr[i] = zalloc(strlen(token) + 1);
 725                if (!arr[i])
 726                        return -ENOMEM;
 727                memcpy(arr[i++], token, strlen(token));
 728                token = strtok(NULL, "/");
 729        }
 730        arr[i] = NULL;
 731
 732        return 0;
 733}
 734
 735int ext4fs_iget(int inode_no, struct ext2_inode *inode)
 736{
 737        if (ext4fs_read_inode(ext4fs_root, inode_no, inode) == 0)
 738                return -1;
 739
 740        return 0;
 741}
 742
 743/*
 744 * Function: ext4fs_get_parent_inode_num
 745 * Return Value: inode Number of the parent directory of  file/Directory to be
 746 * created
 747 * dirname : Input parmater, input path name of the file/directory to be created
 748 * dname : Output parameter, to be filled with the name of the directory
 749 * extracted from dirname
 750 */
 751int ext4fs_get_parent_inode_num(const char *dirname, char *dname, int flags)
 752{
 753        int i;
 754        int depth = 0;
 755        int matched_inode_no;
 756        int result_inode_no = -1;
 757        char **ptr = NULL;
 758        char *depth_dirname = NULL;
 759        char *parse_dirname = NULL;
 760        struct ext2_inode *parent_inode = NULL;
 761        struct ext2_inode *first_inode = NULL;
 762        struct ext2_inode temp_inode;
 763
 764        if (*dirname != '/') {
 765                printf("Please supply Absolute path\n");
 766                return -1;
 767        }
 768
 769        /* TODO: input validation make equivalent to linux */
 770        depth_dirname = zalloc(strlen(dirname) + 1);
 771        if (!depth_dirname)
 772                return -ENOMEM;
 773
 774        memcpy(depth_dirname, dirname, strlen(dirname));
 775        depth = find_dir_depth(depth_dirname);
 776        parse_dirname = zalloc(strlen(dirname) + 1);
 777        if (!parse_dirname)
 778                goto fail;
 779        memcpy(parse_dirname, dirname, strlen(dirname));
 780
 781        /* allocate memory for each directory level */
 782        ptr = zalloc((depth) * sizeof(char *));
 783        if (!ptr)
 784                goto fail;
 785        if (parse_path(ptr, parse_dirname))
 786                goto fail;
 787        parent_inode = zalloc(sizeof(struct ext2_inode));
 788        if (!parent_inode)
 789                goto fail;
 790        first_inode = zalloc(sizeof(struct ext2_inode));
 791        if (!first_inode)
 792                goto fail;
 793        memcpy(parent_inode, ext4fs_root->inode, sizeof(struct ext2_inode));
 794        memcpy(first_inode, parent_inode, sizeof(struct ext2_inode));
 795        if (flags & F_FILE)
 796                result_inode_no = EXT2_ROOT_INO;
 797        for (i = 1; i < depth; i++) {
 798                matched_inode_no = search_dir(parent_inode, ptr[i]);
 799                if (matched_inode_no == -1) {
 800                        if (ptr[i + 1] == NULL && i == 1) {
 801                                result_inode_no = EXT2_ROOT_INO;
 802                                goto end;
 803                        } else {
 804                                if (ptr[i + 1] == NULL)
 805                                        break;
 806                                printf("Invalid path\n");
 807                                result_inode_no = -1;
 808                                goto fail;
 809                        }
 810                } else {
 811                        if (ptr[i + 1] != NULL) {
 812                                memset(parent_inode, '\0',
 813                                       sizeof(struct ext2_inode));
 814                                if (ext4fs_iget(matched_inode_no,
 815                                                parent_inode)) {
 816                                        result_inode_no = -1;
 817                                        goto fail;
 818                                }
 819                                result_inode_no = matched_inode_no;
 820                        } else {
 821                                break;
 822                        }
 823                }
 824        }
 825
 826end:
 827        if (i == 1)
 828                matched_inode_no = search_dir(first_inode, ptr[i]);
 829        else
 830                matched_inode_no = search_dir(parent_inode, ptr[i]);
 831
 832        if (matched_inode_no != -1) {
 833                ext4fs_iget(matched_inode_no, &temp_inode);
 834                if (le16_to_cpu(temp_inode.mode) & S_IFDIR) {
 835                        printf("It is a Directory\n");
 836                        result_inode_no = -1;
 837                        goto fail;
 838                }
 839        }
 840
 841        if (strlen(ptr[i]) > 256) {
 842                result_inode_no = -1;
 843                goto fail;
 844        }
 845        memcpy(dname, ptr[i], strlen(ptr[i]));
 846
 847fail:
 848        free(depth_dirname);
 849        free(parse_dirname);
 850        for (i = 0; i < depth; i++) {
 851                if (!ptr[i])
 852                        break;
 853                free(ptr[i]);
 854        }
 855        free(ptr);
 856        free(parent_inode);
 857        free(first_inode);
 858
 859        return result_inode_no;
 860}
 861
 862static int unlink_filename(char *filename, unsigned int blknr)
 863{
 864        int status;
 865        int inodeno = 0;
 866        int offset;
 867        char *block_buffer = NULL;
 868        struct ext2_dirent *dir = NULL;
 869        struct ext2_dirent *previous_dir;
 870        struct ext_filesystem *fs = get_fs();
 871        int ret = -1;
 872        char *direntname;
 873
 874        block_buffer = zalloc(fs->blksz);
 875        if (!block_buffer)
 876                return -ENOMEM;
 877
 878        /* read the directory block */
 879        status = ext4fs_devread((lbaint_t)blknr * fs->sect_perblk, 0,
 880                                fs->blksz, block_buffer);
 881        if (status == 0)
 882                goto fail;
 883
 884        offset = 0;
 885        do {
 886                if (offset & 3) {
 887                        printf("Badly aligned ext2_dirent\n");
 888                        break;
 889                }
 890
 891                previous_dir = dir;
 892                dir = (struct ext2_dirent *)(block_buffer + offset);
 893                direntname = (char *)(dir) + sizeof(struct ext2_dirent);
 894
 895                int direntlen = le16_to_cpu(dir->direntlen);
 896                if (direntlen < sizeof(struct ext2_dirent))
 897                        break;
 898
 899                if (dir->inode && (strlen(filename) == dir->namelen) &&
 900                    (strncmp(direntname, filename, dir->namelen) == 0)) {
 901                        inodeno = le32_to_cpu(dir->inode);
 902                        break;
 903                }
 904
 905                offset += direntlen;
 906
 907        } while (offset < fs->blksz);
 908
 909        if (inodeno > 0) {
 910                printf("file found, deleting\n");
 911                if (ext4fs_log_journal(block_buffer, blknr))
 912                        goto fail;
 913
 914                if (previous_dir) {
 915                        /* merge dir entry with predecessor */
 916                        uint16_t new_len;
 917                        new_len = le16_to_cpu(previous_dir->direntlen);
 918                        new_len += le16_to_cpu(dir->direntlen);
 919                        previous_dir->direntlen = cpu_to_le16(new_len);
 920                } else {
 921                        /* invalidate dir entry */
 922                        dir->inode = 0;
 923                }
 924                if (ext4fs_put_metadata(block_buffer, blknr))
 925                        goto fail;
 926                ret = inodeno;
 927        }
 928fail:
 929        free(block_buffer);
 930
 931        return ret;
 932}
 933
 934int ext4fs_filename_unlink(char *filename)
 935{
 936        int blk_idx;
 937        long int blknr = -1;
 938        int inodeno = -1;
 939        uint32_t directory_blocks;
 940
 941        directory_blocks = le32_to_cpu(g_parent_inode->size) >>
 942                LOG2_BLOCK_SIZE(ext4fs_root);
 943
 944        /* read the block no allocated to a file */
 945        for (blk_idx = 0; blk_idx < directory_blocks; blk_idx++) {
 946                blknr = read_allocated_block(g_parent_inode, blk_idx);
 947                if (blknr <= 0)
 948                        break;
 949                inodeno = unlink_filename(filename, blknr);
 950                if (inodeno != -1)
 951                        return inodeno;
 952        }
 953
 954        return -1;
 955}
 956
 957uint32_t ext4fs_get_new_blk_no(void)
 958{
 959        short i;
 960        short status;
 961        int remainder;
 962        unsigned int bg_idx;
 963        static int prev_bg_bitmap_index = -1;
 964        unsigned int blk_per_grp = le32_to_cpu(ext4fs_root->sblock.blocks_per_group);
 965        struct ext_filesystem *fs = get_fs();
 966        char *journal_buffer = zalloc(fs->blksz);
 967        char *zero_buffer = zalloc(fs->blksz);
 968        if (!journal_buffer || !zero_buffer)
 969                goto fail;
 970
 971        if (fs->first_pass_bbmap == 0) {
 972                for (i = 0; i < fs->no_blkgrp; i++) {
 973                        struct ext2_block_group *bgd = NULL;
 974                        bgd = ext4fs_get_group_descriptor(fs, i);
 975                        if (ext4fs_bg_get_free_blocks(bgd, fs)) {
 976                                uint16_t bg_flags = ext4fs_bg_get_flags(bgd);
 977                                uint64_t b_bitmap_blk =
 978                                        ext4fs_bg_get_block_id(bgd, fs);
 979                                if (bg_flags & EXT4_BG_BLOCK_UNINIT) {
 980                                        memcpy(fs->blk_bmaps[i], zero_buffer,
 981                                               fs->blksz);
 982                                        put_ext4(b_bitmap_blk * fs->blksz,
 983                                                 fs->blk_bmaps[i], fs->blksz);
 984                                        bg_flags &= ~EXT4_BG_BLOCK_UNINIT;
 985                                        ext4fs_bg_set_flags(bgd, bg_flags);
 986                                }
 987                                fs->curr_blkno =
 988                                    _get_new_blk_no(fs->blk_bmaps[i]);
 989                                if (fs->curr_blkno == -1)
 990                                        /* block bitmap is completely filled */
 991                                        continue;
 992                                fs->curr_blkno = fs->curr_blkno +
 993                                                (i * fs->blksz * 8);
 994                                fs->first_pass_bbmap++;
 995                                ext4fs_bg_free_blocks_dec(bgd, fs);
 996                                ext4fs_sb_free_blocks_dec(fs->sb);
 997                                status = ext4fs_devread(b_bitmap_blk *
 998                                                        fs->sect_perblk,
 999                                                        0, fs->blksz,
1000                                                        journal_buffer);
1001                                if (status == 0)
1002                                        goto fail;
1003                                if (ext4fs_log_journal(journal_buffer,
1004                                                       b_bitmap_blk))
1005                                        goto fail;
1006                                goto success;
1007                        } else {
1008                                debug("no space left on block group %d\n", i);
1009                        }
1010                }
1011
1012                goto fail;
1013        } else {
1014                fs->curr_blkno++;
1015restart:
1016                /* get the blockbitmap index respective to blockno */
1017                bg_idx = fs->curr_blkno / blk_per_grp;
1018                if (fs->blksz == 1024) {
1019                        remainder = fs->curr_blkno % blk_per_grp;
1020                        if (!remainder)
1021                                bg_idx--;
1022                }
1023
1024                /*
1025                 * To skip completely filled block group bitmaps
1026                 * Optimize the block allocation
1027                 */
1028                if (bg_idx >= fs->no_blkgrp)
1029                        goto fail;
1030
1031                struct ext2_block_group *bgd = NULL;
1032                bgd = ext4fs_get_group_descriptor(fs, bg_idx);
1033                if (ext4fs_bg_get_free_blocks(bgd, fs) == 0) {
1034                        debug("block group %u is full. Skipping\n", bg_idx);
1035                        fs->curr_blkno = (bg_idx + 1) * blk_per_grp;
1036                        if (fs->blksz == 1024)
1037                                fs->curr_blkno += 1;
1038                        goto restart;
1039                }
1040
1041                uint16_t bg_flags = ext4fs_bg_get_flags(bgd);
1042                uint64_t b_bitmap_blk = ext4fs_bg_get_block_id(bgd, fs);
1043                if (bg_flags & EXT4_BG_BLOCK_UNINIT) {
1044                        memcpy(fs->blk_bmaps[bg_idx], zero_buffer, fs->blksz);
1045                        put_ext4(b_bitmap_blk * fs->blksz,
1046                                 zero_buffer, fs->blksz);
1047                        bg_flags &= ~EXT4_BG_BLOCK_UNINIT;
1048                        ext4fs_bg_set_flags(bgd, bg_flags);
1049                }
1050
1051                if (ext4fs_set_block_bmap(fs->curr_blkno, fs->blk_bmaps[bg_idx],
1052                                   bg_idx) != 0) {
1053                        debug("going for restart for the block no %ld %u\n",
1054                              fs->curr_blkno, bg_idx);
1055                        fs->curr_blkno++;
1056                        goto restart;
1057                }
1058
1059                /* journal backup */
1060                if (prev_bg_bitmap_index != bg_idx) {
1061                        status = ext4fs_devread(b_bitmap_blk * fs->sect_perblk,
1062                                                0, fs->blksz, journal_buffer);
1063                        if (status == 0)
1064                                goto fail;
1065                        if (ext4fs_log_journal(journal_buffer, b_bitmap_blk))
1066                                goto fail;
1067
1068                        prev_bg_bitmap_index = bg_idx;
1069                }
1070                ext4fs_bg_free_blocks_dec(bgd, fs);
1071                ext4fs_sb_free_blocks_dec(fs->sb);
1072                goto success;
1073        }
1074success:
1075        free(journal_buffer);
1076        free(zero_buffer);
1077
1078        return fs->curr_blkno;
1079fail:
1080        free(journal_buffer);
1081        free(zero_buffer);
1082
1083        return -1;
1084}
1085
1086int ext4fs_get_new_inode_no(void)
1087{
1088        short i;
1089        short status;
1090        unsigned int ibmap_idx;
1091        static int prev_inode_bitmap_index = -1;
1092        unsigned int inodes_per_grp = le32_to_cpu(ext4fs_root->sblock.inodes_per_group);
1093        struct ext_filesystem *fs = get_fs();
1094        char *journal_buffer = zalloc(fs->blksz);
1095        char *zero_buffer = zalloc(fs->blksz);
1096        if (!journal_buffer || !zero_buffer)
1097                goto fail;
1098        int has_gdt_chksum = le32_to_cpu(fs->sb->feature_ro_compat) &
1099                EXT4_FEATURE_RO_COMPAT_GDT_CSUM ? 1 : 0;
1100
1101        if (fs->first_pass_ibmap == 0) {
1102                for (i = 0; i < fs->no_blkgrp; i++) {
1103                        uint32_t free_inodes;
1104                        struct ext2_block_group *bgd = NULL;
1105                        bgd = ext4fs_get_group_descriptor(fs, i);
1106                        free_inodes = ext4fs_bg_get_free_inodes(bgd, fs);
1107                        if (free_inodes) {
1108                                uint16_t bg_flags = ext4fs_bg_get_flags(bgd);
1109                                uint64_t i_bitmap_blk =
1110                                        ext4fs_bg_get_inode_id(bgd, fs);
1111                                if (has_gdt_chksum)
1112                                        bgd->bg_itable_unused = free_inodes;
1113                                if (bg_flags & EXT4_BG_INODE_UNINIT) {
1114                                        put_ext4(i_bitmap_blk * fs->blksz,
1115                                                 zero_buffer, fs->blksz);
1116                                        bg_flags &= ~EXT4_BG_INODE_UNINIT;
1117                                        ext4fs_bg_set_flags(bgd, bg_flags);
1118                                        memcpy(fs->inode_bmaps[i],
1119                                               zero_buffer, fs->blksz);
1120                                }
1121                                fs->curr_inode_no =
1122                                    _get_new_inode_no(fs->inode_bmaps[i]);
1123                                if (fs->curr_inode_no == -1)
1124                                        /* inode bitmap is completely filled */
1125                                        continue;
1126                                fs->curr_inode_no = fs->curr_inode_no +
1127                                                        (i * inodes_per_grp);
1128                                fs->first_pass_ibmap++;
1129                                ext4fs_bg_free_inodes_dec(bgd, fs);
1130                                if (has_gdt_chksum)
1131                                        ext4fs_bg_itable_unused_dec(bgd, fs);
1132                                ext4fs_sb_free_inodes_dec(fs->sb);
1133                                status = ext4fs_devread(i_bitmap_blk *
1134                                                        fs->sect_perblk,
1135                                                        0, fs->blksz,
1136                                                        journal_buffer);
1137                                if (status == 0)
1138                                        goto fail;
1139                                if (ext4fs_log_journal(journal_buffer,
1140                                                       i_bitmap_blk))
1141                                        goto fail;
1142                                goto success;
1143                        } else
1144                                debug("no inode left on block group %d\n", i);
1145                }
1146                goto fail;
1147        } else {
1148restart:
1149                fs->curr_inode_no++;
1150                /* get the blockbitmap index respective to blockno */
1151                ibmap_idx = fs->curr_inode_no / inodes_per_grp;
1152                struct ext2_block_group *bgd =
1153                        ext4fs_get_group_descriptor(fs, ibmap_idx);
1154                uint16_t bg_flags = ext4fs_bg_get_flags(bgd);
1155                uint64_t i_bitmap_blk = ext4fs_bg_get_inode_id(bgd, fs);
1156
1157                if (bg_flags & EXT4_BG_INODE_UNINIT) {
1158                        put_ext4(i_bitmap_blk * fs->blksz,
1159                                 zero_buffer, fs->blksz);
1160                        bg_flags &= ~EXT4_BG_INODE_UNINIT;
1161                        ext4fs_bg_set_flags(bgd, bg_flags);
1162                        memcpy(fs->inode_bmaps[ibmap_idx], zero_buffer,
1163                                fs->blksz);
1164                }
1165
1166                if (ext4fs_set_inode_bmap(fs->curr_inode_no,
1167                                          fs->inode_bmaps[ibmap_idx],
1168                                          ibmap_idx) != 0) {
1169                        debug("going for restart for the block no %d %u\n",
1170                              fs->curr_inode_no, ibmap_idx);
1171                        goto restart;
1172                }
1173
1174                /* journal backup */
1175                if (prev_inode_bitmap_index != ibmap_idx) {
1176                        status = ext4fs_devread(i_bitmap_blk * fs->sect_perblk,
1177                                                0, fs->blksz, journal_buffer);
1178                        if (status == 0)
1179                                goto fail;
1180                        if (ext4fs_log_journal(journal_buffer,
1181                                                le32_to_cpu(bgd->inode_id)))
1182                                goto fail;
1183                        prev_inode_bitmap_index = ibmap_idx;
1184                }
1185                ext4fs_bg_free_inodes_dec(bgd, fs);
1186                if (has_gdt_chksum)
1187                        bgd->bg_itable_unused = bgd->free_inodes;
1188                ext4fs_sb_free_inodes_dec(fs->sb);
1189                goto success;
1190        }
1191
1192success:
1193        free(journal_buffer);
1194        free(zero_buffer);
1195
1196        return fs->curr_inode_no;
1197fail:
1198        free(journal_buffer);
1199        free(zero_buffer);
1200
1201        return -1;
1202
1203}
1204
1205
1206static void alloc_single_indirect_block(struct ext2_inode *file_inode,
1207                                        unsigned int *total_remaining_blocks,
1208                                        unsigned int *no_blks_reqd)
1209{
1210        short i;
1211        short status;
1212        long int actual_block_no;
1213        long int si_blockno;
1214        /* si :single indirect */
1215        __le32 *si_buffer = NULL;
1216        __le32 *si_start_addr = NULL;
1217        struct ext_filesystem *fs = get_fs();
1218
1219        if (*total_remaining_blocks != 0) {
1220                si_buffer = zalloc(fs->blksz);
1221                if (!si_buffer) {
1222                        printf("No Memory\n");
1223                        return;
1224                }
1225                si_start_addr = si_buffer;
1226                si_blockno = ext4fs_get_new_blk_no();
1227                if (si_blockno == -1) {
1228                        printf("no block left to assign\n");
1229                        goto fail;
1230                }
1231                (*no_blks_reqd)++;
1232                debug("SIPB %ld: %u\n", si_blockno, *total_remaining_blocks);
1233
1234                status = ext4fs_devread((lbaint_t)si_blockno * fs->sect_perblk,
1235                                        0, fs->blksz, (char *)si_buffer);
1236                memset(si_buffer, '\0', fs->blksz);
1237                if (status == 0)
1238                        goto fail;
1239
1240                for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
1241                        actual_block_no = ext4fs_get_new_blk_no();
1242                        if (actual_block_no == -1) {
1243                                printf("no block left to assign\n");
1244                                goto fail;
1245                        }
1246                        *si_buffer = cpu_to_le32(actual_block_no);
1247                        debug("SIAB %u: %u\n", *si_buffer,
1248                                *total_remaining_blocks);
1249
1250                        si_buffer++;
1251                        (*total_remaining_blocks)--;
1252                        if (*total_remaining_blocks == 0)
1253                                break;
1254                }
1255
1256                /* write the block to disk */
1257                put_ext4(((uint64_t) ((uint64_t)si_blockno * (uint64_t)fs->blksz)),
1258                         si_start_addr, fs->blksz);
1259                file_inode->b.blocks.indir_block = cpu_to_le32(si_blockno);
1260        }
1261fail:
1262        free(si_start_addr);
1263}
1264
1265static void alloc_double_indirect_block(struct ext2_inode *file_inode,
1266                                        unsigned int *total_remaining_blocks,
1267                                        unsigned int *no_blks_reqd)
1268{
1269        short i;
1270        short j;
1271        short status;
1272        long int actual_block_no;
1273        /* di:double indirect */
1274        long int di_blockno_parent;
1275        long int di_blockno_child;
1276        __le32 *di_parent_buffer = NULL;
1277        __le32 *di_child_buff = NULL;
1278        __le32 *di_block_start_addr = NULL;
1279        __le32 *di_child_buff_start = NULL;
1280        struct ext_filesystem *fs = get_fs();
1281
1282        if (*total_remaining_blocks != 0) {
1283                /* double indirect parent block connecting to inode */
1284                di_blockno_parent = ext4fs_get_new_blk_no();
1285                if (di_blockno_parent == -1) {
1286                        printf("no block left to assign\n");
1287                        goto fail;
1288                }
1289                di_parent_buffer = zalloc(fs->blksz);
1290                if (!di_parent_buffer)
1291                        goto fail;
1292
1293                di_block_start_addr = di_parent_buffer;
1294                (*no_blks_reqd)++;
1295                debug("DIPB %ld: %u\n", di_blockno_parent,
1296                      *total_remaining_blocks);
1297
1298                status = ext4fs_devread((lbaint_t)di_blockno_parent *
1299                                        fs->sect_perblk, 0,
1300                                        fs->blksz, (char *)di_parent_buffer);
1301
1302                if (!status) {
1303                        printf("%s: Device read error!\n", __func__);
1304                        goto fail;
1305                }
1306                memset(di_parent_buffer, '\0', fs->blksz);
1307
1308                /*
1309                 * start:for each double indirect parent
1310                 * block create one more block
1311                 */
1312                for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
1313                        di_blockno_child = ext4fs_get_new_blk_no();
1314                        if (di_blockno_child == -1) {
1315                                printf("no block left to assign\n");
1316                                goto fail;
1317                        }
1318                        di_child_buff = zalloc(fs->blksz);
1319                        if (!di_child_buff)
1320                                goto fail;
1321
1322                        di_child_buff_start = di_child_buff;
1323                        *di_parent_buffer = cpu_to_le32(di_blockno_child);
1324                        di_parent_buffer++;
1325                        (*no_blks_reqd)++;
1326                        debug("DICB %ld: %u\n", di_blockno_child,
1327                              *total_remaining_blocks);
1328
1329                        status = ext4fs_devread((lbaint_t)di_blockno_child *
1330                                                fs->sect_perblk, 0,
1331                                                fs->blksz,
1332                                                (char *)di_child_buff);
1333
1334                        if (!status) {
1335                                printf("%s: Device read error!\n", __func__);
1336                                goto fail;
1337                        }
1338                        memset(di_child_buff, '\0', fs->blksz);
1339                        /* filling of actual datablocks for each child */
1340                        for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
1341                                actual_block_no = ext4fs_get_new_blk_no();
1342                                if (actual_block_no == -1) {
1343                                        printf("no block left to assign\n");
1344                                        goto fail;
1345                                }
1346                                *di_child_buff = cpu_to_le32(actual_block_no);
1347                                debug("DIAB %ld: %u\n", actual_block_no,
1348                                      *total_remaining_blocks);
1349
1350                                di_child_buff++;
1351                                (*total_remaining_blocks)--;
1352                                if (*total_remaining_blocks == 0)
1353                                        break;
1354                        }
1355                        /* write the block  table */
1356                        put_ext4(((uint64_t) ((uint64_t)di_blockno_child * (uint64_t)fs->blksz)),
1357                                 di_child_buff_start, fs->blksz);
1358                        free(di_child_buff_start);
1359                        di_child_buff_start = NULL;
1360
1361                        if (*total_remaining_blocks == 0)
1362                                break;
1363                }
1364                put_ext4(((uint64_t) ((uint64_t)di_blockno_parent * (uint64_t)fs->blksz)),
1365                         di_block_start_addr, fs->blksz);
1366                file_inode->b.blocks.double_indir_block = cpu_to_le32(di_blockno_parent);
1367        }
1368fail:
1369        free(di_block_start_addr);
1370}
1371
1372static void alloc_triple_indirect_block(struct ext2_inode *file_inode,
1373                                        unsigned int *total_remaining_blocks,
1374                                        unsigned int *no_blks_reqd)
1375{
1376        short i;
1377        short j;
1378        short k;
1379        long int actual_block_no;
1380        /* ti: Triple Indirect */
1381        long int ti_gp_blockno;
1382        long int ti_parent_blockno;
1383        long int ti_child_blockno;
1384        __le32 *ti_gp_buff = NULL;
1385        __le32 *ti_parent_buff = NULL;
1386        __le32 *ti_child_buff = NULL;
1387        __le32 *ti_gp_buff_start_addr = NULL;
1388        __le32 *ti_pbuff_start_addr = NULL;
1389        __le32 *ti_cbuff_start_addr = NULL;
1390        struct ext_filesystem *fs = get_fs();
1391        if (*total_remaining_blocks != 0) {
1392                /* triple indirect grand parent block connecting to inode */
1393                ti_gp_blockno = ext4fs_get_new_blk_no();
1394                if (ti_gp_blockno == -1) {
1395                        printf("no block left to assign\n");
1396                        return;
1397                }
1398                ti_gp_buff = zalloc(fs->blksz);
1399                if (!ti_gp_buff)
1400                        return;
1401
1402                ti_gp_buff_start_addr = ti_gp_buff;
1403                (*no_blks_reqd)++;
1404                debug("TIGPB %ld: %u\n", ti_gp_blockno,
1405                      *total_remaining_blocks);
1406
1407                /* for each 4 byte grand parent entry create one more block */
1408                for (i = 0; i < (fs->blksz / sizeof(int)); i++) {
1409                        ti_parent_blockno = ext4fs_get_new_blk_no();
1410                        if (ti_parent_blockno == -1) {
1411                                printf("no block left to assign\n");
1412                                goto fail;
1413                        }
1414                        ti_parent_buff = zalloc(fs->blksz);
1415                        if (!ti_parent_buff)
1416                                goto fail;
1417
1418                        ti_pbuff_start_addr = ti_parent_buff;
1419                        *ti_gp_buff = cpu_to_le32(ti_parent_blockno);
1420                        ti_gp_buff++;
1421                        (*no_blks_reqd)++;
1422                        debug("TIPB %ld: %u\n", ti_parent_blockno,
1423                              *total_remaining_blocks);
1424
1425                        /* for each 4 byte entry parent create one more block */
1426                        for (j = 0; j < (fs->blksz / sizeof(int)); j++) {
1427                                ti_child_blockno = ext4fs_get_new_blk_no();
1428                                if (ti_child_blockno == -1) {
1429                                        printf("no block left assign\n");
1430                                        goto fail1;
1431                                }
1432                                ti_child_buff = zalloc(fs->blksz);
1433                                if (!ti_child_buff)
1434                                        goto fail1;
1435
1436                                ti_cbuff_start_addr = ti_child_buff;
1437                                *ti_parent_buff = cpu_to_le32(ti_child_blockno);
1438                                ti_parent_buff++;
1439                                (*no_blks_reqd)++;
1440                                debug("TICB %ld: %u\n", ti_parent_blockno,
1441                                      *total_remaining_blocks);
1442
1443                                /* fill actual datablocks for each child */
1444                                for (k = 0; k < (fs->blksz / sizeof(int));
1445                                        k++) {
1446                                        actual_block_no =
1447                                            ext4fs_get_new_blk_no();
1448                                        if (actual_block_no == -1) {
1449                                                printf("no block left\n");
1450                                                free(ti_cbuff_start_addr);
1451                                                goto fail1;
1452                                        }
1453                                        *ti_child_buff = cpu_to_le32(actual_block_no);
1454                                        debug("TIAB %ld: %u\n", actual_block_no,
1455                                              *total_remaining_blocks);
1456
1457                                        ti_child_buff++;
1458                                        (*total_remaining_blocks)--;
1459                                        if (*total_remaining_blocks == 0)
1460                                                break;
1461                                }
1462                                /* write the child block */
1463                                put_ext4(((uint64_t) ((uint64_t)ti_child_blockno *
1464                                                      (uint64_t)fs->blksz)),
1465                                         ti_cbuff_start_addr, fs->blksz);
1466                                free(ti_cbuff_start_addr);
1467
1468                                if (*total_remaining_blocks == 0)
1469                                        break;
1470                        }
1471                        /* write the parent block */
1472                        put_ext4(((uint64_t) ((uint64_t)ti_parent_blockno * (uint64_t)fs->blksz)),
1473                                 ti_pbuff_start_addr, fs->blksz);
1474                        free(ti_pbuff_start_addr);
1475
1476                        if (*total_remaining_blocks == 0)
1477                                break;
1478                }
1479                /* write the grand parent block */
1480                put_ext4(((uint64_t) ((uint64_t)ti_gp_blockno * (uint64_t)fs->blksz)),
1481                         ti_gp_buff_start_addr, fs->blksz);
1482                file_inode->b.blocks.triple_indir_block = cpu_to_le32(ti_gp_blockno);
1483                free(ti_gp_buff_start_addr);
1484                return;
1485        }
1486fail1:
1487        free(ti_pbuff_start_addr);
1488fail:
1489        free(ti_gp_buff_start_addr);
1490}
1491
1492void ext4fs_allocate_blocks(struct ext2_inode *file_inode,
1493                                unsigned int total_remaining_blocks,
1494                                unsigned int *total_no_of_block)
1495{
1496        short i;
1497        long int direct_blockno;
1498        unsigned int no_blks_reqd = 0;
1499
1500        /* allocation of direct blocks */
1501        for (i = 0; total_remaining_blocks && i < INDIRECT_BLOCKS; i++) {
1502                direct_blockno = ext4fs_get_new_blk_no();
1503                if (direct_blockno == -1) {
1504                        printf("no block left to assign\n");
1505                        return;
1506                }
1507                file_inode->b.blocks.dir_blocks[i] = cpu_to_le32(direct_blockno);
1508                debug("DB %ld: %u\n", direct_blockno, total_remaining_blocks);
1509
1510                total_remaining_blocks--;
1511        }
1512
1513        alloc_single_indirect_block(file_inode, &total_remaining_blocks,
1514                                    &no_blks_reqd);
1515        alloc_double_indirect_block(file_inode, &total_remaining_blocks,
1516                                    &no_blks_reqd);
1517        alloc_triple_indirect_block(file_inode, &total_remaining_blocks,
1518                                    &no_blks_reqd);
1519        *total_no_of_block += no_blks_reqd;
1520}
1521
1522#endif
1523
1524static struct ext4_extent_header *ext4fs_get_extent_block
1525        (struct ext2_data *data, char *buf,
1526                struct ext4_extent_header *ext_block,
1527                uint32_t fileblock, int log2_blksz)
1528{
1529        struct ext4_extent_idx *index;
1530        unsigned long long block;
1531        int blksz = EXT2_BLOCK_SIZE(data);
1532        int i;
1533
1534        while (1) {
1535                index = (struct ext4_extent_idx *)(ext_block + 1);
1536
1537                if (le16_to_cpu(ext_block->eh_magic) != EXT4_EXT_MAGIC)
1538                        return NULL;
1539
1540                if (ext_block->eh_depth == 0)
1541                        return ext_block;
1542                i = -1;
1543                do {
1544                        i++;
1545                        if (i >= le16_to_cpu(ext_block->eh_entries))
1546                                break;
1547                } while (fileblock >= le32_to_cpu(index[i].ei_block));
1548
1549                if (--i < 0)
1550                        return NULL;
1551
1552                block = le16_to_cpu(index[i].ei_leaf_hi);
1553                block = (block << 32) + le32_to_cpu(index[i].ei_leaf_lo);
1554
1555                if (ext4fs_devread((lbaint_t)block << log2_blksz, 0, blksz,
1556                                   buf))
1557                        ext_block = (struct ext4_extent_header *)buf;
1558                else
1559                        return NULL;
1560        }
1561}
1562
1563static int ext4fs_blockgroup
1564        (struct ext2_data *data, int group, struct ext2_block_group *blkgrp)
1565{
1566        long int blkno;
1567        unsigned int blkoff, desc_per_blk;
1568        int log2blksz = get_fs()->dev_desc->log2blksz;
1569        int desc_size = get_fs()->gdsize;
1570
1571        desc_per_blk = EXT2_BLOCK_SIZE(data) / desc_size;
1572
1573        blkno = le32_to_cpu(data->sblock.first_data_block) + 1 +
1574                        group / desc_per_blk;
1575        blkoff = (group % desc_per_blk) * desc_size;
1576
1577        debug("ext4fs read %d group descriptor (blkno %ld blkoff %u)\n",
1578              group, blkno, blkoff);
1579
1580        return ext4fs_devread((lbaint_t)blkno <<
1581                              (LOG2_BLOCK_SIZE(data) - log2blksz),
1582                              blkoff, desc_size, (char *)blkgrp);
1583}
1584
1585int ext4fs_read_inode(struct ext2_data *data, int ino, struct ext2_inode *inode)
1586{
1587        struct ext2_block_group blkgrp;
1588        struct ext2_sblock *sblock = &data->sblock;
1589        struct ext_filesystem *fs = get_fs();
1590        int log2blksz = get_fs()->dev_desc->log2blksz;
1591        int inodes_per_block, status;
1592        long int blkno;
1593        unsigned int blkoff;
1594
1595        /* It is easier to calculate if the first inode is 0. */
1596        ino--;
1597        status = ext4fs_blockgroup(data, ino / le32_to_cpu
1598                                   (sblock->inodes_per_group), &blkgrp);
1599        if (status == 0)
1600                return 0;
1601
1602        inodes_per_block = EXT2_BLOCK_SIZE(data) / fs->inodesz;
1603        blkno = ext4fs_bg_get_inode_table_id(&blkgrp, fs) +
1604            (ino % le32_to_cpu(sblock->inodes_per_group)) / inodes_per_block;
1605        blkoff = (ino % inodes_per_block) * fs->inodesz;
1606        /* Read the inode. */
1607        status = ext4fs_devread((lbaint_t)blkno << (LOG2_BLOCK_SIZE(data) -
1608                                log2blksz), blkoff,
1609                                sizeof(struct ext2_inode), (char *)inode);
1610        if (status == 0)
1611                return 0;
1612
1613        return 1;
1614}
1615
1616long int read_allocated_block(struct ext2_inode *inode, int fileblock)
1617{
1618        long int blknr;
1619        int blksz;
1620        int log2_blksz;
1621        int status;
1622        long int rblock;
1623        long int perblock_parent;
1624        long int perblock_child;
1625        unsigned long long start;
1626        /* get the blocksize of the filesystem */
1627        blksz = EXT2_BLOCK_SIZE(ext4fs_root);
1628        log2_blksz = LOG2_BLOCK_SIZE(ext4fs_root)
1629                - get_fs()->dev_desc->log2blksz;
1630
1631        if (le32_to_cpu(inode->flags) & EXT4_EXTENTS_FL) {
1632                long int startblock, endblock;
1633                char *buf = zalloc(blksz);
1634                if (!buf)
1635                        return -ENOMEM;
1636                struct ext4_extent_header *ext_block;
1637                struct ext4_extent *extent;
1638                int i;
1639                ext_block =
1640                        ext4fs_get_extent_block(ext4fs_root, buf,
1641                                                (struct ext4_extent_header *)
1642                                                inode->b.blocks.dir_blocks,
1643                                                fileblock, log2_blksz);
1644                if (!ext_block) {
1645                        printf("invalid extent block\n");
1646                        free(buf);
1647                        return -EINVAL;
1648                }
1649
1650                extent = (struct ext4_extent *)(ext_block + 1);
1651
1652                for (i = 0; i < le16_to_cpu(ext_block->eh_entries); i++) {
1653                        startblock = le32_to_cpu(extent[i].ee_block);
1654                        endblock = startblock + le16_to_cpu(extent[i].ee_len);
1655
1656                        if (startblock > fileblock) {
1657                                /* Sparse file */
1658                                free(buf);
1659                                return 0;
1660
1661                        } else if (fileblock < endblock) {
1662                                start = le16_to_cpu(extent[i].ee_start_hi);
1663                                start = (start << 32) +
1664                                        le32_to_cpu(extent[i].ee_start_lo);
1665                                free(buf);
1666                                return (fileblock - startblock) + start;
1667                        }
1668                }
1669
1670                free(buf);
1671                return 0;
1672        }
1673
1674        /* Direct blocks. */
1675        if (fileblock < INDIRECT_BLOCKS)
1676                blknr = le32_to_cpu(inode->b.blocks.dir_blocks[fileblock]);
1677
1678        /* Indirect. */
1679        else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
1680                if (ext4fs_indir1_block == NULL) {
1681                        ext4fs_indir1_block = zalloc(blksz);
1682                        if (ext4fs_indir1_block == NULL) {
1683                                printf("** SI ext2fs read block (indir 1)"
1684                                        "malloc failed. **\n");
1685                                return -1;
1686                        }
1687                        ext4fs_indir1_size = blksz;
1688                        ext4fs_indir1_blkno = -1;
1689                }
1690                if (blksz != ext4fs_indir1_size) {
1691                        free(ext4fs_indir1_block);
1692                        ext4fs_indir1_block = NULL;
1693                        ext4fs_indir1_size = 0;
1694                        ext4fs_indir1_blkno = -1;
1695                        ext4fs_indir1_block = zalloc(blksz);
1696                        if (ext4fs_indir1_block == NULL) {
1697                                printf("** SI ext2fs read block (indir 1):"
1698                                        "malloc failed. **\n");
1699                                return -1;
1700                        }
1701                        ext4fs_indir1_size = blksz;
1702                }
1703                if ((le32_to_cpu(inode->b.blocks.indir_block) <<
1704                     log2_blksz) != ext4fs_indir1_blkno) {
1705                        status =
1706                            ext4fs_devread((lbaint_t)le32_to_cpu
1707                                           (inode->b.blocks.
1708                                            indir_block) << log2_blksz, 0,
1709                                           blksz, (char *)ext4fs_indir1_block);
1710                        if (status == 0) {
1711                                printf("** SI ext2fs read block (indir 1)"
1712                                        "failed. **\n");
1713                                return -1;
1714                        }
1715                        ext4fs_indir1_blkno =
1716                                le32_to_cpu(inode->b.blocks.
1717                                               indir_block) << log2_blksz;
1718                }
1719                blknr = le32_to_cpu(ext4fs_indir1_block
1720                                      [fileblock - INDIRECT_BLOCKS]);
1721        }
1722        /* Double indirect. */
1723        else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4 *
1724                                        (blksz / 4 + 1)))) {
1725
1726                long int perblock = blksz / 4;
1727                long int rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4);
1728
1729                if (ext4fs_indir1_block == NULL) {
1730                        ext4fs_indir1_block = zalloc(blksz);
1731                        if (ext4fs_indir1_block == NULL) {
1732                                printf("** DI ext2fs read block (indir 2 1)"
1733                                        "malloc failed. **\n");
1734                                return -1;
1735                        }
1736                        ext4fs_indir1_size = blksz;
1737                        ext4fs_indir1_blkno = -1;
1738                }
1739                if (blksz != ext4fs_indir1_size) {
1740                        free(ext4fs_indir1_block);
1741                        ext4fs_indir1_block = NULL;
1742                        ext4fs_indir1_size = 0;
1743                        ext4fs_indir1_blkno = -1;
1744                        ext4fs_indir1_block = zalloc(blksz);
1745                        if (ext4fs_indir1_block == NULL) {
1746                                printf("** DI ext2fs read block (indir 2 1)"
1747                                        "malloc failed. **\n");
1748                                return -1;
1749                        }
1750                        ext4fs_indir1_size = blksz;
1751                }
1752                if ((le32_to_cpu(inode->b.blocks.double_indir_block) <<
1753                     log2_blksz) != ext4fs_indir1_blkno) {
1754                        status =
1755                            ext4fs_devread((lbaint_t)le32_to_cpu
1756                                           (inode->b.blocks.
1757                                            double_indir_block) << log2_blksz,
1758                                           0, blksz,
1759                                           (char *)ext4fs_indir1_block);
1760                        if (status == 0) {
1761                                printf("** DI ext2fs read block (indir 2 1)"
1762                                        "failed. **\n");
1763                                return -1;
1764                        }
1765                        ext4fs_indir1_blkno =
1766                            le32_to_cpu(inode->b.blocks.double_indir_block) <<
1767                            log2_blksz;
1768                }
1769
1770                if (ext4fs_indir2_block == NULL) {
1771                        ext4fs_indir2_block = zalloc(blksz);
1772                        if (ext4fs_indir2_block == NULL) {
1773                                printf("** DI ext2fs read block (indir 2 2)"
1774                                        "malloc failed. **\n");
1775                                return -1;
1776                        }
1777                        ext4fs_indir2_size = blksz;
1778                        ext4fs_indir2_blkno = -1;
1779                }
1780                if (blksz != ext4fs_indir2_size) {
1781                        free(ext4fs_indir2_block);
1782                        ext4fs_indir2_block = NULL;
1783                        ext4fs_indir2_size = 0;
1784                        ext4fs_indir2_blkno = -1;
1785                        ext4fs_indir2_block = zalloc(blksz);
1786                        if (ext4fs_indir2_block == NULL) {
1787                                printf("** DI ext2fs read block (indir 2 2)"
1788                                        "malloc failed. **\n");
1789                                return -1;
1790                        }
1791                        ext4fs_indir2_size = blksz;
1792                }
1793                if ((le32_to_cpu(ext4fs_indir1_block[rblock / perblock]) <<
1794                     log2_blksz) != ext4fs_indir2_blkno) {
1795                        status = ext4fs_devread((lbaint_t)le32_to_cpu
1796                                                (ext4fs_indir1_block
1797                                                 [rblock /
1798                                                  perblock]) << log2_blksz, 0,
1799                                                blksz,
1800                                                (char *)ext4fs_indir2_block);
1801                        if (status == 0) {
1802                                printf("** DI ext2fs read block (indir 2 2)"
1803                                        "failed. **\n");
1804                                return -1;
1805                        }
1806                        ext4fs_indir2_blkno =
1807                            le32_to_cpu(ext4fs_indir1_block[rblock
1808                                                              /
1809                                                              perblock]) <<
1810                            log2_blksz;
1811                }
1812                blknr = le32_to_cpu(ext4fs_indir2_block[rblock % perblock]);
1813        }
1814        /* Tripple indirect. */
1815        else {
1816                rblock = fileblock - (INDIRECT_BLOCKS + blksz / 4 +
1817                                      (blksz / 4 * blksz / 4));
1818                perblock_child = blksz / 4;
1819                perblock_parent = ((blksz / 4) * (blksz / 4));
1820
1821                if (ext4fs_indir1_block == NULL) {
1822                        ext4fs_indir1_block = zalloc(blksz);
1823                        if (ext4fs_indir1_block == NULL) {
1824                                printf("** TI ext2fs read block (indir 2 1)"
1825                                        "malloc failed. **\n");
1826                                return -1;
1827                        }
1828                        ext4fs_indir1_size = blksz;
1829                        ext4fs_indir1_blkno = -1;
1830                }
1831                if (blksz != ext4fs_indir1_size) {
1832                        free(ext4fs_indir1_block);
1833                        ext4fs_indir1_block = NULL;
1834                        ext4fs_indir1_size = 0;
1835                        ext4fs_indir1_blkno = -1;
1836                        ext4fs_indir1_block = zalloc(blksz);
1837                        if (ext4fs_indir1_block == NULL) {
1838                                printf("** TI ext2fs read block (indir 2 1)"
1839                                        "malloc failed. **\n");
1840                                return -1;
1841                        }
1842                        ext4fs_indir1_size = blksz;
1843                }
1844                if ((le32_to_cpu(inode->b.blocks.triple_indir_block) <<
1845                     log2_blksz) != ext4fs_indir1_blkno) {
1846                        status = ext4fs_devread
1847                            ((lbaint_t)
1848                             le32_to_cpu(inode->b.blocks.triple_indir_block)
1849                             << log2_blksz, 0, blksz,
1850                             (char *)ext4fs_indir1_block);
1851                        if (status == 0) {
1852                                printf("** TI ext2fs read block (indir 2 1)"
1853                                        "failed. **\n");
1854                                return -1;
1855                        }
1856                        ext4fs_indir1_blkno =
1857                            le32_to_cpu(inode->b.blocks.triple_indir_block) <<
1858                            log2_blksz;
1859                }
1860
1861                if (ext4fs_indir2_block == NULL) {
1862                        ext4fs_indir2_block = zalloc(blksz);
1863                        if (ext4fs_indir2_block == NULL) {
1864                                printf("** TI ext2fs read block (indir 2 2)"
1865                                        "malloc failed. **\n");
1866                                return -1;
1867                        }
1868                        ext4fs_indir2_size = blksz;
1869                        ext4fs_indir2_blkno = -1;
1870                }
1871                if (blksz != ext4fs_indir2_size) {
1872                        free(ext4fs_indir2_block);
1873                        ext4fs_indir2_block = NULL;
1874                        ext4fs_indir2_size = 0;
1875                        ext4fs_indir2_blkno = -1;
1876                        ext4fs_indir2_block = zalloc(blksz);
1877                        if (ext4fs_indir2_block == NULL) {
1878                                printf("** TI ext2fs read block (indir 2 2)"
1879                                        "malloc failed. **\n");
1880                                return -1;
1881                        }
1882                        ext4fs_indir2_size = blksz;
1883                }
1884                if ((le32_to_cpu(ext4fs_indir1_block[rblock /
1885                                                       perblock_parent]) <<
1886                     log2_blksz)
1887                    != ext4fs_indir2_blkno) {
1888                        status = ext4fs_devread((lbaint_t)le32_to_cpu
1889                                                (ext4fs_indir1_block
1890                                                 [rblock /
1891                                                  perblock_parent]) <<
1892                                                log2_blksz, 0, blksz,
1893                                                (char *)ext4fs_indir2_block);
1894                        if (status == 0) {
1895                                printf("** TI ext2fs read block (indir 2 2)"
1896                                        "failed. **\n");
1897                                return -1;
1898                        }
1899                        ext4fs_indir2_blkno =
1900                            le32_to_cpu(ext4fs_indir1_block[rblock /
1901                                                              perblock_parent])
1902                            << log2_blksz;
1903                }
1904
1905                if (ext4fs_indir3_block == NULL) {
1906                        ext4fs_indir3_block = zalloc(blksz);
1907                        if (ext4fs_indir3_block == NULL) {
1908                                printf("** TI ext2fs read block (indir 2 2)"
1909                                        "malloc failed. **\n");
1910                                return -1;
1911                        }
1912                        ext4fs_indir3_size = blksz;
1913                        ext4fs_indir3_blkno = -1;
1914                }
1915                if (blksz != ext4fs_indir3_size) {
1916                        free(ext4fs_indir3_block);
1917                        ext4fs_indir3_block = NULL;
1918                        ext4fs_indir3_size = 0;
1919                        ext4fs_indir3_blkno = -1;
1920                        ext4fs_indir3_block = zalloc(blksz);
1921                        if (ext4fs_indir3_block == NULL) {
1922                                printf("** TI ext2fs read block (indir 2 2)"
1923                                        "malloc failed. **\n");
1924                                return -1;
1925                        }
1926                        ext4fs_indir3_size = blksz;
1927                }
1928                if ((le32_to_cpu(ext4fs_indir2_block[rblock
1929                                                       /
1930                                                       perblock_child]) <<
1931                     log2_blksz) != ext4fs_indir3_blkno) {
1932                        status =
1933                            ext4fs_devread((lbaint_t)le32_to_cpu
1934                                           (ext4fs_indir2_block
1935                                            [(rblock / perblock_child)
1936                                             % (blksz / 4)]) << log2_blksz, 0,
1937                                           blksz, (char *)ext4fs_indir3_block);
1938                        if (status == 0) {
1939                                printf("** TI ext2fs read block (indir 2 2)"
1940                                       "failed. **\n");
1941                                return -1;
1942                        }
1943                        ext4fs_indir3_blkno =
1944                            le32_to_cpu(ext4fs_indir2_block[(rblock /
1945                                                               perblock_child) %
1946                                                              (blksz /
1947                                                               4)]) <<
1948                            log2_blksz;
1949                }
1950
1951                blknr = le32_to_cpu(ext4fs_indir3_block
1952                                      [rblock % perblock_child]);
1953        }
1954        debug("read_allocated_block %ld\n", blknr);
1955
1956        return blknr;
1957}
1958
1959/**
1960 * ext4fs_reinit_global() - Reinitialize values of ext4 write implementation's
1961 *                          global pointers
1962 *
1963 * This function assures that for a file with the same name but different size
1964 * the sequential store on the ext4 filesystem will be correct.
1965 *
1966 * In this function the global data, responsible for internal representation
1967 * of the ext4 data are initialized to the reset state. Without this, during
1968 * replacement of the smaller file with the bigger truncation of new file was
1969 * performed.
1970 */
1971void ext4fs_reinit_global(void)
1972{
1973        if (ext4fs_indir1_block != NULL) {
1974                free(ext4fs_indir1_block);
1975                ext4fs_indir1_block = NULL;
1976                ext4fs_indir1_size = 0;
1977                ext4fs_indir1_blkno = -1;
1978        }
1979        if (ext4fs_indir2_block != NULL) {
1980                free(ext4fs_indir2_block);
1981                ext4fs_indir2_block = NULL;
1982                ext4fs_indir2_size = 0;
1983                ext4fs_indir2_blkno = -1;
1984        }
1985        if (ext4fs_indir3_block != NULL) {
1986                free(ext4fs_indir3_block);
1987                ext4fs_indir3_block = NULL;
1988                ext4fs_indir3_size = 0;
1989                ext4fs_indir3_blkno = -1;
1990        }
1991}
1992void ext4fs_close(void)
1993{
1994        if ((ext4fs_file != NULL) && (ext4fs_root != NULL)) {
1995                ext4fs_free_node(ext4fs_file, &ext4fs_root->diropen);
1996                ext4fs_file = NULL;
1997        }
1998        if (ext4fs_root != NULL) {
1999                free(ext4fs_root);
2000                ext4fs_root = NULL;
2001        }
2002
2003        ext4fs_reinit_global();
2004}
2005
2006int ext4fs_iterate_dir(struct ext2fs_node *dir, char *name,
2007                                struct ext2fs_node **fnode, int *ftype)
2008{
2009        unsigned int fpos = 0;
2010        int status;
2011        loff_t actread;
2012        struct ext2fs_node *diro = (struct ext2fs_node *) dir;
2013
2014#ifdef DEBUG
2015        if (name != NULL)
2016                printf("Iterate dir %s\n", name);
2017#endif /* of DEBUG */
2018        if (!diro->inode_read) {
2019                status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
2020                if (status == 0)
2021                        return 0;
2022        }
2023        /* Search the file.  */
2024        while (fpos < le32_to_cpu(diro->inode.size)) {
2025                struct ext2_dirent dirent;
2026
2027                status = ext4fs_read_file(diro, fpos,
2028                                           sizeof(struct ext2_dirent),
2029                                           (char *)&dirent, &actread);
2030                if (status < 0)
2031                        return 0;
2032
2033                if (dirent.direntlen == 0) {
2034                        printf("Failed to iterate over directory %s\n", name);
2035                        return 0;
2036                }
2037
2038                if (dirent.namelen != 0) {
2039                        char filename[dirent.namelen + 1];
2040                        struct ext2fs_node *fdiro;
2041                        int type = FILETYPE_UNKNOWN;
2042
2043                        status = ext4fs_read_file(diro,
2044                                                  fpos +
2045                                                  sizeof(struct ext2_dirent),
2046                                                  dirent.namelen, filename,
2047                                                  &actread);
2048                        if (status < 0)
2049                                return 0;
2050
2051                        fdiro = zalloc(sizeof(struct ext2fs_node));
2052                        if (!fdiro)
2053                                return 0;
2054
2055                        fdiro->data = diro->data;
2056                        fdiro->ino = le32_to_cpu(dirent.inode);
2057
2058                        filename[dirent.namelen] = '\0';
2059
2060                        if (dirent.filetype != FILETYPE_UNKNOWN) {
2061                                fdiro->inode_read = 0;
2062
2063                                if (dirent.filetype == FILETYPE_DIRECTORY)
2064                                        type = FILETYPE_DIRECTORY;
2065                                else if (dirent.filetype == FILETYPE_SYMLINK)
2066                                        type = FILETYPE_SYMLINK;
2067                                else if (dirent.filetype == FILETYPE_REG)
2068                                        type = FILETYPE_REG;
2069                        } else {
2070                                status = ext4fs_read_inode(diro->data,
2071                                                           le32_to_cpu
2072                                                           (dirent.inode),
2073                                                           &fdiro->inode);
2074                                if (status == 0) {
2075                                        free(fdiro);
2076                                        return 0;
2077                                }
2078                                fdiro->inode_read = 1;
2079
2080                                if ((le16_to_cpu(fdiro->inode.mode) &
2081                                     FILETYPE_INO_MASK) ==
2082                                    FILETYPE_INO_DIRECTORY) {
2083                                        type = FILETYPE_DIRECTORY;
2084                                } else if ((le16_to_cpu(fdiro->inode.mode)
2085                                            & FILETYPE_INO_MASK) ==
2086                                           FILETYPE_INO_SYMLINK) {
2087                                        type = FILETYPE_SYMLINK;
2088                                } else if ((le16_to_cpu(fdiro->inode.mode)
2089                                            & FILETYPE_INO_MASK) ==
2090                                           FILETYPE_INO_REG) {
2091                                        type = FILETYPE_REG;
2092                                }
2093                        }
2094#ifdef DEBUG
2095                        printf("iterate >%s<\n", filename);
2096#endif /* of DEBUG */
2097                        if ((name != NULL) && (fnode != NULL)
2098                            && (ftype != NULL)) {
2099                                if (strcmp(filename, name) == 0) {
2100                                        *ftype = type;
2101                                        *fnode = fdiro;
2102                                        return 1;
2103                                }
2104                        } else {
2105                                if (fdiro->inode_read == 0) {
2106                                        status = ext4fs_read_inode(diro->data,
2107                                                                 le32_to_cpu(
2108                                                                 dirent.inode),
2109                                                                 &fdiro->inode);
2110                                        if (status == 0) {
2111                                                free(fdiro);
2112                                                return 0;
2113                                        }
2114                                        fdiro->inode_read = 1;
2115                                }
2116                                switch (type) {
2117                                case FILETYPE_DIRECTORY:
2118                                        printf("<DIR> ");
2119                                        break;
2120                                case FILETYPE_SYMLINK:
2121                                        printf("<SYM> ");
2122                                        break;
2123                                case FILETYPE_REG:
2124                                        printf("      ");
2125                                        break;
2126                                default:
2127                                        printf("< ? > ");
2128                                        break;
2129                                }
2130                                printf("%10u %s\n",
2131                                       le32_to_cpu(fdiro->inode.size),
2132                                        filename);
2133                        }
2134                        free(fdiro);
2135                }
2136                fpos += le16_to_cpu(dirent.direntlen);
2137        }
2138        return 0;
2139}
2140
2141static char *ext4fs_read_symlink(struct ext2fs_node *node)
2142{
2143        char *symlink;
2144        struct ext2fs_node *diro = node;
2145        int status;
2146        loff_t actread;
2147
2148        if (!diro->inode_read) {
2149                status = ext4fs_read_inode(diro->data, diro->ino, &diro->inode);
2150                if (status == 0)
2151                        return NULL;
2152        }
2153        symlink = zalloc(le32_to_cpu(diro->inode.size) + 1);
2154        if (!symlink)
2155                return NULL;
2156
2157        if (le32_to_cpu(diro->inode.size) < sizeof(diro->inode.b.symlink)) {
2158                strncpy(symlink, diro->inode.b.symlink,
2159                         le32_to_cpu(diro->inode.size));
2160        } else {
2161                status = ext4fs_read_file(diro, 0,
2162                                           le32_to_cpu(diro->inode.size),
2163                                           symlink, &actread);
2164                if ((status < 0) || (actread == 0)) {
2165                        free(symlink);
2166                        return NULL;
2167                }
2168        }
2169        symlink[le32_to_cpu(diro->inode.size)] = '\0';
2170        return symlink;
2171}
2172
2173static int ext4fs_find_file1(const char *currpath,
2174                             struct ext2fs_node *currroot,
2175                             struct ext2fs_node **currfound, int *foundtype)
2176{
2177        char fpath[strlen(currpath) + 1];
2178        char *name = fpath;
2179        char *next;
2180        int status;
2181        int type = FILETYPE_DIRECTORY;
2182        struct ext2fs_node *currnode = currroot;
2183        struct ext2fs_node *oldnode = currroot;
2184
2185        strncpy(fpath, currpath, strlen(currpath) + 1);
2186
2187        /* Remove all leading slashes. */
2188        while (*name == '/')
2189                name++;
2190
2191        if (!*name) {
2192                *currfound = currnode;
2193                return 1;
2194        }
2195
2196        for (;;) {
2197                int found;
2198
2199                /* Extract the actual part from the pathname. */
2200                next = strchr(name, '/');
2201                if (next) {
2202                        /* Remove all leading slashes. */
2203                        while (*next == '/')
2204                                *(next++) = '\0';
2205                }
2206
2207                if (type != FILETYPE_DIRECTORY) {
2208                        ext4fs_free_node(currnode, currroot);
2209                        return 0;
2210                }
2211
2212                oldnode = currnode;
2213
2214                /* Iterate over the directory. */
2215                found = ext4fs_iterate_dir(currnode, name, &currnode, &type);
2216                if (found == 0)
2217                        return 0;
2218
2219                if (found == -1)
2220                        break;
2221
2222                /* Read in the symlink and follow it. */
2223                if (type == FILETYPE_SYMLINK) {
2224                        char *symlink;
2225
2226                        /* Test if the symlink does not loop. */
2227                        if (++symlinknest == 8) {
2228                                ext4fs_free_node(currnode, currroot);
2229                                ext4fs_free_node(oldnode, currroot);
2230                                return 0;
2231                        }
2232
2233                        symlink = ext4fs_read_symlink(currnode);
2234                        ext4fs_free_node(currnode, currroot);
2235
2236                        if (!symlink) {
2237                                ext4fs_free_node(oldnode, currroot);
2238                                return 0;
2239                        }
2240
2241                        debug("Got symlink >%s<\n", symlink);
2242
2243                        if (symlink[0] == '/') {
2244                                ext4fs_free_node(oldnode, currroot);
2245                                oldnode = &ext4fs_root->diropen;
2246                        }
2247
2248                        /* Lookup the node the symlink points to. */
2249                        status = ext4fs_find_file1(symlink, oldnode,
2250                                                    &currnode, &type);
2251
2252                        free(symlink);
2253
2254                        if (status == 0) {
2255                                ext4fs_free_node(oldnode, currroot);
2256                                return 0;
2257                        }
2258                }
2259
2260                ext4fs_free_node(oldnode, currroot);
2261
2262                /* Found the node! */
2263                if (!next || *next == '\0') {
2264                        *currfound = currnode;
2265                        *foundtype = type;
2266                        return 1;
2267                }
2268                name = next;
2269        }
2270        return -1;
2271}
2272
2273int ext4fs_find_file(const char *path, struct ext2fs_node *rootnode,
2274        struct ext2fs_node **foundnode, int expecttype)
2275{
2276        int status;
2277        int foundtype = FILETYPE_DIRECTORY;
2278
2279        symlinknest = 0;
2280        if (!path)
2281                return 0;
2282
2283        status = ext4fs_find_file1(path, rootnode, foundnode, &foundtype);
2284        if (status == 0)
2285                return 0;
2286
2287        /* Check if the node that was found was of the expected type. */
2288        if ((expecttype == FILETYPE_REG) && (foundtype != expecttype))
2289                return 0;
2290        else if ((expecttype == FILETYPE_DIRECTORY)
2291                   && (foundtype != expecttype))
2292                return 0;
2293
2294        return 1;
2295}
2296
2297int ext4fs_open(const char *filename, loff_t *len)
2298{
2299        struct ext2fs_node *fdiro = NULL;
2300        int status;
2301
2302        if (ext4fs_root == NULL)
2303                return -1;
2304
2305        ext4fs_file = NULL;
2306        status = ext4fs_find_file(filename, &ext4fs_root->diropen, &fdiro,
2307                                  FILETYPE_REG);
2308        if (status == 0)
2309                goto fail;
2310
2311        if (!fdiro->inode_read) {
2312                status = ext4fs_read_inode(fdiro->data, fdiro->ino,
2313                                &fdiro->inode);
2314                if (status == 0)
2315                        goto fail;
2316        }
2317        *len = le32_to_cpu(fdiro->inode.size);
2318        ext4fs_file = fdiro;
2319
2320        return 0;
2321fail:
2322        ext4fs_free_node(fdiro, &ext4fs_root->diropen);
2323
2324        return -1;
2325}
2326
2327int ext4fs_mount(unsigned part_length)
2328{
2329        struct ext2_data *data;
2330        int status;
2331        struct ext_filesystem *fs = get_fs();
2332        data = zalloc(SUPERBLOCK_SIZE);
2333        if (!data)
2334                return 0;
2335
2336        /* Read the superblock. */
2337        status = ext4_read_superblock((char *)&data->sblock);
2338
2339        if (status == 0)
2340                goto fail;
2341
2342        /* Make sure this is an ext2 filesystem. */
2343        if (le16_to_cpu(data->sblock.magic) != EXT2_MAGIC)
2344                goto fail_noerr;
2345
2346
2347        if (le32_to_cpu(data->sblock.revision_level) == 0) {
2348                fs->inodesz = 128;
2349                fs->gdsize = 32;
2350        } else {
2351                debug("EXT4 features COMPAT: %08x INCOMPAT: %08x RO_COMPAT: %08x\n",
2352                      __le32_to_cpu(data->sblock.feature_compatibility),
2353                      __le32_to_cpu(data->sblock.feature_incompat),
2354                      __le32_to_cpu(data->sblock.feature_ro_compat));
2355
2356                fs->inodesz = le16_to_cpu(data->sblock.inode_size);
2357                fs->gdsize = le32_to_cpu(data->sblock.feature_incompat) &
2358                        EXT4_FEATURE_INCOMPAT_64BIT ?
2359                        le16_to_cpu(data->sblock.descriptor_size) : 32;
2360        }
2361
2362        debug("EXT2 rev %d, inode_size %d, descriptor size %d\n",
2363              le32_to_cpu(data->sblock.revision_level),
2364              fs->inodesz, fs->gdsize);
2365
2366        data->diropen.data = data;
2367        data->diropen.ino = 2;
2368        data->diropen.inode_read = 1;
2369        data->inode = &data->diropen.inode;
2370
2371        status = ext4fs_read_inode(data, 2, data->inode);
2372        if (status == 0)
2373                goto fail;
2374
2375        ext4fs_root = data;
2376
2377        return 1;
2378fail:
2379        printf("Failed to mount ext2 filesystem...\n");
2380fail_noerr:
2381        free(data);
2382        ext4fs_root = NULL;
2383
2384        return 0;
2385}
2386