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