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