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