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