blob: 436f4a4aa92a0f7eaef694743c172b4f8c2482e3 [file] [log] [blame]
stroese15be8132004-12-16 17:26:24 +00001/*
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>
stroese15be8132004-12-16 17:26:24 +000027#include <ext2fs.h>
28#include <malloc.h>
29#include <asm/byteorder.h>
30
wdenk07d7e6b2004-12-16 21:44:03 +000031extern int ext2fs_devread (int sector, int byte_offset, int byte_len,
32 char *buf);
stroese15be8132004-12-16 17:26:24 +000033
34/* Magic value used to identify an ext2 filesystem. */
35#define EXT2_MAGIC 0xEF53
36/* Amount of indirect blocks in an inode. */
37#define INDIRECT_BLOCKS 12
38/* Maximum lenght of a pathname. */
39#define EXT2_PATH_MAX 4096
40/* Maximum nesting of symlinks, used to prevent a loop. */
41#define EXT2_MAX_SYMLINKCNT 8
42
43/* Filetype used in directory entry. */
44#define FILETYPE_UNKNOWN 0
45#define FILETYPE_REG 1
46#define FILETYPE_DIRECTORY 2
47#define FILETYPE_SYMLINK 7
48
49/* Filetype information as used in inodes. */
50#define FILETYPE_INO_MASK 0170000
51#define FILETYPE_INO_REG 0100000
52#define FILETYPE_INO_DIRECTORY 0040000
53#define FILETYPE_INO_SYMLINK 0120000
54
55/* Bits used as offset in sector */
56#define DISK_SECTOR_BITS 9
57
58/* Log2 size of ext2 block in 512 blocks. */
59#define LOG2_EXT2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 1)
60
61/* Log2 size of ext2 block in bytes. */
62#define LOG2_BLOCK_SIZE(data) (__le32_to_cpu (data->sblock.log2_block_size) + 10)
63
64/* The size of an ext2 block in bytes. */
65#define EXT2_BLOCK_SIZE(data) (1 << LOG2_BLOCK_SIZE(data))
66
67/* The ext2 superblock. */
wdenk07d7e6b2004-12-16 21:44:03 +000068struct ext2_sblock {
stroese15be8132004-12-16 17:26:24 +000069 uint32_t total_inodes;
70 uint32_t total_blocks;
71 uint32_t reserved_blocks;
72 uint32_t free_blocks;
73 uint32_t free_inodes;
74 uint32_t first_data_block;
75 uint32_t log2_block_size;
76 uint32_t log2_fragment_size;
77 uint32_t blocks_per_group;
78 uint32_t fragments_per_group;
79 uint32_t inodes_per_group;
80 uint32_t mtime;
81 uint32_t utime;
82 uint16_t mnt_count;
83 uint16_t max_mnt_count;
84 uint16_t magic;
85 uint16_t fs_state;
86 uint16_t error_handling;
87 uint16_t minor_revision_level;
88 uint32_t lastcheck;
89 uint32_t checkinterval;
90 uint32_t creator_os;
91 uint32_t revision_level;
92 uint16_t uid_reserved;
93 uint16_t gid_reserved;
94 uint32_t first_inode;
95 uint16_t inode_size;
96 uint16_t block_group_number;
97 uint32_t feature_compatibility;
98 uint32_t feature_incompat;
99 uint32_t feature_ro_compat;
100 uint32_t unique_id[4];
101 char volume_name[16];
102 char last_mounted_on[64];
103 uint32_t compression_info;
104};
105
106/* The ext2 blockgroup. */
wdenk07d7e6b2004-12-16 21:44:03 +0000107struct ext2_block_group {
stroese15be8132004-12-16 17:26:24 +0000108 uint32_t block_id;
109 uint32_t inode_id;
110 uint32_t inode_table_id;
111 uint16_t free_blocks;
112 uint16_t free_inodes;
113 uint16_t pad;
114 uint32_t reserved[3];
115};
116
117/* The ext2 inode. */
wdenk07d7e6b2004-12-16 21:44:03 +0000118struct ext2_inode {
stroese15be8132004-12-16 17:26:24 +0000119 uint16_t mode;
120 uint16_t uid;
121 uint32_t size;
122 uint32_t atime;
123 uint32_t ctime;
124 uint32_t mtime;
125 uint32_t dtime;
126 uint16_t gid;
127 uint16_t nlinks;
wdenk07d7e6b2004-12-16 21:44:03 +0000128 uint32_t blockcnt; /* Blocks of 512 bytes!! */
stroese15be8132004-12-16 17:26:24 +0000129 uint32_t flags;
130 uint32_t osd1;
wdenk07d7e6b2004-12-16 21:44:03 +0000131 union {
132 struct datablocks {
stroese15be8132004-12-16 17:26:24 +0000133 uint32_t dir_blocks[INDIRECT_BLOCKS];
134 uint32_t indir_block;
135 uint32_t double_indir_block;
136 uint32_t tripple_indir_block;
137 } blocks;
138 char symlink[60];
wdenk07d7e6b2004-12-16 21:44:03 +0000139 } b;
stroese15be8132004-12-16 17:26:24 +0000140 uint32_t version;
141 uint32_t acl;
142 uint32_t dir_acl;
143 uint32_t fragment_addr;
144 uint32_t osd2[3];
145};
146
147/* The header of an ext2 directory entry. */
wdenk07d7e6b2004-12-16 21:44:03 +0000148struct ext2_dirent {
stroese15be8132004-12-16 17:26:24 +0000149 uint32_t inode;
150 uint16_t direntlen;
wdenk07d7e6b2004-12-16 21:44:03 +0000151 uint8_t namelen;
152 uint8_t filetype;
stroese15be8132004-12-16 17:26:24 +0000153};
154
wdenk07d7e6b2004-12-16 21:44:03 +0000155struct ext2fs_node {
stroese15be8132004-12-16 17:26:24 +0000156 struct ext2_data *data;
157 struct ext2_inode inode;
wdenk07d7e6b2004-12-16 21:44:03 +0000158 int ino;
159 int inode_read;
stroese15be8132004-12-16 17:26:24 +0000160};
161
162/* Information about a "mounted" ext2 filesystem. */
wdenk07d7e6b2004-12-16 21:44:03 +0000163struct ext2_data {
stroese15be8132004-12-16 17:26:24 +0000164 struct ext2_sblock sblock;
165 struct ext2_inode *inode;
166 struct ext2fs_node diropen;
167};
168
169
170typedef struct ext2fs_node *ext2fs_node_t;
171
wdenk07d7e6b2004-12-16 21:44:03 +0000172struct ext2_data *ext2fs_root = NULL;
173ext2fs_node_t ext2fs_file = NULL;
174int symlinknest = 0;
175uint32_t *indir1_block = NULL;
176int indir1_size = 0;
177int indir1_blkno = -1;
178uint32_t *indir2_block = NULL;
179int indir2_size = 0;
180int indir2_blkno = -1;
stroese15be8132004-12-16 17:26:24 +0000181
182
183static int ext2fs_blockgroup
wdenk07d7e6b2004-12-16 21:44:03 +0000184 (struct ext2_data *data, int group, struct ext2_block_group *blkgrp) {
stroese15be8132004-12-16 17:26:24 +0000185#ifdef DEBUG
wdenk07d7e6b2004-12-16 21:44:03 +0000186 printf ("ext2fs read blockgroup\n");
stroese15be8132004-12-16 17:26:24 +0000187#endif
wdenk07d7e6b2004-12-16 21:44:03 +0000188 return (ext2fs_devread
189 (((__le32_to_cpu (data->sblock.first_data_block) +
190 1) << LOG2_EXT2_BLOCK_SIZE (data)),
191 group * sizeof (struct ext2_block_group),
192 sizeof (struct ext2_block_group), (char *) blkgrp));
stroese15be8132004-12-16 17:26:24 +0000193}
194
195
196static int ext2fs_read_inode
wdenk07d7e6b2004-12-16 21:44:03 +0000197 (struct ext2_data *data, int ino, struct ext2_inode *inode) {
198 struct ext2_block_group blkgrp;
199 struct ext2_sblock *sblock = &data->sblock;
200 int inodes_per_block;
201 int status;
stroese15be8132004-12-16 17:26:24 +0000202
wdenk07d7e6b2004-12-16 21:44:03 +0000203 unsigned int blkno;
204 unsigned int blkoff;
stroese15be8132004-12-16 17:26:24 +0000205
206 /* It is easier to calculate if the first inode is 0. */
207 ino--;
208#ifdef DEBUG
wdenk07d7e6b2004-12-16 21:44:03 +0000209 printf ("ext2fs read inode %d\n", ino);
stroese15be8132004-12-16 17:26:24 +0000210#endif
wdenk07d7e6b2004-12-16 21:44:03 +0000211 status = ext2fs_blockgroup (data,
212 ino /
213 __le32_to_cpu (sblock->inodes_per_group),
214 &blkgrp);
215 if (status == 0) {
216 return (0);
stroese15be8132004-12-16 17:26:24 +0000217 }
218 inodes_per_block = EXT2_BLOCK_SIZE (data) / 128;
wdenk07d7e6b2004-12-16 21:44:03 +0000219 blkno = (ino % __le32_to_cpu (sblock->inodes_per_group)) /
220 inodes_per_block;
221 blkoff = (ino % __le32_to_cpu (sblock->inodes_per_group)) %
222 inodes_per_block;
stroese15be8132004-12-16 17:26:24 +0000223#ifdef DEBUG
wdenk07d7e6b2004-12-16 21:44:03 +0000224 printf ("ext2fs read inode blkno %d blkoff %d\n", blkno, blkoff);
stroese15be8132004-12-16 17:26:24 +0000225#endif
226 /* Read the inode. */
wdenk07d7e6b2004-12-16 21:44:03 +0000227 status = ext2fs_devread (((__le32_to_cpu (blkgrp.inode_table_id) +
228 blkno) << LOG2_EXT2_BLOCK_SIZE (data)),
229 sizeof (struct ext2_inode) * blkoff,
230 sizeof (struct ext2_inode), (char *) inode);
231 if (status == 0) {
232 return (0);
stroese15be8132004-12-16 17:26:24 +0000233 }
wdenk07d7e6b2004-12-16 21:44:03 +0000234 return (1);
stroese15be8132004-12-16 17:26:24 +0000235}
236
237
wdenk07d7e6b2004-12-16 21:44:03 +0000238void ext2fs_free_node (ext2fs_node_t node, ext2fs_node_t currroot) {
239 if ((node != &ext2fs_root->diropen) && (node != currroot)) {
stroese15be8132004-12-16 17:26:24 +0000240 free (node);
241 }
242}
243
244
wdenk07d7e6b2004-12-16 21:44:03 +0000245static int ext2fs_read_block (ext2fs_node_t node, int fileblock) {
246 struct ext2_data *data = node->data;
247 struct ext2_inode *inode = &node->inode;
248 int blknr;
249 int blksz = EXT2_BLOCK_SIZE (data);
250 int log2_blksz = LOG2_EXT2_BLOCK_SIZE (data);
251 int status;
stroese15be8132004-12-16 17:26:24 +0000252
253 /* Direct blocks. */
wdenk07d7e6b2004-12-16 21:44:03 +0000254 if (fileblock < INDIRECT_BLOCKS) {
stroese15be8132004-12-16 17:26:24 +0000255 blknr = __le32_to_cpu (inode->b.blocks.dir_blocks[fileblock]);
wdenk07d7e6b2004-12-16 21:44:03 +0000256 }
stroese15be8132004-12-16 17:26:24 +0000257 /* Indirect. */
wdenk07d7e6b2004-12-16 21:44:03 +0000258 else if (fileblock < (INDIRECT_BLOCKS + (blksz / 4))) {
259 if (indir1_block == NULL) {
260 indir1_block = (uint32_t *) malloc (blksz);
261 if (indir1_block == NULL) {
262 printf ("** ext2fs read block (indir 1) malloc failed. **\n");
263 return (-1);
stroese15be8132004-12-16 17:26:24 +0000264 }
wdenk07d7e6b2004-12-16 21:44:03 +0000265 indir1_size = blksz;
stroese15be8132004-12-16 17:26:24 +0000266 indir1_blkno = -1;
267 }
wdenk07d7e6b2004-12-16 21:44:03 +0000268 if (blksz != indir1_size) {
269 free (indir1_block);
stroese15be8132004-12-16 17:26:24 +0000270 indir1_block = NULL;
wdenk07d7e6b2004-12-16 21:44:03 +0000271 indir1_size = 0;
stroese15be8132004-12-16 17:26:24 +0000272 indir1_blkno = -1;
wdenk07d7e6b2004-12-16 21:44:03 +0000273 indir1_block = (uint32_t *) malloc (blksz);
274 if (indir1_block == NULL) {
275 printf ("** ext2fs read block (indir 1) malloc failed. **\n");
276 return (-1);
stroese15be8132004-12-16 17:26:24 +0000277 }
wdenk07d7e6b2004-12-16 21:44:03 +0000278 indir1_size = blksz;
stroese15be8132004-12-16 17:26:24 +0000279 }
wdenk07d7e6b2004-12-16 21:44:03 +0000280 if ((__le32_to_cpu (inode->b.blocks.indir_block) <<
281 log2_blksz) != indir1_blkno) {
282 status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.indir_block) << log2_blksz,
283 0, blksz,
284 (char *) indir1_block);
285 if (status == 0) {
286 printf ("** ext2fs read block (indir 1) failed. **\n");
287 return (0);
stroese15be8132004-12-16 17:26:24 +0000288 }
wdenk07d7e6b2004-12-16 21:44:03 +0000289 indir1_blkno =
290 __le32_to_cpu (inode->b.blocks.
291 indir_block) << log2_blksz;
stroese15be8132004-12-16 17:26:24 +0000292 }
wdenk07d7e6b2004-12-16 21:44:03 +0000293 blknr = __le32_to_cpu (indir1_block
294 [fileblock - INDIRECT_BLOCKS]);
stroese15be8132004-12-16 17:26:24 +0000295 }
296 /* Double indirect. */
wdenk07d7e6b2004-12-16 21:44:03 +0000297 else if (fileblock <
298 (INDIRECT_BLOCKS + (blksz / 4 * (blksz / 4 + 1)))) {
stroese15be8132004-12-16 17:26:24 +0000299 unsigned int perblock = blksz / 4;
300 unsigned int rblock = fileblock - (INDIRECT_BLOCKS
301 + blksz / 4);
302
wdenk07d7e6b2004-12-16 21:44:03 +0000303 if (indir1_block == NULL) {
304 indir1_block = (uint32_t *) malloc (blksz);
305 if (indir1_block == NULL) {
306 printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
307 return (-1);
stroese15be8132004-12-16 17:26:24 +0000308 }
wdenk07d7e6b2004-12-16 21:44:03 +0000309 indir1_size = blksz;
stroese15be8132004-12-16 17:26:24 +0000310 indir1_blkno = -1;
311 }
wdenk07d7e6b2004-12-16 21:44:03 +0000312 if (blksz != indir1_size) {
313 free (indir1_block);
stroese15be8132004-12-16 17:26:24 +0000314 indir1_block = NULL;
wdenk07d7e6b2004-12-16 21:44:03 +0000315 indir1_size = 0;
stroese15be8132004-12-16 17:26:24 +0000316 indir1_blkno = -1;
wdenk07d7e6b2004-12-16 21:44:03 +0000317 indir1_block = (uint32_t *) malloc (blksz);
318 if (indir1_block == NULL) {
319 printf ("** ext2fs read block (indir 2 1) malloc failed. **\n");
320 return (-1);
stroese15be8132004-12-16 17:26:24 +0000321 }
wdenk07d7e6b2004-12-16 21:44:03 +0000322 indir1_size = blksz;
stroese15be8132004-12-16 17:26:24 +0000323 }
wdenk07d7e6b2004-12-16 21:44:03 +0000324 if ((__le32_to_cpu (inode->b.blocks.double_indir_block) <<
325 log2_blksz) != indir1_blkno) {
326 status = ext2fs_devread (__le32_to_cpu(inode->b.blocks.double_indir_block) << log2_blksz,
327 0, blksz,
328 (char *) indir1_block);
329 if (status == 0) {
330 printf ("** ext2fs read block (indir 2 1) failed. **\n");
331 return (-1);
stroese15be8132004-12-16 17:26:24 +0000332 }
wdenk07d7e6b2004-12-16 21:44:03 +0000333 indir1_blkno =
334 __le32_to_cpu (inode->b.blocks.double_indir_block) << log2_blksz;
stroese15be8132004-12-16 17:26:24 +0000335 }
336
wdenk07d7e6b2004-12-16 21:44:03 +0000337 if (indir2_block == NULL) {
338 indir2_block = (uint32_t *) malloc (blksz);
339 if (indir2_block == NULL) {
340 printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
341 return (-1);
stroese15be8132004-12-16 17:26:24 +0000342 }
wdenk07d7e6b2004-12-16 21:44:03 +0000343 indir2_size = blksz;
stroese15be8132004-12-16 17:26:24 +0000344 indir2_blkno = -1;
345 }
wdenk07d7e6b2004-12-16 21:44:03 +0000346 if (blksz != indir2_size) {
347 free (indir2_block);
stroese15be8132004-12-16 17:26:24 +0000348 indir2_block = NULL;
wdenk07d7e6b2004-12-16 21:44:03 +0000349 indir2_size = 0;
stroese15be8132004-12-16 17:26:24 +0000350 indir2_blkno = -1;
wdenk07d7e6b2004-12-16 21:44:03 +0000351 indir2_block = (uint32_t *) malloc (blksz);
352 if (indir2_block == NULL) {
353 printf ("** ext2fs read block (indir 2 2) malloc failed. **\n");
354 return (-1);
stroese15be8132004-12-16 17:26:24 +0000355 }
wdenk07d7e6b2004-12-16 21:44:03 +0000356 indir2_size = blksz;
stroese15be8132004-12-16 17:26:24 +0000357 }
wdenk07d7e6b2004-12-16 21:44:03 +0000358 if ((__le32_to_cpu (indir1_block[rblock / perblock]) <<
359 log2_blksz) != indir1_blkno) {
360 status = ext2fs_devread (__le32_to_cpu(indir1_block[rblock / perblock]) << log2_blksz,
361 0, blksz,
362 (char *) indir2_block);
363 if (status == 0) {
364 printf ("** ext2fs read block (indir 2 2) failed. **\n");
365 return (-1);
stroese15be8132004-12-16 17:26:24 +0000366 }
wdenk07d7e6b2004-12-16 21:44:03 +0000367 indir2_blkno =
368 __le32_to_cpu (indir1_block[rblock / perblock]) << log2_blksz;
stroese15be8132004-12-16 17:26:24 +0000369 }
wdenk07d7e6b2004-12-16 21:44:03 +0000370 blknr = __le32_to_cpu (indir2_block[rblock % perblock]);
stroese15be8132004-12-16 17:26:24 +0000371 }
372 /* Tripple indirect. */
wdenk07d7e6b2004-12-16 21:44:03 +0000373 else {
374 printf ("** ext2fs doesn't support tripple indirect blocks. **\n");
375 return (-1);
376 }
stroese15be8132004-12-16 17:26:24 +0000377#ifdef DEBUG
wdenk07d7e6b2004-12-16 21:44:03 +0000378 printf ("ext2fs_read_block %08x\n", blknr);
stroese15be8132004-12-16 17:26:24 +0000379#endif
wdenk07d7e6b2004-12-16 21:44:03 +0000380 return (blknr);
stroese15be8132004-12-16 17:26:24 +0000381}
382
383
384int ext2fs_read_file
wdenk07d7e6b2004-12-16 21:44:03 +0000385 (ext2fs_node_t node, int pos, unsigned int len, char *buf) {
386 int i;
387 int blockcnt;
388 int log2blocksize = LOG2_EXT2_BLOCK_SIZE (node->data);
389 int blocksize = 1 << (log2blocksize + DISK_SECTOR_BITS);
Stefan Roeseb7a97c72006-01-18 20:05:34 +0100390 unsigned int filesize = __le32_to_cpu(node->inode.size);
stroese15be8132004-12-16 17:26:24 +0000391
392 /* Adjust len so it we can't read past the end of the file. */
wdenk07d7e6b2004-12-16 21:44:03 +0000393 if (len > filesize) {
stroese15be8132004-12-16 17:26:24 +0000394 len = filesize;
395 }
wdenk07d7e6b2004-12-16 21:44:03 +0000396 blockcnt = ((len + pos) + blocksize - 1) / blocksize;
stroese15be8132004-12-16 17:26:24 +0000397
wdenk07d7e6b2004-12-16 21:44:03 +0000398 for (i = pos / blocksize; i < blockcnt; i++) {
stroese15be8132004-12-16 17:26:24 +0000399 int blknr;
400 int blockoff = pos % blocksize;
401 int blockend = blocksize;
402
403 int skipfirst = 0;
404
wdenk07d7e6b2004-12-16 21:44:03 +0000405 blknr = ext2fs_read_block (node, i);
406 if (blknr < 0) {
407 return (-1);
stroese15be8132004-12-16 17:26:24 +0000408 }
409 blknr = blknr << log2blocksize;
410
411 /* Last block. */
wdenk07d7e6b2004-12-16 21:44:03 +0000412 if (i == blockcnt - 1) {
stroese15be8132004-12-16 17:26:24 +0000413 blockend = (len + pos) % blocksize;
414
415 /* The last portion is exactly blocksize. */
wdenk07d7e6b2004-12-16 21:44:03 +0000416 if (!blockend) {
stroese15be8132004-12-16 17:26:24 +0000417 blockend = blocksize;
418 }
419 }
420
421 /* First block. */
wdenk07d7e6b2004-12-16 21:44:03 +0000422 if (i == pos / blocksize) {
stroese15be8132004-12-16 17:26:24 +0000423 skipfirst = blockoff;
424 blockend -= skipfirst;
425 }
426
427 /* If the block number is 0 this block is not stored on disk but
428 is zero filled instead. */
wdenk07d7e6b2004-12-16 21:44:03 +0000429 if (blknr) {
stroese15be8132004-12-16 17:26:24 +0000430 int status;
431
432 status = ext2fs_devread (blknr, skipfirst, blockend, buf);
wdenk07d7e6b2004-12-16 21:44:03 +0000433 if (status == 0) {
434 return (-1);
stroese15be8132004-12-16 17:26:24 +0000435 }
wdenk07d7e6b2004-12-16 21:44:03 +0000436 } else {
Wolfgang Denk51fbbb72008-01-09 10:16:33 +0100437 memset (buf, 0, blocksize - skipfirst);
stroese15be8132004-12-16 17:26:24 +0000438 }
439 buf += blocksize - skipfirst;
wdenk07d7e6b2004-12-16 21:44:03 +0000440 }
441 return (len);
stroese15be8132004-12-16 17:26:24 +0000442}
443
444
wdenk07d7e6b2004-12-16 21:44:03 +0000445static int ext2fs_iterate_dir (ext2fs_node_t dir, char *name, ext2fs_node_t * fnode, int *ftype)
stroese15be8132004-12-16 17:26:24 +0000446{
447 unsigned int fpos = 0;
wdenk07d7e6b2004-12-16 21:44:03 +0000448 int status;
stroese15be8132004-12-16 17:26:24 +0000449 struct ext2fs_node *diro = (struct ext2fs_node *) dir;
wdenk07d7e6b2004-12-16 21:44:03 +0000450
stroese15be8132004-12-16 17:26:24 +0000451#ifdef DEBUG
wdenk07d7e6b2004-12-16 21:44:03 +0000452 if (name != NULL)
453 printf ("Iterate dir %s\n", name);
stroese15be8132004-12-16 17:26:24 +0000454#endif /* of DEBUG */
wdenk07d7e6b2004-12-16 21:44:03 +0000455 if (!diro->inode_read) {
456 status = ext2fs_read_inode (diro->data, diro->ino,
457 &diro->inode);
458 if (status == 0) {
459 return (0);
stroese15be8132004-12-16 17:26:24 +0000460 }
461 }
462 /* Search the file. */
wdenk07d7e6b2004-12-16 21:44:03 +0000463 while (fpos < __le32_to_cpu (diro->inode.size)) {
stroese15be8132004-12-16 17:26:24 +0000464 struct ext2_dirent dirent;
465
wdenk07d7e6b2004-12-16 21:44:03 +0000466 status = ext2fs_read_file (diro, fpos,
467 sizeof (struct ext2_dirent),
468 (char *) &dirent);
469 if (status < 1) {
470 return (0);
stroese15be8132004-12-16 17:26:24 +0000471 }
wdenk07d7e6b2004-12-16 21:44:03 +0000472 if (dirent.namelen != 0) {
473 char filename[dirent.namelen + 1];
474 ext2fs_node_t fdiro;
475 int type = FILETYPE_UNKNOWN;
stroese15be8132004-12-16 17:26:24 +0000476
wdenk07d7e6b2004-12-16 21:44:03 +0000477 status = ext2fs_read_file (diro,
478 fpos + sizeof (struct ext2_dirent),
479 dirent.namelen, filename);
480 if (status < 1) {
481 return (0);
stroese15be8132004-12-16 17:26:24 +0000482 }
483 fdiro = malloc (sizeof (struct ext2fs_node));
wdenk07d7e6b2004-12-16 21:44:03 +0000484 if (!fdiro) {
485 return (0);
stroese15be8132004-12-16 17:26:24 +0000486 }
487
488 fdiro->data = diro->data;
wdenk07d7e6b2004-12-16 21:44:03 +0000489 fdiro->ino = __le32_to_cpu (dirent.inode);
stroese15be8132004-12-16 17:26:24 +0000490
491 filename[dirent.namelen] = '\0';
492
wdenk07d7e6b2004-12-16 21:44:03 +0000493 if (dirent.filetype != FILETYPE_UNKNOWN) {
stroese15be8132004-12-16 17:26:24 +0000494 fdiro->inode_read = 0;
495
wdenk07d7e6b2004-12-16 21:44:03 +0000496 if (dirent.filetype == FILETYPE_DIRECTORY) {
stroese15be8132004-12-16 17:26:24 +0000497 type = FILETYPE_DIRECTORY;
wdenk07d7e6b2004-12-16 21:44:03 +0000498 } else if (dirent.filetype ==
499 FILETYPE_SYMLINK) {
stroese15be8132004-12-16 17:26:24 +0000500 type = FILETYPE_SYMLINK;
wdenk07d7e6b2004-12-16 21:44:03 +0000501 } else if (dirent.filetype == FILETYPE_REG) {
502 type = FILETYPE_REG;
stroese15be8132004-12-16 17:26:24 +0000503 }
wdenk07d7e6b2004-12-16 21:44:03 +0000504 } else {
stroese15be8132004-12-16 17:26:24 +0000505 /* The filetype can not be read from the dirent, get it from inode */
506
wdenk07d7e6b2004-12-16 21:44:03 +0000507 status = ext2fs_read_inode (diro->data,
508 __le32_to_cpu(dirent.inode),
509 &fdiro->inode);
510 if (status == 0) {
511 free (fdiro);
512 return (0);
stroese15be8132004-12-16 17:26:24 +0000513 }
514 fdiro->inode_read = 1;
515
wdenk07d7e6b2004-12-16 21:44:03 +0000516 if ((__le16_to_cpu (fdiro->inode.mode) &
517 FILETYPE_INO_MASK) ==
518 FILETYPE_INO_DIRECTORY) {
stroese15be8132004-12-16 17:26:24 +0000519 type = FILETYPE_DIRECTORY;
wdenk07d7e6b2004-12-16 21:44:03 +0000520 } else if ((__le16_to_cpu (fdiro->inode.mode)
521 & FILETYPE_INO_MASK) ==
522 FILETYPE_INO_SYMLINK) {
stroese15be8132004-12-16 17:26:24 +0000523 type = FILETYPE_SYMLINK;
wdenk07d7e6b2004-12-16 21:44:03 +0000524 } else if ((__le16_to_cpu (fdiro->inode.mode)
525 & FILETYPE_INO_MASK) ==
526 FILETYPE_INO_REG) {
stroese15be8132004-12-16 17:26:24 +0000527 type = FILETYPE_REG;
528 }
529 }
530#ifdef DEBUG
wdenk07d7e6b2004-12-16 21:44:03 +0000531 printf ("iterate >%s<\n", filename);
stroese15be8132004-12-16 17:26:24 +0000532#endif /* of DEBUG */
wdenk07d7e6b2004-12-16 21:44:03 +0000533 if ((name != NULL) && (fnode != NULL)
534 && (ftype != NULL)) {
535 if (strcmp (filename, name) == 0) {
stroese15be8132004-12-16 17:26:24 +0000536 *ftype = type;
537 *fnode = fdiro;
wdenk07d7e6b2004-12-16 21:44:03 +0000538 return (1);
stroese15be8132004-12-16 17:26:24 +0000539 }
wdenk07d7e6b2004-12-16 21:44:03 +0000540 } else {
541 if (fdiro->inode_read == 0) {
542 status = ext2fs_read_inode (diro->data,
543 __le32_to_cpu (dirent.inode),
544 &fdiro->inode);
545 if (status == 0) {
546 free (fdiro);
547 return (0);
stroese15be8132004-12-16 17:26:24 +0000548 }
549 fdiro->inode_read = 1;
550 }
wdenk07d7e6b2004-12-16 21:44:03 +0000551 switch (type) {
stroese15be8132004-12-16 17:26:24 +0000552 case FILETYPE_DIRECTORY:
wdenk07d7e6b2004-12-16 21:44:03 +0000553 printf ("<DIR> ");
stroese15be8132004-12-16 17:26:24 +0000554 break;
555 case FILETYPE_SYMLINK:
wdenk07d7e6b2004-12-16 21:44:03 +0000556 printf ("<SYM> ");
stroese15be8132004-12-16 17:26:24 +0000557 break;
558 case FILETYPE_REG:
wdenk07d7e6b2004-12-16 21:44:03 +0000559 printf (" ");
stroese15be8132004-12-16 17:26:24 +0000560 break;
561 default:
wdenk11392db2004-12-19 09:58:11 +0000562 printf ("< ? > ");
stroese15be8132004-12-16 17:26:24 +0000563 break;
564 }
wdenk07d7e6b2004-12-16 21:44:03 +0000565 printf ("%10d %s\n",
566 __le32_to_cpu (fdiro->inode.size),
567 filename);
stroese15be8132004-12-16 17:26:24 +0000568 }
wdenk07d7e6b2004-12-16 21:44:03 +0000569 free (fdiro);
stroese15be8132004-12-16 17:26:24 +0000570 }
571 fpos += __le16_to_cpu (dirent.direntlen);
572 }
wdenk07d7e6b2004-12-16 21:44:03 +0000573 return (0);
stroese15be8132004-12-16 17:26:24 +0000574}
575
576
wdenk07d7e6b2004-12-16 21:44:03 +0000577static char *ext2fs_read_symlink (ext2fs_node_t node) {
578 char *symlink;
stroese15be8132004-12-16 17:26:24 +0000579 struct ext2fs_node *diro = node;
wdenk07d7e6b2004-12-16 21:44:03 +0000580 int status;
stroese15be8132004-12-16 17:26:24 +0000581
wdenk07d7e6b2004-12-16 21:44:03 +0000582 if (!diro->inode_read) {
583 status = ext2fs_read_inode (diro->data, diro->ino,
584 &diro->inode);
585 if (status == 0) {
586 return (0);
stroese15be8132004-12-16 17:26:24 +0000587 }
588 }
589 symlink = malloc (__le32_to_cpu (diro->inode.size) + 1);
wdenk07d7e6b2004-12-16 21:44:03 +0000590 if (!symlink) {
591 return (0);
stroese15be8132004-12-16 17:26:24 +0000592 }
593 /* If the filesize of the symlink is bigger than
594 60 the symlink is stored in a separate block,
595 otherwise it is stored in the inode. */
wdenk07d7e6b2004-12-16 21:44:03 +0000596 if (__le32_to_cpu (diro->inode.size) <= 60) {
597 strncpy (symlink, diro->inode.b.symlink,
598 __le32_to_cpu (diro->inode.size));
599 } else {
600 status = ext2fs_read_file (diro, 0,
601 __le32_to_cpu (diro->inode.size),
602 symlink);
603 if (status == 0) {
stroese15be8132004-12-16 17:26:24 +0000604 free (symlink);
wdenk07d7e6b2004-12-16 21:44:03 +0000605 return (0);
stroese15be8132004-12-16 17:26:24 +0000606 }
607 }
608 symlink[__le32_to_cpu (diro->inode.size)] = '\0';
wdenk07d7e6b2004-12-16 21:44:03 +0000609 return (symlink);
stroese15be8132004-12-16 17:26:24 +0000610}
611
612
613int ext2fs_find_file1
wdenk07d7e6b2004-12-16 21:44:03 +0000614 (const char *currpath,
615 ext2fs_node_t currroot, ext2fs_node_t * currfound, int *foundtype) {
616 char fpath[strlen (currpath) + 1];
617 char *name = fpath;
618 char *next;
619 int status;
620 int type = FILETYPE_DIRECTORY;
621 ext2fs_node_t currnode = currroot;
622 ext2fs_node_t oldnode = currroot;
stroese15be8132004-12-16 17:26:24 +0000623
624 strncpy (fpath, currpath, strlen (currpath) + 1);
625
626 /* Remove all leading slashes. */
wdenk07d7e6b2004-12-16 21:44:03 +0000627 while (*name == '/') {
stroese15be8132004-12-16 17:26:24 +0000628 name++;
wdenk07d7e6b2004-12-16 21:44:03 +0000629 }
630 if (!*name) {
stroese15be8132004-12-16 17:26:24 +0000631 *currfound = currnode;
wdenk07d7e6b2004-12-16 21:44:03 +0000632 return (1);
stroese15be8132004-12-16 17:26:24 +0000633 }
634
wdenk07d7e6b2004-12-16 21:44:03 +0000635 for (;;) {
stroese15be8132004-12-16 17:26:24 +0000636 int found;
637
638 /* Extract the actual part from the pathname. */
639 next = strchr (name, '/');
wdenk07d7e6b2004-12-16 21:44:03 +0000640 if (next) {
stroese15be8132004-12-16 17:26:24 +0000641 /* Remove all leading slashes. */
wdenk07d7e6b2004-12-16 21:44:03 +0000642 while (*next == '/') {
stroese15be8132004-12-16 17:26:24 +0000643 *(next++) = '\0';
644 }
645 }
646
647 /* At this point it is expected that the current node is a directory, check if this is true. */
wdenk07d7e6b2004-12-16 21:44:03 +0000648 if (type != FILETYPE_DIRECTORY) {
stroese15be8132004-12-16 17:26:24 +0000649 ext2fs_free_node (currnode, currroot);
wdenk07d7e6b2004-12-16 21:44:03 +0000650 return (0);
stroese15be8132004-12-16 17:26:24 +0000651 }
652
653 oldnode = currnode;
654
655 /* Iterate over the directory. */
656 found = ext2fs_iterate_dir (currnode, name, &currnode, &type);
wdenk07d7e6b2004-12-16 21:44:03 +0000657 if (found == 0) {
658 return (0);
stroese15be8132004-12-16 17:26:24 +0000659 }
wdenk07d7e6b2004-12-16 21:44:03 +0000660 if (found == -1) {
stroese15be8132004-12-16 17:26:24 +0000661 break;
662 }
663
664 /* Read in the symlink and follow it. */
wdenk07d7e6b2004-12-16 21:44:03 +0000665 if (type == FILETYPE_SYMLINK) {
stroese15be8132004-12-16 17:26:24 +0000666 char *symlink;
667
668 /* Test if the symlink does not loop. */
wdenk07d7e6b2004-12-16 21:44:03 +0000669 if (++symlinknest == 8) {
stroese15be8132004-12-16 17:26:24 +0000670 ext2fs_free_node (currnode, currroot);
wdenk07d7e6b2004-12-16 21:44:03 +0000671 ext2fs_free_node (oldnode, currroot);
672 return (0);
stroese15be8132004-12-16 17:26:24 +0000673 }
674
675 symlink = ext2fs_read_symlink (currnode);
676 ext2fs_free_node (currnode, currroot);
677
wdenk07d7e6b2004-12-16 21:44:03 +0000678 if (!symlink) {
stroese15be8132004-12-16 17:26:24 +0000679 ext2fs_free_node (oldnode, currroot);
wdenk07d7e6b2004-12-16 21:44:03 +0000680 return (0);
stroese15be8132004-12-16 17:26:24 +0000681 }
682#ifdef DEBUG
wdenk07d7e6b2004-12-16 21:44:03 +0000683 printf ("Got symlink >%s<\n", symlink);
stroese15be8132004-12-16 17:26:24 +0000684#endif /* of DEBUG */
685 /* The symlink is an absolute path, go back to the root inode. */
wdenk07d7e6b2004-12-16 21:44:03 +0000686 if (symlink[0] == '/') {
stroese15be8132004-12-16 17:26:24 +0000687 ext2fs_free_node (oldnode, currroot);
688 oldnode = &ext2fs_root->diropen;
689 }
690
691 /* Lookup the node the symlink points to. */
wdenk07d7e6b2004-12-16 21:44:03 +0000692 status = ext2fs_find_file1 (symlink, oldnode,
693 &currnode, &type);
stroese15be8132004-12-16 17:26:24 +0000694
695 free (symlink);
696
wdenk07d7e6b2004-12-16 21:44:03 +0000697 if (status == 0) {
stroese15be8132004-12-16 17:26:24 +0000698 ext2fs_free_node (oldnode, currroot);
wdenk07d7e6b2004-12-16 21:44:03 +0000699 return (0);
stroese15be8132004-12-16 17:26:24 +0000700 }
701 }
702
703 ext2fs_free_node (oldnode, currroot);
704
705 /* Found the node! */
wdenk07d7e6b2004-12-16 21:44:03 +0000706 if (!next || *next == '\0') {
stroese15be8132004-12-16 17:26:24 +0000707 *currfound = currnode;
708 *foundtype = type;
wdenk07d7e6b2004-12-16 21:44:03 +0000709 return (1);
stroese15be8132004-12-16 17:26:24 +0000710 }
711 name = next;
712 }
wdenk07d7e6b2004-12-16 21:44:03 +0000713 return (-1);
stroese15be8132004-12-16 17:26:24 +0000714}
715
716
717int ext2fs_find_file
wdenk07d7e6b2004-12-16 21:44:03 +0000718 (const char *path,
719 ext2fs_node_t rootnode, ext2fs_node_t * foundnode, int expecttype) {
stroese15be8132004-12-16 17:26:24 +0000720 int status;
721 int foundtype = FILETYPE_DIRECTORY;
722
723
724 symlinknest = 0;
wdenkb7345fc2005-02-04 15:02:06 +0000725 if (!path) {
wdenk07d7e6b2004-12-16 21:44:03 +0000726 return (0);
stroese15be8132004-12-16 17:26:24 +0000727 }
728
wdenk07d7e6b2004-12-16 21:44:03 +0000729 status = ext2fs_find_file1 (path, rootnode, foundnode, &foundtype);
730 if (status == 0) {
731 return (0);
stroese15be8132004-12-16 17:26:24 +0000732 }
733 /* Check if the node that was found was of the expected type. */
wdenk07d7e6b2004-12-16 21:44:03 +0000734 if ((expecttype == FILETYPE_REG) && (foundtype != expecttype)) {
735 return (0);
736 } else if ((expecttype == FILETYPE_DIRECTORY)
737 && (foundtype != expecttype)) {
738 return (0);
stroese15be8132004-12-16 17:26:24 +0000739 }
wdenk07d7e6b2004-12-16 21:44:03 +0000740 return (1);
stroese15be8132004-12-16 17:26:24 +0000741}
742
743
wdenk07d7e6b2004-12-16 21:44:03 +0000744int ext2fs_ls (char *dirname) {
stroese15be8132004-12-16 17:26:24 +0000745 ext2fs_node_t dirnode;
wdenk07d7e6b2004-12-16 21:44:03 +0000746 int status;
stroese15be8132004-12-16 17:26:24 +0000747
wdenk07d7e6b2004-12-16 21:44:03 +0000748 if (ext2fs_root == NULL) {
749 return (0);
stroese15be8132004-12-16 17:26:24 +0000750 }
751
wdenk07d7e6b2004-12-16 21:44:03 +0000752 status = ext2fs_find_file (dirname, &ext2fs_root->diropen, &dirnode,
753 FILETYPE_DIRECTORY);
754 if (status != 1) {
755 printf ("** Can not find directory. **\n");
756 return (1);
757 }
758 ext2fs_iterate_dir (dirnode, NULL, NULL, NULL);
759 ext2fs_free_node (dirnode, &ext2fs_root->diropen);
760 return (0);
stroese15be8132004-12-16 17:26:24 +0000761}
762
763
wdenk07d7e6b2004-12-16 21:44:03 +0000764int ext2fs_open (char *filename) {
765 ext2fs_node_t fdiro = NULL;
766 int status;
767 int len;
stroese15be8132004-12-16 17:26:24 +0000768
wdenk07d7e6b2004-12-16 21:44:03 +0000769 if (ext2fs_root == NULL) {
wdenkb7345fc2005-02-04 15:02:06 +0000770 return (-1);
stroese15be8132004-12-16 17:26:24 +0000771 }
772 ext2fs_file = NULL;
wdenk07d7e6b2004-12-16 21:44:03 +0000773 status = ext2fs_find_file (filename, &ext2fs_root->diropen, &fdiro,
774 FILETYPE_REG);
775 if (status == 0) {
stroese15be8132004-12-16 17:26:24 +0000776 goto fail;
777 }
wdenk07d7e6b2004-12-16 21:44:03 +0000778 if (!fdiro->inode_read) {
779 status = ext2fs_read_inode (fdiro->data, fdiro->ino,
780 &fdiro->inode);
781 if (status == 0) {
stroese15be8132004-12-16 17:26:24 +0000782 goto fail;
783 }
784 }
785 len = __le32_to_cpu (fdiro->inode.size);
786 ext2fs_file = fdiro;
wdenk07d7e6b2004-12-16 21:44:03 +0000787 return (len);
stroese15be8132004-12-16 17:26:24 +0000788
wdenkb7345fc2005-02-04 15:02:06 +0000789fail:
wdenk07d7e6b2004-12-16 21:44:03 +0000790 ext2fs_free_node (fdiro, &ext2fs_root->diropen);
wdenkb7345fc2005-02-04 15:02:06 +0000791 return (-1);
stroese15be8132004-12-16 17:26:24 +0000792}
793
794
wdenk07d7e6b2004-12-16 21:44:03 +0000795int ext2fs_close (void
796 ) {
797 if ((ext2fs_file != NULL) && (ext2fs_root != NULL)) {
798 ext2fs_free_node (ext2fs_file, &ext2fs_root->diropen);
stroese15be8132004-12-16 17:26:24 +0000799 ext2fs_file = NULL;
800 }
wdenk07d7e6b2004-12-16 21:44:03 +0000801 if (ext2fs_root != NULL) {
802 free (ext2fs_root);
803 ext2fs_root = NULL;
stroese15be8132004-12-16 17:26:24 +0000804 }
wdenk07d7e6b2004-12-16 21:44:03 +0000805 if (indir1_block != NULL) {
806 free (indir1_block);
807 indir1_block = NULL;
808 indir1_size = 0;
809 indir1_blkno = -1;
stroese15be8132004-12-16 17:26:24 +0000810 }
wdenk07d7e6b2004-12-16 21:44:03 +0000811 if (indir2_block != NULL) {
812 free (indir2_block);
813 indir2_block = NULL;
814 indir2_size = 0;
815 indir2_blkno = -1;
stroese15be8132004-12-16 17:26:24 +0000816 }
wdenk07d7e6b2004-12-16 21:44:03 +0000817 return (0);
stroese15be8132004-12-16 17:26:24 +0000818}
819
820
wdenk07d7e6b2004-12-16 21:44:03 +0000821int ext2fs_read (char *buf, unsigned len) {
stroese15be8132004-12-16 17:26:24 +0000822 int status;
823
wdenk07d7e6b2004-12-16 21:44:03 +0000824 if (ext2fs_root == NULL) {
825 return (0);
stroese15be8132004-12-16 17:26:24 +0000826 }
827
wdenk07d7e6b2004-12-16 21:44:03 +0000828 if (ext2fs_file == NULL) {
829 return (0);
stroese15be8132004-12-16 17:26:24 +0000830 }
831
wdenk07d7e6b2004-12-16 21:44:03 +0000832 status = ext2fs_read_file (ext2fs_file, 0, len, buf);
833 return (status);
stroese15be8132004-12-16 17:26:24 +0000834}
835
836
wdenk07d7e6b2004-12-16 21:44:03 +0000837int ext2fs_mount (unsigned part_length) {
stroese15be8132004-12-16 17:26:24 +0000838 struct ext2_data *data;
wdenk07d7e6b2004-12-16 21:44:03 +0000839 int status;
stroese15be8132004-12-16 17:26:24 +0000840
841 data = malloc (sizeof (struct ext2_data));
wdenk07d7e6b2004-12-16 21:44:03 +0000842 if (!data) {
843 return (0);
stroese15be8132004-12-16 17:26:24 +0000844 }
845 /* Read the superblock. */
wdenk07d7e6b2004-12-16 21:44:03 +0000846 status = ext2fs_devread (1 * 2, 0, sizeof (struct ext2_sblock),
847 (char *) &data->sblock);
848 if (status == 0) {
stroese15be8132004-12-16 17:26:24 +0000849 goto fail;
850 }
851 /* Make sure this is an ext2 filesystem. */
wdenk07d7e6b2004-12-16 21:44:03 +0000852 if (__le16_to_cpu (data->sblock.magic) != EXT2_MAGIC) {
stroese15be8132004-12-16 17:26:24 +0000853 goto fail;
854 }
wdenk07d7e6b2004-12-16 21:44:03 +0000855 data->diropen.data = data;
856 data->diropen.ino = 2;
857 data->diropen.inode_read = 1;
858 data->inode = &data->diropen.inode;
stroese15be8132004-12-16 17:26:24 +0000859
860 status = ext2fs_read_inode (data, 2, data->inode);
wdenk07d7e6b2004-12-16 21:44:03 +0000861 if (status == 0) {
stroese15be8132004-12-16 17:26:24 +0000862 goto fail;
863 }
864
865 ext2fs_root = data;
866
wdenk07d7e6b2004-12-16 21:44:03 +0000867 return (1);
stroese15be8132004-12-16 17:26:24 +0000868
wdenk07d7e6b2004-12-16 21:44:03 +0000869fail:
870 printf ("Failed to mount ext2 filesystem...\n");
871 free (data);
stroese15be8132004-12-16 17:26:24 +0000872 ext2fs_root = NULL;
wdenk07d7e6b2004-12-16 21:44:03 +0000873 return (0);
stroese15be8132004-12-16 17:26:24 +0000874}