3
* (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info>
5
* This file has been copied from EMILE, http://emile.sf.net
10
#include "ext2_utils.h"
11
#include "libopenbios/bindings.h"
12
#include "libc/diskio.h"
13
#include "libc/byteorder.h"
15
int ext2_probe(int fd, long long offset)
17
struct ext2_super_block *super;
19
super = (struct ext2_super_block*)malloc(sizeof(struct ext2_super_block));
20
seek_io(fd, 2 * 512 + offset);
21
read_io(fd, super, sizeof (*super));
23
if (__le16_to_cpu(super->s_magic) != EXT2_SUPER_MAGIC) {
32
void ext2_get_super(int fd, struct ext2_super_block *super)
35
read_io(fd, super, sizeof (*super));
37
super->s_inodes_count = __le32_to_cpu(super->s_inodes_count);
38
super->s_blocks_count = __le32_to_cpu(super->s_blocks_count);
39
super->s_r_blocks_count = __le32_to_cpu(super->s_r_blocks_count);
40
super->s_free_blocks_count = __le32_to_cpu(super->s_free_blocks_count);
41
super->s_free_inodes_count = __le32_to_cpu(super->s_free_inodes_count);
42
super->s_first_data_block = __le32_to_cpu(super->s_first_data_block);
43
super->s_log_block_size = __le32_to_cpu(super->s_log_block_size);
44
super->s_log_frag_size = __le32_to_cpu(super->s_log_frag_size);
45
super->s_blocks_per_group = __le32_to_cpu(super->s_blocks_per_group);
46
super->s_frags_per_group = __le32_to_cpu(super->s_frags_per_group);
47
super->s_inodes_per_group = __le32_to_cpu(super->s_inodes_per_group);
48
super->s_mtime = __le32_to_cpu(super->s_mtime);
49
super->s_wtime = __le32_to_cpu(super->s_wtime);
50
super->s_mnt_count = __le16_to_cpu(super->s_mnt_count);
51
super->s_max_mnt_count = __le16_to_cpu(super->s_max_mnt_count);
52
super->s_magic = __le16_to_cpu(super->s_magic);
53
super->s_state = __le16_to_cpu(super->s_state);
54
super->s_errors = __le16_to_cpu(super->s_errors);
55
super->s_minor_rev_level = __le16_to_cpu(super->s_minor_rev_level);
56
super->s_lastcheck = __le32_to_cpu(super->s_lastcheck);
57
super->s_checkinterval = __le32_to_cpu(super->s_checkinterval);
58
super->s_creator_os = __le32_to_cpu(super->s_creator_os);
59
super->s_rev_level = __le32_to_cpu(super->s_rev_level);
60
super->s_def_resuid = __le16_to_cpu(super->s_def_resuid);
61
super->s_def_resgid = __le16_to_cpu(super->s_def_resgid);
62
super->s_first_ino = __le32_to_cpu(super->s_first_ino);
63
super->s_inode_size = __le16_to_cpu(super->s_inode_size);
64
super->s_block_group_nr = __le16_to_cpu(super->s_block_group_nr);
65
super->s_feature_compat = __le32_to_cpu(super->s_feature_compat);
66
super->s_feature_incompat = __le32_to_cpu(super->s_feature_incompat);
67
super->s_feature_ro_compat = __le32_to_cpu(super->s_feature_ro_compat);
68
super->s_algorithm_usage_bitmap =
69
__le32_to_cpu(super->s_algorithm_usage_bitmap);
70
super->s_journal_inum = __le32_to_cpu(super->s_journal_inum);
71
super->s_journal_dev = __le32_to_cpu(super->s_journal_dev);
72
super->s_last_orphan = __le32_to_cpu(super->s_last_orphan);
73
super->s_hash_seed[0] = __le32_to_cpu(super->s_hash_seed[0]);
74
super->s_hash_seed[1] = __le32_to_cpu(super->s_hash_seed[1]);
75
super->s_hash_seed[2] = __le32_to_cpu(super->s_hash_seed[2]);
76
super->s_hash_seed[3] = __le32_to_cpu(super->s_hash_seed[3]);
77
super->s_default_mount_opts =
78
__le32_to_cpu(super->s_default_mount_opts);
79
super->s_first_meta_bg = __le32_to_cpu(super->s_first_meta_bg);
82
void ext2_read_block(ext2_VOLUME* volume, unsigned int fsblock)
86
if (fsblock == volume->current)
89
volume->current = fsblock;
90
offset = fsblock * EXT2_BLOCK_SIZE(volume->super);
92
seek_io(volume->fd, offset);
93
read_io(volume->fd, volume->buffer, EXT2_BLOCK_SIZE(volume->super));
96
void ext2_get_group_desc(ext2_VOLUME* volume,
97
int group_id, struct ext2_group_desc *gdp)
99
unsigned int block, offset;
100
struct ext2_group_desc *le_gdp;
102
block = 1 + volume->super->s_first_data_block;
103
block += group_id / EXT2_DESC_PER_BLOCK(volume->super);
104
ext2_read_block(volume, block);
106
offset = group_id % EXT2_DESC_PER_BLOCK(volume->super);
107
offset *= sizeof(*gdp);
109
le_gdp = (struct ext2_group_desc *)(volume->buffer + offset);
111
gdp->bg_block_bitmap = __le32_to_cpu(le_gdp->bg_block_bitmap);
112
gdp->bg_inode_bitmap = __le32_to_cpu(le_gdp->bg_inode_bitmap);
113
gdp->bg_inode_table = __le32_to_cpu(le_gdp->bg_inode_table);
114
gdp->bg_free_blocks_count = __le16_to_cpu(le_gdp->bg_free_blocks_count);
115
gdp->bg_free_inodes_count = __le16_to_cpu(le_gdp->bg_free_inodes_count);
116
gdp->bg_used_dirs_count = __le16_to_cpu(le_gdp->bg_used_dirs_count);
119
int ext2_get_inode(ext2_VOLUME* volume,
120
unsigned int ino, struct ext2_inode *inode)
122
struct ext2_group_desc desc;
124
unsigned int group_id;
126
struct ext2_inode *le_inode;
131
group_id = ino / EXT2_INODES_PER_GROUP(volume->super);
132
ext2_get_group_desc(volume, group_id, &desc);
134
ino %= EXT2_INODES_PER_GROUP(volume->super);
136
block = desc.bg_inode_table;
137
block += ino / (EXT2_BLOCK_SIZE(volume->super) /
138
EXT2_INODE_SIZE(volume->super));
139
ext2_read_block(volume, block);
141
offset = ino % (EXT2_BLOCK_SIZE(volume->super) /
142
EXT2_INODE_SIZE(volume->super));
143
offset *= EXT2_INODE_SIZE(volume->super);
145
le_inode = (struct ext2_inode *)(volume->buffer + offset);
147
inode->i_mode = __le16_to_cpu(le_inode->i_mode);
148
inode->i_uid = __le16_to_cpu(le_inode->i_uid);
149
inode->i_size = __le32_to_cpu(le_inode->i_size);
150
inode->i_atime = __le32_to_cpu(le_inode->i_atime);
151
inode->i_ctime = __le32_to_cpu(le_inode->i_ctime);
152
inode->i_mtime = __le32_to_cpu(le_inode->i_mtime);
153
inode->i_dtime = __le32_to_cpu(le_inode->i_dtime);
154
inode->i_gid = __le16_to_cpu(le_inode->i_gid);
155
inode->i_links_count = __le16_to_cpu(le_inode->i_links_count);
156
inode->i_blocks = __le32_to_cpu(le_inode->i_blocks);
157
inode->i_flags = __le32_to_cpu(le_inode->i_flags);
158
if (S_ISLNK(inode->i_mode)) {
159
memcpy(inode->i_block, le_inode->i_block, EXT2_N_BLOCKS * 4);
161
for (i = 0; i < EXT2_N_BLOCKS; i++)
162
inode->i_block[i] = __le32_to_cpu(le_inode->i_block[i]);
164
inode->i_generation = __le32_to_cpu(le_inode->i_generation);
165
inode->i_file_acl = __le32_to_cpu(le_inode->i_file_acl);
166
inode->i_dir_acl = __le32_to_cpu(le_inode->i_dir_acl);
167
inode->i_faddr = __le32_to_cpu(le_inode->i_faddr);
168
inode->osd2.linux2.l_i_frag = le_inode->osd2.linux2.l_i_frag;
169
inode->osd2.linux2.l_i_fsize = le_inode->osd2.linux2.l_i_fsize;
170
inode->osd2.linux2.l_i_uid_high =
171
__le16_to_cpu(le_inode->osd2.linux2.l_i_uid_high);
172
inode->osd2.linux2.l_i_gid_high =
173
__le16_to_cpu(le_inode->osd2.linux2.l_i_gid_high);
177
unsigned int ext2_get_block_addr(ext2_VOLUME* volume, struct ext2_inode *inode,
178
unsigned int logical)
180
unsigned int physical;
181
unsigned int addr_per_block;
185
if (logical < EXT2_NDIR_BLOCKS) {
186
physical = inode->i_block[logical];
192
logical -= EXT2_NDIR_BLOCKS;
194
addr_per_block = EXT2_ADDR_PER_BLOCK (volume->super);
195
if (logical < addr_per_block) {
196
ext2_read_block(volume, inode->i_block[EXT2_IND_BLOCK]);
197
physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical]);
201
/* double indirect */
203
logical -= addr_per_block;
205
if (logical < addr_per_block * addr_per_block) {
206
ext2_read_block(volume, inode->i_block[EXT2_DIND_BLOCK]);
207
physical = __le32_to_cpu(((unsigned int *)volume->buffer)
208
[logical / addr_per_block]);
209
ext2_read_block(volume, physical);
210
physical = __le32_to_cpu(((unsigned int *)volume->buffer)
211
[logical % addr_per_block]);
215
/* triple indirect */
217
logical -= addr_per_block * addr_per_block;
218
ext2_read_block(volume, inode->i_block[EXT2_DIND_BLOCK]);
219
physical = __le32_to_cpu(((unsigned int *)volume->buffer)
220
[logical / (addr_per_block * addr_per_block)]);
221
ext2_read_block(volume, physical);
222
logical = logical % (addr_per_block * addr_per_block);
223
physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical / addr_per_block]);
224
ext2_read_block(volume, physical);
225
physical = __le32_to_cpu(((unsigned int *)volume->buffer)[logical % addr_per_block]);
229
int ext2_read_data(ext2_VOLUME* volume, struct ext2_inode *inode,
230
off_t offset, char *buffer, size_t length)
232
unsigned int logical, physical;
233
int blocksize = EXT2_BLOCK_SIZE(volume->super);
237
if (offset >= inode->i_size)
240
if (offset + length >= inode->i_size)
241
length = inode->i_size - offset;
244
logical = offset / blocksize;
245
shift = offset % blocksize;
248
physical = ext2_get_block_addr(volume, inode, logical);
249
ext2_read_block(volume, physical);
251
if (length < blocksize - shift) {
252
memcpy(buffer, volume->buffer + shift, length);
255
read += blocksize - shift;
256
memcpy(buffer, volume->buffer + shift, read);
264
physical = ext2_get_block_addr(volume, inode, logical);
265
ext2_read_block(volume, physical);
267
if (length < blocksize) {
268
memcpy(buffer, volume->buffer, length);
272
memcpy(buffer, volume->buffer, blocksize);
283
off_t ext2_dir_entry(ext2_VOLUME *volume, struct ext2_inode *inode,
284
off_t index, struct ext2_dir_entry_2 *entry)
288
ret = ext2_read_data(volume, inode, index,
289
(char*)entry, sizeof(*entry));
293
entry->inode = __le32_to_cpu(entry->inode);
294
entry->rec_len = __le16_to_cpu(entry->rec_len);
295
return index + entry->rec_len;
298
unsigned int ext2_seek_name(ext2_VOLUME *volume, const char *name)
300
struct ext2_inode inode;
304
struct ext2_dir_entry_2 entry;
308
while (*name == '\\')
312
ret = ext2_get_inode(volume, ino, &inode);
317
index = ext2_dir_entry(volume, &inode, index, &entry);
320
ret = strncmp(name, entry.name, entry.name_len);
322
(name[entry.name_len] == 0 ||
323
name[entry.name_len] == '\\')) {
328
name += entry.name_len;