~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/openbios/fs/ext2/ext2_utils.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 * (c) 2008-2009 Laurent Vivier <Laurent@lvivier.info>
 
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
}