|
|
1.1 root 1: /*
2: *
3: * (c) 2008-2009 Laurent Vivier <[email protected]>
4: *
5: * This file has been copied from EMILE, http://emile.sf.net
6: *
7: */
8:
9: #include "libext2.h"
10: #include "ext2_utils.h"
11: #include "libopenbios/bindings.h"
12: #include "libc/diskio.h"
13: #include "libc/byteorder.h"
14:
15: int ext2_probe(int fd, long long offset)
16: {
17: struct ext2_super_block *super;
18:
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));
22:
23: if (__le16_to_cpu(super->s_magic) != EXT2_SUPER_MAGIC) {
24: free(super);
25: return 0;
26: }
27:
28: free(super);
29: return -1;
30: }
31:
32: void ext2_get_super(int fd, struct ext2_super_block *super)
33: {
34: seek_io(fd, 2 * 512);
35: read_io(fd, super, sizeof (*super));
36:
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);
80: }
81:
82: void ext2_read_block(ext2_VOLUME* volume, unsigned int fsblock)
83: {
84: long long offset;
85:
86: if (fsblock == volume->current)
87: return;
88:
89: volume->current = fsblock;
90: offset = fsblock * EXT2_BLOCK_SIZE(volume->super);
91:
92: seek_io(volume->fd, offset);
93: read_io(volume->fd, volume->buffer, EXT2_BLOCK_SIZE(volume->super));
94: }
95:
96: void ext2_get_group_desc(ext2_VOLUME* volume,
97: int group_id, struct ext2_group_desc *gdp)
98: {
99: unsigned int block, offset;
100: struct ext2_group_desc *le_gdp;
101:
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);
105:
106: offset = group_id % EXT2_DESC_PER_BLOCK(volume->super);
107: offset *= sizeof(*gdp);
108:
109: le_gdp = (struct ext2_group_desc *)(volume->buffer + offset);
110:
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);
117: }
118:
119: int ext2_get_inode(ext2_VOLUME* volume,
120: unsigned int ino, struct ext2_inode *inode)
121: {
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;
128:
129: ino--;
130:
131: group_id = ino / EXT2_INODES_PER_GROUP(volume->super);
132: ext2_get_group_desc(volume, group_id, &desc);
133:
134: ino %= EXT2_INODES_PER_GROUP(volume->super);
135:
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);
140:
141: offset = ino % (EXT2_BLOCK_SIZE(volume->super) /
142: EXT2_INODE_SIZE(volume->super));
143: offset *= EXT2_INODE_SIZE(volume->super);
144:
145: le_inode = (struct ext2_inode *)(volume->buffer + offset);
146:
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]);
163: }
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;
175: }
176:
177: unsigned int ext2_get_block_addr(ext2_VOLUME* volume, struct ext2_inode *inode,
178: unsigned int logical)
179: {
180: unsigned int physical;
181: unsigned int addr_per_block;
182:
183: /* direct */
184:
185: if (logical < EXT2_NDIR_BLOCKS) {
186: physical = inode->i_block[logical];
187: return physical;
188: }
189:
190: /* indirect */
191:
192: logical -= EXT2_NDIR_BLOCKS;
193:
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;
199: }
200:
201: /* double indirect */
202:
203: logical -= addr_per_block;
204:
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;
213: }
214:
215: /* triple indirect */
216:
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;
227: }
228:
229: int ext2_read_data(ext2_VOLUME* volume, struct ext2_inode *inode,
230: off_t offset, char *buffer, size_t length)
231: {
232: unsigned int logical, physical;
233: int blocksize = EXT2_BLOCK_SIZE(volume->super);
234: int shift;
235: size_t read;
236:
237: if (offset >= inode->i_size)
238: return -1;
239:
240: if (offset + length >= inode->i_size)
241: length = inode->i_size - offset;
242:
243: read = 0;
244: logical = offset / blocksize;
245: shift = offset % blocksize;
246:
247: if (shift) {
248: physical = ext2_get_block_addr(volume, inode, logical);
249: ext2_read_block(volume, physical);
250:
251: if (length < blocksize - shift) {
252: memcpy(buffer, volume->buffer + shift, length);
253: return length;
254: }
255: read += blocksize - shift;
256: memcpy(buffer, volume->buffer + shift, read);
257:
258: buffer += read;
259: length -= read;
260: logical++;
261: }
262:
263: while (length) {
264: physical = ext2_get_block_addr(volume, inode, logical);
265: ext2_read_block(volume, physical);
266:
267: if (length < blocksize) {
268: memcpy(buffer, volume->buffer, length);
269: read += length;
270: return read;
271: }
272: memcpy(buffer, volume->buffer, blocksize);
273:
274: buffer += blocksize;
275: length -= blocksize;
276: read += blocksize;
277: logical++;
278: }
279:
280: return read;
281: }
282:
283: off_t ext2_dir_entry(ext2_VOLUME *volume, struct ext2_inode *inode,
284: off_t index, struct ext2_dir_entry_2 *entry)
285: {
286: int ret;
287:
288: ret = ext2_read_data(volume, inode, index,
289: (char*)entry, sizeof(*entry));
290: if (ret == -1)
291: return -1;
292:
293: entry->inode = __le32_to_cpu(entry->inode);
294: entry->rec_len = __le16_to_cpu(entry->rec_len);
295: return index + entry->rec_len;
296: }
297:
298: unsigned int ext2_seek_name(ext2_VOLUME *volume, const char *name)
299: {
300: struct ext2_inode inode;
301: int ret;
302: unsigned int ino;
303: off_t index;
304: struct ext2_dir_entry_2 entry;
305:
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;
326: }
327: }
328: name += entry.name_len;
329: }
330:
331: return ino;
332: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.