]> git.sur5r.net Git - u-boot/blob - fs/ext2/ext2fs.c
436f4a4aa92a0f7eaef694743c172b4f8c2482e3
[u-boot] / fs / ext2 / ext2fs.c
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
31 extern 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.  */
68 struct 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.  */
107 struct 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 pad;
114         uint32_t reserved[3];
115 };
116
117 /* The ext2 inode.  */
118 struct 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.  */
148 struct ext2_dirent {
149         uint32_t inode;
150         uint16_t direntlen;
151         uint8_t namelen;
152         uint8_t filetype;
153 };
154
155 struct 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.  */
163 struct ext2_data {
164         struct ext2_sblock sblock;
165         struct ext2_inode *inode;
166         struct ext2fs_node diropen;
167 };
168
169
170 typedef struct ext2fs_node *ext2fs_node_t;
171
172 struct ext2_data *ext2fs_root = NULL;
173 ext2fs_node_t ext2fs_file = NULL;
174 int symlinknest = 0;
175 uint32_t *indir1_block = NULL;
176 int indir1_size = 0;
177 int indir1_blkno = -1;
178 uint32_t *indir2_block = NULL;
179 int indir2_size = 0;
180 int indir2_blkno = -1;
181
182
183 static int ext2fs_blockgroup
184         (struct ext2_data *data, int group, struct ext2_block_group *blkgrp) {
185 #ifdef DEBUG
186         printf ("ext2fs read blockgroup\n");
187 #endif
188         return (ext2fs_devread
189                 (((__le32_to_cpu (data->sblock.first_data_block) +
190                    1) << LOG2_EXT2_BLOCK_SIZE (data)),
191                  group * sizeof (struct ext2_block_group),
192                  sizeof (struct ext2_block_group), (char *) blkgrp));
193 }
194
195
196 static int ext2fs_read_inode
197         (struct ext2_data *data, int ino, struct ext2_inode *inode) {
198         struct ext2_block_group blkgrp;
199         struct ext2_sblock *sblock = &data->sblock;
200         int inodes_per_block;
201         int status;
202
203         unsigned int blkno;
204         unsigned int blkoff;
205
206         /* It is easier to calculate if the first inode is 0.  */
207         ino--;
208 #ifdef DEBUG
209         printf ("ext2fs read inode %d\n", ino);
210 #endif
211         status = ext2fs_blockgroup (data,
212                                     ino /
213                                     __le32_to_cpu (sblock->inodes_per_group),
214                                     &blkgrp);
215         if (status == 0) {
216                 return (0);
217         }
218         inodes_per_block = EXT2_BLOCK_SIZE (data) / 128;
219         blkno = (ino % __le32_to_cpu (sblock->inodes_per_group)) /
220                 inodes_per_block;
221         blkoff = (ino % __le32_to_cpu (sblock->inodes_per_group)) %
222                 inodes_per_block;
223 #ifdef DEBUG
224         printf ("ext2fs read inode blkno %d blkoff %d\n", blkno, blkoff);
225 #endif
226         /* Read the inode.  */
227         status = ext2fs_devread (((__le32_to_cpu (blkgrp.inode_table_id) +
228                                    blkno) << LOG2_EXT2_BLOCK_SIZE (data)),
229                                  sizeof (struct ext2_inode) * blkoff,
230                                  sizeof (struct ext2_inode), (char *) inode);
231         if (status == 0) {
232                 return (0);
233         }
234         return (1);
235 }
236
237
238 void ext2fs_free_node (ext2fs_node_t node, ext2fs_node_t currroot) {
239         if ((node != &ext2fs_root->diropen) && (node != currroot)) {
240                 free (node);
241         }
242 }
243
244
245 static int ext2fs_read_block (ext2fs_node_t node, int fileblock) {
246         struct ext2_data *data = node->data;
247         struct ext2_inode *inode = &node->inode;
248         int blknr;
249         int blksz = EXT2_BLOCK_SIZE (data);
250         int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
251         int status;
252
253         /* Direct blocks.  */
254         if (fileblock < INDIRECT_BLOCKS) {
255                 blknr = __le32_to_cpu (inode->b.blocks.dir_blocks[fileblock]);
256         }
257         /* Indirect.  */
258         else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
259                 if (indir1_block == NULL) {
260                         indir1_block = (uint32_t *) malloc (blksz);
261                         if (indir1_block == NULL) {
262                                 printf ("** ext2fs read block (indir 1) malloc failed. **\n");
263                                 return (-1);
264                         }
265                         indir1_size = blksz;
266                         indir1_blkno = -1;
267                 }
268                 if (blksz != indir1_size) {
269                         free (indir1_block);
270                         indir1_block = NULL;
271                         indir1_size = 0;
272                         indir1_blkno = -1;
273                         indir1_block = (uint32_t *) malloc (blksz);
274                         if (indir1_block == NULL) {
275                                 printf ("** ext2fs read block (indir 1) malloc failed. **\n");
276                                 return (-1);
277                         }
278                         indir1_size = blksz;
279                 }
280                 if ((__le32_to_cpu (inode->b.blocks.indir_block) <<
281                      log2_blksz) != indir1_blkno) {
282                         status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.indir_block) << log2_blksz,
283                                                  0, blksz,
284                                                  (char *) indir1_block);
285                         if (status == 0) {
286                                 printf ("** ext2fs read block (indir 1) failed. **\n");
287                                 return (0);
288                         }
289                         indir1_blkno =
290                                 __le32_to_cpu (inode->b.blocks.
291                                                indir_block) << log2_blksz;
292                 }
293                 blknr = __le32_to_cpu (indir1_block
294                                        [fileblock - INDIRECT_BLOCKS]);
295         }
296         /* Double indirect.  */
297         else if (fileblock <
298                  (INDIRECT_BLOCKS + (blksz / 4 * (blksz / 4 + 1)))) {
299                 unsigned int perblock = blksz / 4;
300                 unsigned int rblock = fileblock - (INDIRECT_BLOCKS
301                                                    + blksz / 4);
302
303                 if (indir1_block == NULL) {
304                         indir1_block = (uint32_t *) malloc (blksz);
305                         if (indir1_block == NULL) {
306                                 printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
307                                 return (-1);
308                         }
309                         indir1_size = blksz;
310                         indir1_blkno = -1;
311                 }
312                 if (blksz != indir1_size) {
313                         free (indir1_block);
314                         indir1_block = NULL;
315                         indir1_size = 0;
316                         indir1_blkno = -1;
317                         indir1_block = (uint32_t *) malloc (blksz);
318                         if (indir1_block == NULL) {
319                                 printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
320                                 return (-1);
321                         }
322                         indir1_size = blksz;
323                 }
324                 if ((__le32_to_cpu (inode->b.blocks.double_indir_block) <<
325                      log2_blksz) != indir1_blkno) {
326                         status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz,
327                                                 0, blksz,
328                                                 (char *) indir1_block);
329                         if (status == 0) {
330                                 printf ("** ext2fs read block (indir 2 1) failed. **\n");
331                                 return (-1);
332                         }
333                         indir1_blkno =
334                                 __le32_to_cpu (inode->b.blocks.double_indir_block) << log2_blksz;
335                 }
336
337                 if (indir2_block == NULL) {
338                         indir2_block = (uint32_t *) malloc (blksz);
339                         if (indir2_block == NULL) {
340                                 printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
341                                 return (-1);
342                         }
343                         indir2_size = blksz;
344                         indir2_blkno = -1;
345                 }
346                 if (blksz != indir2_size) {
347                         free (indir2_block);
348                         indir2_block = NULL;
349                         indir2_size = 0;
350                         indir2_blkno = -1;
351                         indir2_block = (uint32_t *) malloc (blksz);
352                         if (indir2_block == NULL) {
353                                 printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
354                                 return (-1);
355                         }
356                         indir2_size = blksz;
357                 }
358                 if ((__le32_to_cpu (indir1_block[rblock / perblock]) <<
359                      log2_blksz) != indir1_blkno) {
360                         status = ext2fs_devread (__le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz,
361                                                  0, blksz,
362                                                  (char *) indir2_block);
363                         if (status == 0) {
364                                 printf ("** ext2fs read block (indir 2 2) failed. **\n");
365                                 return (-1);
366                         }
367                         indir2_blkno =
368                                 __le32_to_cpu (indir1_block[rblock / perblock]) << log2_blksz;
369                 }
370                 blknr = __le32_to_cpu (indir2_block[rblock % perblock]);
371         }
372         /* Tripple indirect.  */
373         else {
374                 printf ("** ext2fs doesn't support tripple indirect blocks. **\n");
375                 return (-1);
376         }
377 #ifdef DEBUG
378         printf ("ext2fs_read_block %08x\n", blknr);
379 #endif
380         return (blknr);
381 }
382
383
384 int ext2fs_read_file
385         (ext2fs_node_t node, int pos, unsigned int len, char *buf) {
386         int i;
387         int blockcnt;
388         int log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
389         int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
390         unsigned int filesize = __le32_to_cpu(node->inode.size);
391
392         /* Adjust len so it we can't read past the end of the file.  */
393         if (len > filesize) {
394                 len = filesize;
395         }
396         blockcnt = ((len + pos) + blocksize - 1) / blocksize;
397
398         for (i = pos / blocksize; i < blockcnt; i++) {
399                 int blknr;
400                 int blockoff = pos % blocksize;
401                 int blockend = blocksize;
402
403                 int skipfirst = 0;
404
405                 blknr = ext2fs_read_block (node, i);
406                 if (blknr < 0) {
407                         return (-1);
408                 }
409                 blknr = blknr << log2blocksize;
410
411                 /* Last block.  */
412                 if (i == blockcnt - 1) {
413                         blockend = (len + pos) % blocksize;
414
415                         /* The last portion is exactly blocksize.  */
416                         if (!blockend) {
417                                 blockend = blocksize;
418                         }
419                 }
420
421                 /* First block.  */
422                 if (i == pos / blocksize) {
423                         skipfirst = blockoff;
424                         blockend -= skipfirst;
425                 }
426
427                 /* If the block number is 0 this block is not stored on disk but
428                    is zero filled instead.  */
429                 if (blknr) {
430                         int status;
431
432                         status = ext2fs_devread (blknr, skipfirst, blockend, buf);
433                         if (status == 0) {
434                                 return (-1);
435                         }
436                 } else {
437                         memset (buf, 0, blocksize - skipfirst);
438                 }
439                 buf += blocksize - skipfirst;
440         }
441         return (len);
442 }
443
444
445 static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fnode, int *ftype)
446 {
447         unsigned int fpos = 0;
448         int status;
449         struct ext2fs_node *diro = (struct ext2fs_node *) dir;
450
451 #ifdef DEBUG
452         if (name != NULL)
453                 printf ("Iterate dir %s\n", name);
454 #endif /* of DEBUG */
455         if (!diro->inode_read) {
456                 status = ext2fs_read_inode (diro->data, diro->ino,
457                                             &diro->inode);
458                 if (status == 0) {
459                         return (0);
460                 }
461         }
462         /* Search the file.  */
463         while (fpos < __le32_to_cpu (diro->inode.size)) {
464                 struct ext2_dirent dirent;
465
466                 status = ext2fs_read_file (diro, fpos,
467                                            sizeof (struct ext2_dirent),
468                                            (char *) &dirent);
469                 if (status < 1) {
470                         return (0);
471                 }
472                 if (dirent.namelen != 0) {
473                         char filename[dirent.namelen + 1];
474                         ext2fs_node_t fdiro;
475                         int type = FILETYPE_UNKNOWN;
476
477                         status = ext2fs_read_file (diro,
478                                                    fpos + sizeof (struct ext2_dirent),
479                                                    dirent.namelen, filename);
480                         if (status < 1) {
481                                 return (0);
482                         }
483                         fdiro = malloc (sizeof (struct ext2fs_node));
484                         if (!fdiro) {
485                                 return (0);
486                         }
487
488                         fdiro->data = diro->data;
489                         fdiro->ino = __le32_to_cpu (dirent.inode);
490
491                         filename[dirent.namelen] = '\0';
492
493                         if (dirent.filetype != FILETYPE_UNKNOWN) {
494                                 fdiro->inode_read = 0;
495
496                                 if (dirent.filetype == FILETYPE_DIRECTORY) {
497                                         type = FILETYPE_DIRECTORY;
498                                 } else if (dirent.filetype ==
499                                            FILETYPE_SYMLINK) {
500                                         type = FILETYPE_SYMLINK;
501                                 } else if (dirent.filetype == FILETYPE_REG) {
502                                         type = FILETYPE_REG;
503                                 }
504                         } else {
505                                 /* The filetype can not be read from the dirent, get it from inode */
506
507                                 status = ext2fs_read_inode (diro->data,
508                                                             __le32_to_cpu(dirent.inode),
509                                                             &fdiro->inode);
510                                 if (status == 0) {
511                                         free (fdiro);
512                                         return (0);
513                                 }
514                                 fdiro->inode_read = 1;
515
516                                 if ((__le16_to_cpu (fdiro->inode.mode) &
517                                      FILETYPE_INO_MASK) ==
518                                     FILETYPE_INO_DIRECTORY) {
519                                         type = FILETYPE_DIRECTORY;
520                                 } else if ((__le16_to_cpu (fdiro->inode.mode)
521                                             & FILETYPE_INO_MASK) ==
522                                            FILETYPE_INO_SYMLINK) {
523                                         type = FILETYPE_SYMLINK;
524                                 } else if ((__le16_to_cpu (fdiro->inode.mode)
525                                             & FILETYPE_INO_MASK) ==
526                                            FILETYPE_INO_REG) {
527                                         type = FILETYPE_REG;
528                                 }
529                         }
530 #ifdef DEBUG
531                         printf ("iterate >%s<\n", filename);
532 #endif /* of DEBUG */
533                         if ((name != NULL) && (fnode != NULL)
534                             && (ftype != NULL)) {
535                                 if (strcmp (filename, name) == 0) {
536                                         *ftype = type;
537                                         *fnode = fdiro;
538                                         return (1);
539                                 }
540                         } else {
541                                 if (fdiro->inode_read == 0) {
542                                         status = ext2fs_read_inode (diro->data,
543                                                             __le32_to_cpu (dirent.inode),
544                                                             &fdiro->inode);
545                                         if (status == 0) {
546                                                 free (fdiro);
547                                                 return (0);
548                                         }
549                                         fdiro->inode_read = 1;
550                                 }
551                                 switch (type) {
552                                 case FILETYPE_DIRECTORY:
553                                         printf ("<DIR> ");
554                                         break;
555                                 case FILETYPE_SYMLINK:
556                                         printf ("<SYM> ");
557                                         break;
558                                 case FILETYPE_REG:
559                                         printf ("      ");
560                                         break;
561                                 default:
562                                         printf ("< ? > ");
563                                         break;
564                                 }
565                                 printf ("%10d %s\n",
566                                         __le32_to_cpu (fdiro->inode.size),
567                                         filename);
568                         }
569                         free (fdiro);
570                 }
571                 fpos += __le16_to_cpu (dirent.direntlen);
572         }
573         return (0);
574 }
575
576
577 static char *ext2fs_read_symlink (ext2fs_node_t node) {
578         char *symlink;
579         struct ext2fs_node *diro = node;
580         int status;
581
582         if (!diro->inode_read) {
583                 status = ext2fs_read_inode (diro->data, diro->ino,
584                                             &diro->inode);
585                 if (status == 0) {
586                         return (0);
587                 }
588         }
589         symlink = malloc (__le32_to_cpu (diro->inode.size) + 1);
590         if (!symlink) {
591                 return (0);
592         }
593         /* If the filesize of the symlink is bigger than
594            60 the symlink is stored in a separate block,
595            otherwise it is stored in the inode.  */
596         if (__le32_to_cpu (diro->inode.size) <= 60) {
597                 strncpy (symlink, diro->inode.b.symlink,
598                          __le32_to_cpu (diro->inode.size));
599         } else {
600                 status = ext2fs_read_file (diro, 0,
601                                            __le32_to_cpu (diro->inode.size),
602                                            symlink);
603                 if (status == 0) {
604                         free (symlink);
605                         return (0);
606                 }
607         }
608         symlink[__le32_to_cpu (diro->inode.size)] = '\0';
609         return (symlink);
610 }
611
612
613 int ext2fs_find_file1
614         (const char *currpath,
615          ext2fs_node_t currroot, ext2fs_node_t * currfound, int *foundtype) {
616         char fpath[strlen (currpath) + 1];
617         char *name = fpath;
618         char *next;
619         int status;
620         int type = FILETYPE_DIRECTORY;
621         ext2fs_node_t currnode = currroot;
622         ext2fs_node_t oldnode = currroot;
623
624         strncpy (fpath, currpath, strlen (currpath) + 1);
625
626         /* Remove all leading slashes.  */
627         while (*name == '/') {
628                 name++;
629         }
630         if (!*name) {
631                 *currfound = currnode;
632                 return (1);
633         }
634
635         for (;;) {
636                 int found;
637
638                 /* Extract the actual part from the pathname.  */
639                 next = strchr (name, '/');
640                 if (next) {
641                         /* Remove all leading slashes.  */
642                         while (*next == '/') {
643                                 *(next++) = '\0';
644                         }
645                 }
646
647                 /* At this point it is expected that the current node is a directory, check if this is true.  */
648                 if (type != FILETYPE_DIRECTORY) {
649                         ext2fs_free_node (currnode, currroot);
650                         return (0);
651                 }
652
653                 oldnode = currnode;
654
655                 /* Iterate over the directory.  */
656                 found = ext2fs_iterate_dir (currnode, name, &currnode, &type);
657                 if (found == 0) {
658                         return (0);
659                 }
660                 if (found == -1) {
661                         break;
662                 }
663
664                 /* Read in the symlink and follow it.  */
665                 if (type == FILETYPE_SYMLINK) {
666                         char *symlink;
667
668                         /* Test if the symlink does not loop.  */
669                         if (++symlinknest == 8) {
670                                 ext2fs_free_node (currnode, currroot);
671                                 ext2fs_free_node (oldnode, currroot);
672                                 return (0);
673                         }
674
675                         symlink = ext2fs_read_symlink (currnode);
676                         ext2fs_free_node (currnode, currroot);
677
678                         if (!symlink) {
679                                 ext2fs_free_node (oldnode, currroot);
680                                 return (0);
681                         }
682 #ifdef DEBUG
683                         printf ("Got symlink >%s<\n", symlink);
684 #endif /* of DEBUG */
685                         /* The symlink is an absolute path, go back to the root inode.  */
686                         if (symlink[0] == '/') {
687                                 ext2fs_free_node (oldnode, currroot);
688                                 oldnode = &ext2fs_root->diropen;
689                         }
690
691                         /* Lookup the node the symlink points to.  */
692                         status = ext2fs_find_file1 (symlink, oldnode,
693                                                     &currnode, &type);
694
695                         free (symlink);
696
697                         if (status == 0) {
698                                 ext2fs_free_node (oldnode, currroot);
699                                 return (0);
700                         }
701                 }
702
703                 ext2fs_free_node (oldnode, currroot);
704
705                 /* Found the node!  */
706                 if (!next || *next == '\0') {
707                         *currfound = currnode;
708                         *foundtype = type;
709                         return (1);
710                 }
711                 name = next;
712         }
713         return (-1);
714 }
715
716
717 int ext2fs_find_file
718         (const char *path,
719          ext2fs_node_t rootnode, ext2fs_node_t * foundnode, int expecttype) {
720         int status;
721         int foundtype = FILETYPE_DIRECTORY;
722
723
724         symlinknest = 0;
725         if (!path) {
726                 return (0);
727         }
728
729         status = ext2fs_find_file1 (path, rootnode, foundnode, &foundtype);
730         if (status == 0) {
731                 return (0);
732         }
733         /* Check if the node that was found was of the expected type.  */
734         if ((expecttype == FILETYPE_REG) && (foundtype != expecttype)) {
735                 return (0);
736         } else if ((expecttype == FILETYPE_DIRECTORY)
737                    && (foundtype != expecttype)) {
738                 return (0);
739         }
740         return (1);
741 }
742
743
744 int ext2fs_ls (char *dirname) {
745         ext2fs_node_t dirnode;
746         int status;
747
748         if (ext2fs_root == NULL) {
749                 return (0);
750         }
751
752         status = ext2fs_find_file (dirname, &ext2fs_root->diropen, &dirnode,
753                                    FILETYPE_DIRECTORY);
754         if (status != 1) {
755                 printf ("** Can not find directory. **\n");
756                 return (1);
757         }
758         ext2fs_iterate_dir (dirnode, NULL, NULL, NULL);
759         ext2fs_free_node (dirnode, &ext2fs_root->diropen);
760         return (0);
761 }
762
763
764 int ext2fs_open (char *filename) {
765         ext2fs_node_t fdiro = NULL;
766         int status;
767         int len;
768
769         if (ext2fs_root == NULL) {
770                 return (-1);
771         }
772         ext2fs_file = NULL;
773         status = ext2fs_find_file (filename, &ext2fs_root->diropen, &fdiro,
774                                    FILETYPE_REG);
775         if (status == 0) {
776                 goto fail;
777         }
778         if (!fdiro->inode_read) {
779                 status = ext2fs_read_inode (fdiro->data, fdiro->ino,
780                                             &fdiro->inode);
781                 if (status == 0) {
782                         goto fail;
783                 }
784         }
785         len = __le32_to_cpu (fdiro->inode.size);
786         ext2fs_file = fdiro;
787         return (len);
788
789 fail:
790         ext2fs_free_node (fdiro, &ext2fs_root->diropen);
791         return (-1);
792 }
793
794
795 int ext2fs_close (void
796         ) {
797         if ((ext2fs_file != NULL) && (ext2fs_root != NULL)) {
798                 ext2fs_free_node (ext2fs_file, &ext2fs_root->diropen);
799                 ext2fs_file = NULL;
800         }
801         if (ext2fs_root != NULL) {
802                 free (ext2fs_root);
803                 ext2fs_root = NULL;
804         }
805         if (indir1_block != NULL) {
806                 free (indir1_block);
807                 indir1_block = NULL;
808                 indir1_size = 0;
809                 indir1_blkno = -1;
810         }
811         if (indir2_block != NULL) {
812                 free (indir2_block);
813                 indir2_block = NULL;
814                 indir2_size = 0;
815                 indir2_blkno = -1;
816         }
817         return (0);
818 }
819
820
821 int ext2fs_read (char *buf, unsigned len) {
822         int status;
823
824         if (ext2fs_root == NULL) {
825                 return (0);
826         }
827
828         if (ext2fs_file == NULL) {
829                 return (0);
830         }
831
832         status = ext2fs_read_file (ext2fs_file, 0, len, buf);
833         return (status);
834 }
835
836
837 int ext2fs_mount (unsigned part_length) {
838         struct ext2_data *data;
839         int status;
840
841         data = malloc (sizeof (struct ext2_data));
842         if (!data) {
843                 return (0);
844         }
845         /* Read the superblock.  */
846         status = ext2fs_devread (1 * 2, 0, sizeof (struct ext2_sblock),
847                                  (char *) &data->sblock);
848         if (status == 0) {
849                 goto fail;
850         }
851         /* Make sure this is an ext2 filesystem.  */
852         if (__le16_to_cpu (data->sblock.magic) != EXT2_MAGIC) {
853                 goto fail;
854         }
855         data->diropen.data = data;
856         data->diropen.ino = 2;
857         data->diropen.inode_read = 1;
858         data->inode = &data->diropen.inode;
859
860         status = ext2fs_read_inode (data, 2, data->inode);
861         if (status == 0) {
862                 goto fail;
863         }
864
865         ext2fs_root = data;
866
867         return (1);
868
869 fail:
870         printf ("Failed to mount ext2 filesystem...\n");
871         free (data);
872         ext2fs_root = NULL;
873         return (0);
874 }