~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to uspace/lib/ext2/libext2_superblock.c

  • Committer: Jakub Jermar
  • Date: 2011-06-02 21:26:44 UTC
  • mfrom: (720.2.82 ext2-merge)
  • Revision ID: jakub@jermar.eu-20110602212644-t5p3o4bux1n8ybvd
Merge from http://ho.st.dcs.fmph.uniba.sk/~mato/bzr/helenos-ext2.

Changes made against the ext2 branch parent:
- removed .bzrignore
- removed all traces of pipefs

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011 Martin Sucha
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * - Redistributions of source code must retain the above copyright
 
10
 *   notice, this list of conditions and the following disclaimer.
 
11
 * - Redistributions in binary form must reproduce the above copyright
 
12
 *   notice, this list of conditions and the following disclaimer in the
 
13
 *   documentation and/or other materials provided with the distribution.
 
14
 * - The name of the author may not be used to endorse or promote products
 
15
 *   derived from this software without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 */
 
28
 
 
29
/** @addtogroup libext2
 
30
 * @{
 
31
 */
 
32
/**
 
33
 * @file
 
34
 */
 
35
 
 
36
#include "libext2.h"
 
37
#include <errno.h>
 
38
#include <malloc.h>
 
39
#include <libblock.h>
 
40
#include <byteorder.h>
 
41
 
 
42
/**
 
43
 * Return a magic number from ext2 superblock, this should be equal to
 
44
 * EXT_SUPERBLOCK_MAGIC for valid ext2 superblock
 
45
 * 
 
46
 * @param sb pointer to superblock
 
47
 */
 
48
uint16_t ext2_superblock_get_magic(ext2_superblock_t *sb)
 
49
{
 
50
        return uint16_t_le2host(sb->magic);
 
51
}
 
52
 
 
53
/**
 
54
 * Get the position of first ext2 data block (i.e. the block number
 
55
 * containing main superblock)
 
56
 * 
 
57
 * @param sb pointer to superblock
 
58
 */
 
59
uint32_t ext2_superblock_get_first_block(ext2_superblock_t *sb)
 
60
{
 
61
        return uint32_t_le2host(sb->first_block);
 
62
}
 
63
 
 
64
/**
 
65
 * Get the number of bits to shift a value of 1024 to the left necessary
 
66
 * to get the size of a block
 
67
 * 
 
68
 * @param sb pointer to superblock
 
69
 */
 
70
uint32_t ext2_superblock_get_block_size_log2(ext2_superblock_t *sb)
 
71
{
 
72
        return uint32_t_le2host(sb->block_size_log2);
 
73
}
 
74
 
 
75
/**
 
76
 * Get the size of a block, in bytes 
 
77
 * 
 
78
 * @param sb pointer to superblock
 
79
 */
 
80
uint32_t ext2_superblock_get_block_size(ext2_superblock_t *sb)
 
81
{
 
82
        return 1024 << ext2_superblock_get_block_size_log2(sb);
 
83
}
 
84
 
 
85
/**
 
86
 * Get the number of bits to shift a value of 1024 to the left necessary
 
87
 * to get the size of a fragment (note that this is a signed integer and
 
88
 * if negative, the value should be shifted to the right instead)
 
89
 * 
 
90
 * @param sb pointer to superblock
 
91
 */
 
92
int32_t ext2_superblock_get_fragment_size_log2(ext2_superblock_t *sb)
 
93
{
 
94
        return uint32_t_le2host(sb->fragment_size_log2);
 
95
}
 
96
 
 
97
/**
 
98
 * Get the size of a fragment, in bytes 
 
99
 * 
 
100
 * @param sb pointer to superblock
 
101
 */
 
102
uint32_t ext2_superblock_get_fragment_size(ext2_superblock_t *sb)
 
103
{
 
104
        int32_t log = ext2_superblock_get_fragment_size_log2(sb);
 
105
        if (log >= 0) {
 
106
                return 1024 << log;
 
107
        }
 
108
        else {
 
109
                return 1024 >> -log;
 
110
        }
 
111
}
 
112
 
 
113
/**
 
114
 * Get number of blocks per block group
 
115
 * 
 
116
 * @param sb pointer to superblock
 
117
 */
 
118
uint32_t ext2_superblock_get_blocks_per_group(ext2_superblock_t *sb)
 
119
{
 
120
        return uint32_t_le2host(sb->blocks_per_group);
 
121
}
 
122
 
 
123
/**
 
124
 * Get number of fragments per block group
 
125
 * 
 
126
 * @param sb pointer to superblock
 
127
 */
 
128
uint32_t ext2_superblock_get_fragments_per_group(ext2_superblock_t *sb)
 
129
{
 
130
        return uint32_t_le2host(sb->fragments_per_group);
 
131
}
 
132
 
 
133
/**
 
134
 * Get filesystem state
 
135
 * 
 
136
 * @param sb pointer to superblock
 
137
 */
 
138
uint16_t ext2_superblock_get_state(ext2_superblock_t *sb)
 
139
{
 
140
        return uint16_t_le2host(sb->state);
 
141
}
 
142
 
 
143
/**
 
144
 * Get minor revision number
 
145
 * 
 
146
 * @param sb pointer to superblock
 
147
 */
 
148
uint16_t ext2_superblock_get_rev_minor(ext2_superblock_t *sb)
 
149
{
 
150
        return uint16_t_le2host(sb->rev_minor);
 
151
}
 
152
 
 
153
/**
 
154
 * Get major revision number
 
155
 * 
 
156
 * @param sb pointer to superblock
 
157
 */
 
158
uint32_t ext2_superblock_get_rev_major(ext2_superblock_t *sb)
 
159
{
 
160
        return uint32_t_le2host(sb->rev_major);
 
161
}
 
162
 
 
163
/**
 
164
 * Get index of first regular inode
 
165
 * 
 
166
 * @param sb pointer to superblock
 
167
 */
 
168
uint32_t ext2_superblock_get_first_inode(ext2_superblock_t *sb)
 
169
{
 
170
        if (ext2_superblock_get_rev_major(sb) == 0) {
 
171
                return EXT2_REV0_FIRST_INODE;
 
172
        }
 
173
        return uint32_t_le2host(sb->first_inode);
 
174
}
 
175
 
 
176
/**
 
177
 * Get size of inode
 
178
 * 
 
179
 * @param sb pointer to superblock
 
180
 */
 
181
uint16_t ext2_superblock_get_inode_size(ext2_superblock_t *sb)
 
182
{
 
183
        if (ext2_superblock_get_rev_major(sb) == 0) {
 
184
                return EXT2_REV0_INODE_SIZE;
 
185
        }
 
186
        return uint32_t_le2host(sb->inode_size);
 
187
}
 
188
 
 
189
/**
 
190
 * Get total inode count
 
191
 * 
 
192
 * @param sb pointer to superblock
 
193
 */
 
194
uint32_t ext2_superblock_get_total_inode_count(ext2_superblock_t *sb)
 
195
{
 
196
        return uint32_t_le2host(sb->total_inode_count);
 
197
}
 
198
 
 
199
/**
 
200
 * Get total block count
 
201
 * 
 
202
 * @param sb pointer to superblock
 
203
 */
 
204
uint32_t ext2_superblock_get_total_block_count(ext2_superblock_t *sb)
 
205
{
 
206
        return uint32_t_le2host(sb->total_block_count);
 
207
}
 
208
 
 
209
/**
 
210
 * Get amount of blocks reserved for the superuser
 
211
 * 
 
212
 * @param sb pointer to superblock
 
213
 */
 
214
uint32_t ext2_superblock_get_reserved_block_count(ext2_superblock_t *sb)
 
215
{
 
216
        return uint32_t_le2host(sb->reserved_block_count);
 
217
}
 
218
 
 
219
/**
 
220
 * Get amount of free blocks
 
221
 * 
 
222
 * @param sb pointer to superblock
 
223
 */
 
224
uint32_t ext2_superblock_get_free_block_count(ext2_superblock_t *sb)
 
225
{
 
226
        return uint32_t_le2host(sb->free_block_count);
 
227
}
 
228
 
 
229
/**
 
230
 * Get amount of free inodes
 
231
 * 
 
232
 * @param sb pointer to superblock
 
233
 */
 
234
uint32_t ext2_superblock_get_free_inode_count(ext2_superblock_t *sb)
 
235
{
 
236
        return uint32_t_le2host(sb->free_inode_count);
 
237
}
 
238
 
 
239
/**
 
240
 * Get id of operating system that created the filesystem
 
241
 * 
 
242
 * @param sb pointer to superblock
 
243
 */
 
244
uint32_t ext2_superblock_get_os(ext2_superblock_t *sb)
 
245
{
 
246
        return uint32_t_le2host(sb->os);
 
247
}
 
248
 
 
249
/**
 
250
 * Get count of inodes per block group
 
251
 * 
 
252
 * @param sb pointer to superblock
 
253
 */
 
254
uint32_t ext2_superblock_get_inodes_per_group(ext2_superblock_t *sb)
 
255
{
 
256
        return uint32_t_le2host(sb->inodes_per_group);
 
257
}
 
258
 
 
259
/**
 
260
 * Get compatible features flags
 
261
 * 
 
262
 * @param sb pointer to superblock
 
263
 */
 
264
uint32_t ext2_superblock_get_features_compatible(ext2_superblock_t *sb)
 
265
{
 
266
        return uint32_t_le2host(sb->features_compatible);
 
267
}
 
268
 
 
269
/**
 
270
 * Get incompatible features flags
 
271
 * 
 
272
 * @param sb pointer to superblock
 
273
 */
 
274
uint32_t ext2_superblock_get_features_incompatible(ext2_superblock_t *sb)
 
275
{
 
276
        return uint32_t_le2host(sb->features_incompatible);
 
277
}
 
278
 
 
279
/**
 
280
 * Get read-only compatible features flags
 
281
 * 
 
282
 * @param sb pointer to superblock
 
283
 */
 
284
uint32_t ext2_superblock_get_features_read_only(ext2_superblock_t *sb)
 
285
{
 
286
        return uint32_t_le2host(sb->features_read_only);
 
287
}
 
288
 
 
289
/**
 
290
 * Compute count of block groups present in the filesystem
 
291
 * 
 
292
 * Note: This function works only for correct filesystem,
 
293
 *       i.e. it assumes that total block count > 0 and
 
294
 *       blocks per group > 0
 
295
 * 
 
296
 * Example:
 
297
 *   If there are 3 blocks per group, the result should be as follows:
 
298
 *   Total blocks       Result
 
299
 *   1                          1
 
300
 *   2                          1
 
301
 *   3                          1
 
302
 *   4                          2
 
303
 * 
 
304
 * 
 
305
 * @param sb pointer to superblock
 
306
 */
 
307
uint32_t ext2_superblock_get_block_group_count(ext2_superblock_t *sb)
 
308
{
 
309
        /* We add one to the result because e.g. 2/3 = 0, while to store
 
310
         *  2 blocks in 3-block group we need one (1) block group
 
311
         * 
 
312
         * We subtract one first because of special case that to store e.g.
 
313
         *  3 blocks in a 3-block group we need only one group
 
314
         *  (and 3/3 yields one - this is one more that we want as we
 
315
         *   already add one at the end)
 
316
         */ 
 
317
        return ((ext2_superblock_get_total_block_count(sb)-1) / 
 
318
            ext2_superblock_get_blocks_per_group(sb))+1;
 
319
}
 
320
 
 
321
/** Read a superblock directly from device (i.e. no libblock cache)
 
322
 * 
 
323
 * @param devmap_handle Device handle of the block device.
 
324
 * @param superblock    Pointer where to store pointer to new superblock
 
325
 * 
 
326
 * @return              EOK on success or negative error code on failure.
 
327
 */
 
328
int ext2_superblock_read_direct(devmap_handle_t devmap_handle,
 
329
    ext2_superblock_t **superblock)
 
330
{
 
331
        void *data;
 
332
        int rc;
 
333
        
 
334
        data = malloc(EXT2_SUPERBLOCK_SIZE);
 
335
        if (data == NULL) {
 
336
                return ENOMEM;
 
337
        }
 
338
        
 
339
        rc = block_read_bytes_direct(devmap_handle, EXT2_SUPERBLOCK_OFFSET,
 
340
            EXT2_SUPERBLOCK_SIZE, data);
 
341
        if (rc != EOK) {
 
342
                free(data);
 
343
                return rc;
 
344
        }
 
345
        
 
346
        (*superblock) = data;
 
347
        return EOK;
 
348
}
 
349
 
 
350
/** Check a superblock for sanity
 
351
 * 
 
352
 * @param sb    Pointer to superblock
 
353
 * 
 
354
 * @return              EOK on success or negative error code on failure.
 
355
 */
 
356
int ext2_superblock_check_sanity(ext2_superblock_t *sb)
 
357
{
 
358
        if (ext2_superblock_get_magic(sb) != EXT2_SUPERBLOCK_MAGIC) {
 
359
                return ENOTSUP;
 
360
        }
 
361
        
 
362
        if (ext2_superblock_get_rev_major(sb) > 1) {
 
363
                return ENOTSUP;
 
364
        }
 
365
        
 
366
        if (ext2_superblock_get_total_inode_count(sb) == 0) {
 
367
                return ENOTSUP;
 
368
        }
 
369
        
 
370
        if (ext2_superblock_get_total_block_count(sb) == 0) {
 
371
                return ENOTSUP;
 
372
        }
 
373
        
 
374
        if (ext2_superblock_get_blocks_per_group(sb) == 0) {
 
375
                return ENOTSUP;
 
376
        }
 
377
        
 
378
        if (ext2_superblock_get_fragments_per_group(sb) == 0) {
 
379
                return ENOTSUP;
 
380
        }
 
381
        
 
382
        /* We don't support fragments smaller than block */
 
383
        if (ext2_superblock_get_block_size(sb) != 
 
384
                    ext2_superblock_get_fragment_size(sb)) {
 
385
                return ENOTSUP;
 
386
        }
 
387
        if (ext2_superblock_get_blocks_per_group(sb) !=
 
388
                    ext2_superblock_get_fragments_per_group(sb)) {
 
389
                return ENOTSUP;
 
390
        }
 
391
        
 
392
        if (ext2_superblock_get_inodes_per_group(sb) == 0) {
 
393
                return ENOTSUP;
 
394
        }
 
395
        
 
396
        if (ext2_superblock_get_inode_size(sb) < 128) {
 
397
                return ENOTSUP;
 
398
        }
 
399
        
 
400
        if (ext2_superblock_get_first_inode(sb) < 11) {
 
401
                return ENOTSUP;
 
402
        }
 
403
        
 
404
        return EOK;
 
405
}
 
406
 
 
407
 
 
408
/** @}
 
409
 */