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