uboot/fs/ext2/ext2fs.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2004
   3 *  esd gmbh <www.esd-electronics.com>
   4 *  Reinhard Arlt <reinhard.arlt@esd-electronics.com>
   5 *
   6 *  based on code from grub2 fs/ext2.c and fs/fshelp.c by
   7 *
   8 *  GRUB  --  GRand Unified Bootloader
   9 *  Copyright (C) 2003, 2004  Free Software Foundation, Inc.
  10 *
  11 *  This program is free software; you can redistribute it and/or modify
  12 *  it under the terms of the GNU General Public License as published by
  13 *  the Free Software Foundation; either version 2 of the License, or
  14 *  (at your option) any later version.
  15 *
  16 *  This program is distributed in the hope that it will be useful,
  17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 *  GNU General Public License for more details.
  20 *
  21 *  You should have received a copy of the GNU General Public License
  22 *  along with this program; if not, write to the Free Software
  23 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 */
  25
  26#include <common.h>
  27#include <ext2fs.h>
  28#include <malloc.h>
  29#include <asm/byteorder.h>
  30
  31extern int ext2fs_devread (int sector, int byte_offset, int byte_len,
  32                           char *buf);
  33
  34/* Magic value used to identify an ext2 filesystem.  */
  35#define EXT2_MAGIC              0xEF53
  36/* Amount of indirect blocks in an inode.  */
  37#define INDIRECT_BLOCKS         12
  38/* Maximum lenght of a pathname.  */
  39#define EXT2_PATH_MAX           4096
  40/* Maximum nesting of symlinks, used to prevent a loop.  */
  41#define EXT2_MAX_SYMLINKCNT     8
  42
  43/* Filetype used in directory entry.  */
  44#define FILETYPE_UNKNOWN        0
  45#define FILETYPE_REG            1
  46#define FILETYPE_DIRECTORY      2
  47#define FILETYPE_SYMLINK        7
  48
  49/* Filetype information as used in inodes.  */
  50#define FILETYPE_INO_MASK       0170000
  51#define FILETYPE_INO_REG        0100000
  52#define FILETYPE_INO_DIRECTORY  0040000
  53#define FILETYPE_INO_SYMLINK    0120000
  54
  55/* Bits used as offset in sector */
  56#define DISK_SECTOR_BITS        9
  57
  58/* Log2 size of ext2 block in 512 blocks.  */
  59#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 1)
  60
  61/* Log2 size of ext2 block in bytes.  */
  62#define LOG2_BLOCK_SIZE(data)      (__le32_to_cpu (data->sblock.log2_block_size) + 10)
  63
  64/* The size of an ext2 block in bytes.  */
  65#define EXT2_BLOCK_SIZE(data)      (1 << LOG2_BLOCK_SIZE(data))
  66
  67/* The ext2 superblock.  */
  68struct ext2_sblock {
  69        uint32_t total_inodes;
  70        uint32_t total_blocks;
  71        uint32_t reserved_blocks;
  72        uint32_t free_blocks;
  73        uint32_t free_inodes;
  74        uint32_t first_data_block;
  75        uint32_t log2_block_size;
  76        uint32_t log2_fragment_size;
  77        uint32_t blocks_per_group;
  78        uint32_t fragments_per_group;
  79        uint32_t inodes_per_group;
  80        uint32_t mtime;
  81        uint32_t utime;
  82        uint16_t mnt_count;
  83        uint16_t max_mnt_count;
  84        uint16_t magic;
  85        uint16_t fs_state;
  86        uint16_t error_handling;
  87        uint16_t minor_revision_level;
  88        uint32_t lastcheck;
  89        uint32_t checkinterval;
  90        uint32_t creator_os;
  91        uint32_t revision_level;
  92        uint16_t uid_reserved;
  93        uint16_t gid_reserved;
  94        uint32_t first_inode;
  95        uint16_t inode_size;
  96        uint16_t block_group_number;
  97        uint32_t feature_compatibility;
  98        uint32_t feature_incompat;
  99        uint32_t feature_ro_compat;
 100        uint32_t unique_id[4];
 101        char volume_name[16];
 102        char last_mounted_on[64];
 103        uint32_t compression_info;
 104};
 105
 106/* The ext2 blockgroup.  */
 107struct ext2_block_group {
 108        uint32_t block_id;
 109        uint32_t inode_id;
 110        uint32_t inode_table_id;
 111        uint16_t free_blocks;
 112        uint16_t free_inodes;
 113        uint16_t used_dir_cnt;
 114        uint32_t reserved[3];
 115};
 116
 117/* The ext2 inode.  */
 118struct ext2_inode {
 119        uint16_t mode;
 120        uint16_t uid;
 121        uint32_t size;
 122        uint32_t atime;
 123        uint32_t ctime;
 124        uint32_t mtime;
 125        uint32_t dtime;
 126        uint16_t gid;
 127        uint16_t nlinks;
 128        uint32_t blockcnt;      /* Blocks of 512 bytes!! */
 129        uint32_t flags;
 130        uint32_t osd1;
 131        union {
 132                struct datablocks {
 133                        uint32_t dir_blocks[INDIRECT_BLOCKS];
 134                        uint32_t indir_block;
 135                        uint32_t double_indir_block;
 136                        uint32_t tripple_indir_block;
 137                } blocks;
 138                char symlink[60];
 139        } b;
 140        uint32_t version;
 141        uint32_t acl;
 142        uint32_t dir_acl;
 143        uint32_t fragment_addr;
 144        uint32_t osd2[3];
 145};
 146
 147/* The header of an ext2 directory entry.  */
 148struct ext2_dirent {
 149        uint32_t inode;
 150        uint16_t direntlen;
 151        uint8_t namelen;
 152        uint8_t filetype;
 153};
 154
 155struct ext2fs_node {
 156        struct ext2_data *data;
 157        struct ext2_inode inode;
 158        int ino;
 159        int inode_read;
 160};
 161
 162/* Information about a "mounted" ext2 filesystem.  */
 163struct ext2_data {
 164        struct ext2_sblock sblock;
 165        struct ext2_inode *inode;
 166        struct ext2fs_node diropen;
 167};
 168
 169
 170typedef struct ext2fs_node *ext2fs_node_t;
 171
 172struct ext2_data *ext2fs_root = NULL;
 173ext2fs_node_t ext2fs_file = NULL;
 174int symlinknest = 0;
 175uint32_t *indir1_block = NULL;
 176int indir1_size = 0;
 177int indir1_blkno = -1;
 178uint32_t *indir2_block = NULL;
 179int indir2_size = 0;
 180int indir2_blkno = -1;
 181static unsigned int inode_size;
 182
 183
 184static int ext2fs_blockgroup
 185        (struct ext2_data *data, int group, struct ext2_block_group *blkgrp) {
 186        unsigned int blkno;
 187        unsigned int blkoff;
 188        unsigned int desc_per_blk;
 189
 190        desc_per_blk = EXT2_BLOCK_SIZE(data) / sizeof(struct ext2_block_group);
 191
 192        blkno = __le32_to_cpu(data->sblock.first_data_block) + 1 +
 193        group / desc_per_blk;
 194        blkoff = (group % desc_per_blk) * sizeof(struct ext2_block_group);
 195#ifdef DEBUG
 196        printf ("ext2fs read %d group descriptor (blkno %d blkoff %d)\n",
 197                group, blkno, blkoff);
 198#endif
 199        return (ext2fs_devread (blkno << LOG2_EXT2_BLOCK_SIZE(data),
 200                blkoff, sizeof(struct ext2_block_group), (char *)blkgrp));
 201
 202}
 203
 204
 205static int ext2fs_read_inode
 206        (struct ext2_data *data, int ino, struct ext2_inode *inode) {
 207        struct ext2_block_group blkgrp;
 208        struct ext2_sblock *sblock = &data->sblock;
 209        int inodes_per_block;
 210        int status;
 211
 212        unsigned int blkno;
 213        unsigned int blkoff;
 214
 215#ifdef DEBUG
 216        printf ("ext2fs read inode %d, inode_size %d\n", ino, inode_size);
 217#endif
 218        /* It is easier to calculate if the first inode is 0.  */
 219        ino--;
 220        status = ext2fs_blockgroup (data, ino / __le32_to_cpu
 221                                    (sblock->inodes_per_group), &blkgrp);
 222        if (status == 0) {
 223                return (0);
 224        }
 225
 226        inodes_per_block = EXT2_BLOCK_SIZE(data) / inode_size;
 227
 228        blkno = __le32_to_cpu (blkgrp.inode_table_id) +
 229                (ino % __le32_to_cpu (sblock->inodes_per_group))
 230                / inodes_per_block;
 231        blkoff = (ino % inodes_per_block) * inode_size;
 232#ifdef DEBUG
 233        printf ("ext2fs read inode blkno %d blkoff %d\n", blkno, blkoff);
 234#endif
 235        /* Read the inode.  */
 236        status = ext2fs_devread (blkno << LOG2_EXT2_BLOCK_SIZE (data), blkoff,
 237                                 sizeof (struct ext2_inode), (char *) inode);
 238        if (status == 0) {
 239                return (0);
 240        }
 241
 242        return (1);
 243}
 244
 245
 246void ext2fs_free_node (ext2fs_node_t node, ext2fs_node_t currroot) {
 247        if ((node != &ext2fs_root->diropen) && (node != currroot)) {
 248                free (node);
 249        }
 250}
 251
 252
 253static int ext2fs_read_block (ext2fs_node_t node, int fileblock) {
 254        struct ext2_data *data = node->data;
 255        struct ext2_inode *inode = &node->inode;
 256        int blknr;
 257        int blksz = EXT2_BLOCK_SIZE (data);
 258        int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
 259        int status;
 260
 261        /* Direct blocks.  */
 262        if (fileblock < INDIRECT_BLOCKS) {
 263                blknr = __le32_to_cpu (inode->b.blocks.dir_blocks[fileblock]);
 264        }
 265        /* Indirect.  */
 266        else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
 267                if (indir1_block == NULL) {
 268                        indir1_block = (uint32_t *) malloc (blksz);
 269                        if (indir1_block == NULL) {
 270                                printf ("** ext2fs read block (indir 1) malloc failed. **\n");
 271                                return (-1);
 272                        }
 273                        indir1_size = blksz;
 274                        indir1_blkno = -1;
 275                }
 276                if (blksz != indir1_size) {
 277                        free (indir1_block);
 278                        indir1_block = NULL;
 279                        indir1_size = 0;
 280                        indir1_blkno = -1;
 281                        indir1_block = (uint32_t *) malloc (blksz);
 282                        if (indir1_block == NULL) {
 283                                printf ("** ext2fs read block (indir 1) malloc failed. **\n");
 284                                return (-1);
 285                        }
 286                        indir1_size = blksz;
 287                }
 288                if ((__le32_to_cpu (inode->b.blocks.indir_block) <<
 289                     log2_blksz) != indir1_blkno) {
 290                        status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.indir_block) << log2_blksz,
 291                                                 0, blksz,
 292                                                 (char *) indir1_block);
 293                        if (status == 0) {
 294                                printf ("** ext2fs read block (indir 1) failed. **\n");
 295                                return (0);
 296                        }
 297                        indir1_blkno =
 298                                __le32_to_cpu (inode->b.blocks.
 299                                               indir_block) << log2_blksz;
 300                }
 301                blknr = __le32_to_cpu (indir1_block
 302                                       [fileblock - INDIRECT_BLOCKS]);
 303        }
 304        /* Double indirect.  */
 305        else if (fileblock <
 306                 (INDIRECT_BLOCKS + (blksz / 4 * (blksz / 4 + 1)))) {
 307                unsigned int perblock = blksz / 4;
 308                unsigned int rblock = fileblock - (INDIRECT_BLOCKS
 309                                                   + blksz / 4);
 310
 311                if (indir1_block == NULL) {
 312                        indir1_block = (uint32_t *) malloc (blksz);
 313                        if (indir1_block == NULL) {
 314                                printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
 315                                return (-1);
 316                        }
 317                        indir1_size = blksz;
 318                        indir1_blkno = -1;
 319                }
 320                if (blksz != indir1_size) {
 321                        free (indir1_block);
 322                        indir1_block = NULL;
 323                        indir1_size = 0;
 324                        indir1_blkno = -1;
 325                        indir1_block = (uint32_t *) malloc (blksz);
 326                        if (indir1_block == NULL) {
 327                                printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
 328                                return (-1);
 329                        }
 330                        indir1_size = blksz;
 331                }
 332                if ((__le32_to_cpu (inode->b.blocks.double_indir_block) <<
 333                     log2_blksz) != indir1_blkno) {
 334                        status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz,
 335                                                0, blksz,
 336                                                (char *) indir1_block);
 337                        if (status == 0) {
 338                                printf ("** ext2fs read block (indir 2 1) failed. **\n");
 339                                return (-1);
 340                        }
 341                        indir1_blkno =
 342                                __le32_to_cpu (inode->b.blocks.double_indir_block) << log2_blksz;
 343                }
 344
 345                if (indir2_block == NULL) {
 346                        indir2_block = (uint32_t *) malloc (blksz);
 347                        if (indir2_block == NULL) {
 348                                printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
 349                                return (-1);
 350                        }
 351                        indir2_size = blksz;
 352                        indir2_blkno = -1;
 353                }
 354                if (blksz != indir2_size) {
 355                        free (indir2_block);
 356                        indir2_block = NULL;
 357                        indir2_size = 0;
 358                        indir2_blkno = -1;
 359                        indir2_block = (uint32_t *) malloc (blksz);
 360                        if (indir2_block == NULL) {
 361                                printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
 362                                return (-1);
 363                        }
 364                        indir2_size = blksz;
 365                }
 366                if ((__le32_to_cpu (indir1_block[rblock / perblock]) <<
 367                     log2_blksz) != indir2_blkno) {
 368                        status = ext2fs_devread (__le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz,
 369                                                 0, blksz,
 370                                                 (char *) indir2_block);
 371                        if (status == 0) {
 372                                printf ("** ext2fs read block (indir 2 2) failed. **\n");
 373                                return (-1);
 374                        }
 375                        indir2_blkno =
 376                                __le32_to_cpu (indir1_block[rblock / perblock]) << log2_blksz;
 377                }
 378                blknr = __le32_to_cpu (indir2_block[rblock % perblock]);
 379        }
 380        /* Tripple indirect.  */
 381        else {
 382                printf ("** ext2fs doesn't support tripple indirect blocks. **\n");
 383                return (-1);
 384        }
 385#ifdef DEBUG
 386        printf ("ext2fs_read_block %08x\n", blknr);
 387#endif
 388        return (blknr);
 389}
 390
 391
 392int ext2fs_read_file
 393        (ext2fs_node_t node, int pos, unsigned int len, char *buf) {
 394        int i;
 395        int blockcnt;
 396        int log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
 397        int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
 398        unsigned int filesize = __le32_to_cpu(node->inode.size);
 399
 400        /* Adjust len so it we can't read past the end of the file.  */
 401        if (len > filesize) {
 402                len = filesize;
 403        }
 404        blockcnt = ((len + pos) + blocksize - 1) / blocksize;
 405
 406        for (i = pos / blocksize; i < blockcnt; i++) {
 407                int blknr;
 408                int blockoff = pos % blocksize;
 409                int blockend = blocksize;
 410
 411                int skipfirst = 0;
 412
 413                blknr = ext2fs_read_block (node, i);
 414                if (blknr < 0) {
 415                        return (-1);
 416                }
 417                blknr = blknr << log2blocksize;
 418
 419                /* Last block.  */
 420                if (i == blockcnt - 1) {
 421                        blockend = (len + pos) % blocksize;
 422
 423                        /* The last portion is exactly blocksize.  */
 424                        if (!blockend) {
 425                                blockend = blocksize;
 426                        }
 427                }
 428
 429                /* First block.  */
 430                if (i == pos / blocksize) {
 431                        skipfirst = blockoff;
 432                        blockend -= skipfirst;
 433                }
 434
 435                /* If the block number is 0 this block is not stored on disk but
 436                   is zero filled instead.  */
 437                if (blknr) {
 438                        int status;
 439
 440                        status = ext2fs_devread (blknr, skipfirst, blockend, buf);
 441                        if (status == 0) {
 442                                return (-1);
 443                        }
 444                } else {
 445                        memset (buf, 0, blocksize - skipfirst);
 446                }
 447                buf += blocksize - skipfirst;
 448        }
 449        return (len);
 450}
 451
 452
 453static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fnode, int *ftype)
 454{
 455        unsigned int fpos = 0;
 456        int status;
 457        struct ext2fs_node *diro = (struct ext2fs_node *) dir;
 458
 459#ifdef DEBUG
 460        if (name != NULL)
 461                printf ("Iterate dir %s\n", name);
 462#endif /* of DEBUG */
 463        if (!diro->inode_read) {
 464                status = ext2fs_read_inode (diro->data, diro->ino,
 465                                            &diro->inode);
 466                if (status == 0) {
 467                        return (0);
 468                }
 469        }
 470        /* Search the file.  */
 471        while (fpos < __le32_to_cpu (diro->inode.size)) {
 472                struct ext2_dirent dirent;
 473
 474                status = ext2fs_read_file (diro, fpos,
 475                                           sizeof (struct ext2_dirent),
 476                                           (char *) &dirent);
 477                if (status < 1) {
 478                        return (0);
 479                }
 480                if (dirent.namelen != 0) {
 481                        char filename[dirent.namelen + 1];
 482                        ext2fs_node_t fdiro;
 483                        int type = FILETYPE_UNKNOWN;
 484
 485                        status = ext2fs_read_file (diro,
 486                                                   fpos + sizeof (struct ext2_dirent),
 487                                                   dirent.namelen, filename);
 488                        if (status < 1) {
 489                                return (0);
 490                        }
 491                        fdiro = malloc (sizeof (struct ext2fs_node));
 492                        if (!fdiro) {
 493                                return (0);
 494                        }
 495
 496                        fdiro->data = diro->data;
 497                        fdiro->ino = __le32_to_cpu (dirent.inode);
 498
 499                        filename[dirent.namelen] = '\0';
 500
 501                        if (dirent.filetype != FILETYPE_UNKNOWN) {
 502                                fdiro->inode_read = 0;
 503
 504                                if (dirent.filetype == FILETYPE_DIRECTORY) {
 505                                        type = FILETYPE_DIRECTORY;
 506                                } else if (dirent.filetype ==
 507                                           FILETYPE_SYMLINK) {
 508                                        type = FILETYPE_SYMLINK;
 509                                } else if (dirent.filetype == FILETYPE_REG) {
 510                                        type = FILETYPE_REG;
 511                                }
 512                        } else {
 513                                /* The filetype can not be read from the dirent, get it from inode */
 514
 515                                status = ext2fs_read_inode (diro->data,
 516                                                            __le32_to_cpu(dirent.inode),
 517                                                            &fdiro->inode);
 518                                if (status == 0) {
 519                                        free (fdiro);
 520                                        return (0);
 521                                }
 522                                fdiro->inode_read = 1;
 523
 524                                if ((__le16_to_cpu (fdiro->inode.mode) &
 525                                     FILETYPE_INO_MASK) ==
 526                                    FILETYPE_INO_DIRECTORY) {
 527                                        type = FILETYPE_DIRECTORY;
 528                                } else if ((__le16_to_cpu (fdiro->inode.mode)
 529                                            & FILETYPE_INO_MASK) ==
 530                                           FILETYPE_INO_SYMLINK) {
 531                                        type = FILETYPE_SYMLINK;
 532                                } else if ((__le16_to_cpu (fdiro->inode.mode)
 533                                            & FILETYPE_INO_MASK) ==
 534                                           FILETYPE_INO_REG) {
 535                                        type = FILETYPE_REG;
 536                                }
 537                        }
 538#ifdef DEBUG
 539                        printf ("iterate >%s<\n", filename);
 540#endif /* of DEBUG */
 541                        if ((name != NULL) && (fnode != NULL)
 542                            && (ftype != NULL)) {
 543                                if (strcmp (filename, name) == 0) {
 544                                        *ftype = type;
 545                                        *fnode = fdiro;
 546                                        return (1);
 547                                }
 548                        } else {
 549                                if (fdiro->inode_read == 0) {
 550                                        status = ext2fs_read_inode (diro->data,
 551                                                            __le32_to_cpu (dirent.inode),
 552                                                            &fdiro->inode);
 553                                        if (status == 0) {
 554                                                free (fdiro);
 555                                                return (0);
 556                                        }
 557                                        fdiro->inode_read = 1;
 558                                }
 559                                switch (type) {
 560                                case FILETYPE_DIRECTORY:
 561                                        printf ("<DIR> ");
 562                                        break;
 563                                case FILETYPE_SYMLINK:
 564                                        printf ("<SYM> ");
 565                                        break;
 566                                case FILETYPE_REG:
 567                                        printf ("      ");
 568                                        break;
 569                                default:
 570                                        printf ("< ? > ");
 571                                        break;
 572                                }
 573                                printf ("%10d %s\n",
 574                                        __le32_to_cpu (fdiro->inode.size),
 575                                        filename);
 576                        }
 577                        free (fdiro);
 578                }
 579                fpos += __le16_to_cpu (dirent.direntlen);
 580        }
 581        return (0);
 582}
 583
 584
 585static char *ext2fs_read_symlink (ext2fs_node_t node) {
 586        char *symlink;
 587        struct ext2fs_node *diro = node;
 588        int status;
 589
 590        if (!diro->inode_read) {
 591                status = ext2fs_read_inode (diro->data, diro->ino,
 592                                            &diro->inode);
 593                if (status == 0) {
 594                        return (0);
 595                }
 596        }
 597        symlink = malloc (__le32_to_cpu (diro->inode.size) + 1);
 598        if (!symlink) {
 599                return (0);
 600        }
 601        /* If the filesize of the symlink is bigger than
 602           60 the symlink is stored in a separate block,
 603           otherwise it is stored in the inode.  */
 604        if (__le32_to_cpu (diro->inode.size) <= 60) {
 605                strncpy (symlink, diro->inode.b.symlink,
 606                         __le32_to_cpu (diro->inode.size));
 607        } else {
 608                status = ext2fs_read_file (diro, 0,
 609                                           __le32_to_cpu (diro->inode.size),
 610                                           symlink);
 611                if (status == 0) {
 612                        free (symlink);
 613                        return (0);
 614                }
 615        }
 616        symlink[__le32_to_cpu (diro->inode.size)] = '\0';
 617        return (symlink);
 618}
 619
 620
 621int ext2fs_find_file1
 622        (const char *currpath,
 623         ext2fs_node_t currroot, ext2fs_node_t * currfound, int *foundtype) {
 624        char fpath[strlen (currpath) + 1];
 625        char *name = fpath;
 626        char *next;
 627        int status;
 628        int type = FILETYPE_DIRECTORY;
 629        ext2fs_node_t currnode = currroot;
 630        ext2fs_node_t oldnode = currroot;
 631
 632        strncpy (fpath, currpath, strlen (currpath) + 1);
 633
 634        /* Remove all leading slashes.  */
 635        while (*name == '/') {
 636                name++;
 637        }
 638        if (!*name) {
 639                *currfound = currnode;
 640                return (1);
 641        }
 642
 643        for (;;) {
 644                int found;
 645
 646                /* Extract the actual part from the pathname.  */
 647                next = strchr (name, '/');
 648                if (next) {
 649                        /* Remove all leading slashes.  */
 650                        while (*next == '/') {
 651                                *(next++) = '\0';
 652                        }
 653                }
 654
 655                /* At this point it is expected that the current node is a directory, check if this is true.  */
 656                if (type != FILETYPE_DIRECTORY) {
 657                        ext2fs_free_node (currnode, currroot);
 658                        return (0);
 659                }
 660
 661                oldnode = currnode;
 662
 663                /* Iterate over the directory.  */
 664                found = ext2fs_iterate_dir (currnode, name, &currnode, &type);
 665                if (found == 0) {
 666                        return (0);
 667                }
 668                if (found == -1) {
 669                        break;
 670                }
 671
 672                /* Read in the symlink and follow it.  */
 673                if (type == FILETYPE_SYMLINK) {
 674                        char *symlink;
 675
 676                        /* Test if the symlink does not loop.  */
 677                        if (++symlinknest == 8) {
 678                                ext2fs_free_node (currnode, currroot);
 679                                ext2fs_free_node (oldnode, currroot);
 680                                return (0);
 681                        }
 682
 683                        symlink = ext2fs_read_symlink (currnode);
 684                        ext2fs_free_node (currnode, currroot);
 685
 686                        if (!symlink) {
 687                                ext2fs_free_node (oldnode, currroot);
 688                                return (0);
 689                        }
 690#ifdef DEBUG
 691                        printf ("Got symlink >%s<\n", symlink);
 692#endif /* of DEBUG */
 693                        /* The symlink is an absolute path, go back to the root inode.  */
 694                        if (symlink[0] == '/') {
 695                                ext2fs_free_node (oldnode, currroot);
 696                                oldnode = &ext2fs_root->diropen;
 697                        }
 698
 699                        /* Lookup the node the symlink points to.  */
 700                        status = ext2fs_find_file1 (symlink, oldnode,
 701                                                    &currnode, &type);
 702
 703                        free (symlink);
 704
 705                        if (status == 0) {
 706                                ext2fs_free_node (oldnode, currroot);
 707                                return (0);
 708                        }
 709                }
 710
 711                ext2fs_free_node (oldnode, currroot);
 712
 713                /* Found the node!  */
 714                if (!next || *next == '\0') {
 715                        *currfound = currnode;
 716                        *foundtype = type;
 717                        return (1);
 718                }
 719                name = next;
 720        }
 721        return (-1);
 722}
 723
 724
 725int ext2fs_find_file
 726        (const char *path,
 727         ext2fs_node_t rootnode, ext2fs_node_t * foundnode, int expecttype) {
 728        int status;
 729        int foundtype = FILETYPE_DIRECTORY;
 730
 731
 732        symlinknest = 0;
 733        if (!path) {
 734                return (0);
 735        }
 736
 737        status = ext2fs_find_file1 (path, rootnode, foundnode, &foundtype);
 738        if (status == 0) {
 739                return (0);
 740        }
 741        /* Check if the node that was found was of the expected type.  */
 742        if ((expecttype == FILETYPE_REG) && (foundtype != expecttype)) {
 743                return (0);
 744        } else if ((expecttype == FILETYPE_DIRECTORY)
 745                   && (foundtype != expecttype)) {
 746                return (0);
 747        }
 748        return (1);
 749}
 750
 751
 752int ext2fs_ls (const char *dirname) {
 753        ext2fs_node_t dirnode;
 754        int status;
 755
 756        if (ext2fs_root == NULL) {
 757                return (0);
 758        }
 759
 760        status = ext2fs_find_file (dirname, &ext2fs_root->diropen, &dirnode,
 761                                   FILETYPE_DIRECTORY);
 762        if (status != 1) {
 763                printf ("** Can not find directory. **\n");
 764                return (1);
 765        }
 766        ext2fs_iterate_dir (dirnode, NULL, NULL, NULL);
 767        ext2fs_free_node (dirnode, &ext2fs_root->diropen);
 768        return (0);
 769}
 770
 771
 772int ext2fs_open (const char *filename) {
 773        ext2fs_node_t fdiro = NULL;
 774        int status;
 775        int len;
 776
 777        if (ext2fs_root == NULL) {
 778                return (-1);
 779        }
 780        ext2fs_file = NULL;
 781        status = ext2fs_find_file (filename, &ext2fs_root->diropen, &fdiro,
 782                                   FILETYPE_REG);
 783        if (status == 0) {
 784                goto fail;
 785        }
 786        if (!fdiro->inode_read) {
 787                status = ext2fs_read_inode (fdiro->data, fdiro->ino,
 788                                            &fdiro->inode);
 789                if (status == 0) {
 790                        goto fail;
 791                }
 792        }
 793        len = __le32_to_cpu (fdiro->inode.size);
 794        ext2fs_file = fdiro;
 795        return (len);
 796
 797fail:
 798        ext2fs_free_node (fdiro, &ext2fs_root->diropen);
 799        return (-1);
 800}
 801
 802
 803int ext2fs_close (void
 804        ) {
 805        if ((ext2fs_file != NULL) && (ext2fs_root != NULL)) {
 806                ext2fs_free_node (ext2fs_file, &ext2fs_root->diropen);
 807                ext2fs_file = NULL;
 808        }
 809        if (ext2fs_root != NULL) {
 810                free (ext2fs_root);
 811                ext2fs_root = NULL;
 812        }
 813        if (indir1_block != NULL) {
 814                free (indir1_block);
 815                indir1_block = NULL;
 816                indir1_size = 0;
 817                indir1_blkno = -1;
 818        }
 819        if (indir2_block != NULL) {
 820                free (indir2_block);
 821                indir2_block = NULL;
 822                indir2_size = 0;
 823                indir2_blkno = -1;
 824        }
 825        return (0);
 826}
 827
 828
 829int ext2fs_read (char *buf, unsigned len) {
 830        int status;
 831
 832        if (ext2fs_root == NULL) {
 833                return (0);
 834        }
 835
 836        if (ext2fs_file == NULL) {
 837                return (0);
 838        }
 839
 840        status = ext2fs_read_file (ext2fs_file, 0, len, buf);
 841        return (status);
 842}
 843
 844
 845int ext2fs_mount (unsigned part_length) {
 846        struct ext2_data *data;
 847        int status;
 848
 849        data = malloc (sizeof (struct ext2_data));
 850        if (!data) {
 851                return (0);
 852        }
 853        /* Read the superblock.  */
 854        status = ext2fs_devread (1 * 2, 0, sizeof (struct ext2_sblock),
 855                                 (char *) &data->sblock);
 856        if (status == 0) {
 857                goto fail;
 858        }
 859        /* Make sure this is an ext2 filesystem.  */
 860        if (__le16_to_cpu (data->sblock.magic) != EXT2_MAGIC) {
 861                goto fail;
 862        }
 863        if (__le32_to_cpu(data->sblock.revision_level == 0)) {
 864                inode_size = 128;
 865        } else {
 866                inode_size = __le16_to_cpu(data->sblock.inode_size);
 867        }
 868#ifdef DEBUG
 869        printf("EXT2 rev %d, inode_size %d\n",
 870                        __le32_to_cpu(data->sblock.revision_level), inode_size);
 871#endif
 872        data->diropen.data = data;
 873        data->diropen.ino = 2;
 874        data->diropen.inode_read = 1;
 875        data->inode = &data->diropen.inode;
 876
 877        status = ext2fs_read_inode (data, 2, data->inode);
 878        if (status == 0) {
 879                goto fail;
 880        }
 881
 882        ext2fs_root = data;
 883
 884        return (1);
 885
 886fail:
 887        printf ("Failed to mount ext2 filesystem...\n");
 888        free (data);
 889        ext2fs_root = NULL;
 890        return (0);
 891}
 892