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
;