Disable mixing of DMA and FIFO messages in the Solaris ESP kernel module.
[openbios.git] / fs / ext2 / ext2_utils.c
blob64563c826806fcafcc4adc798ece698d31169475
1 /*
3 * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info>
5 * This file has been copied from EMILE, http://emile.sf.net
7 */
9 #include "libext2.h"
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) {
24 free(super);
25 return 0;
28 free(super);
29 return -1;
32 void ext2_get_super(int fd, struct ext2_super_block *super)
34 seek_io(fd, 2 * 512);
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)
84 long long offset;
86 if (fsblock == volume->current)
87 return;
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;
123 unsigned int block;
124 unsigned int group_id;
125 unsigned int offset;
126 struct ext2_inode *le_inode;
127 int i;
129 ino--;
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);
160 } else {
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);
174 return 0;
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;
183 /* direct */
185 if (logical < EXT2_NDIR_BLOCKS) {
186 physical = inode->i_block[logical];
187 return physical;
190 /* indirect */
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]);
198 return physical;
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]);
212 return physical;
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]);
226 return physical;
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);
234 int shift;
235 size_t read;
237 if (offset >= inode->i_size)
238 return -1;
240 if (offset + length >= inode->i_size)
241 length = inode->i_size - offset;
243 read = 0;
244 logical = offset / blocksize;
245 shift = offset % blocksize;
247 if (shift) {
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);
253 return length;
255 read += blocksize - shift;
256 memcpy(buffer, volume->buffer + shift, read);
258 buffer += read;
259 length -= read;
260 logical++;
263 while (length) {
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);
269 read += length;
270 return read;
272 memcpy(buffer, volume->buffer, blocksize);
274 buffer += blocksize;
275 length -= blocksize;
276 read += blocksize;
277 logical++;
280 return read;
283 off_t ext2_dir_entry(ext2_VOLUME *volume, struct ext2_inode *inode,
284 off_t index, struct ext2_dir_entry_2 *entry)
286 int ret;
288 ret = ext2_read_data(volume, inode, index,
289 (char*)entry, sizeof(*entry));
290 if (ret == -1)
291 return -1;
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;
301 int ret;
302 unsigned int ino;
303 off_t index;
304 struct ext2_dir_entry_2 entry;
306 ino = EXT2_ROOT_INO;
307 while(1) {
308 while (*name == '\\')
309 name++;
310 if (!*name)
311 break;
312 ret = ext2_get_inode(volume, ino, &inode);
313 if (ret == -1)
314 return 0;
315 index = 0;
316 while (1) {
317 index = ext2_dir_entry(volume, &inode, index, &entry);
318 if (index == -1)
319 return 0;
320 ret = strncmp(name, entry.name, entry.name_len);
321 if (ret == 0 &&
322 (name[entry.name_len] == 0 ||
323 name[entry.name_len] == '\\')) {
324 ino = entry.inode;
325 break;
328 name += entry.name_len;
331 return ino;