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