source: mainline/uspace/lib/ext2/libext2_superblock.c@ cf9cb36

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since cf9cb36 was 15f3c3f, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Rename devmap to loc, devfs to locfs.

  • Property mode set to 100644
File size: 9.5 KB
RevLine 
[36bca8eb]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"
[e272949]37#include <errno.h>
38#include <malloc.h>
39#include <libblock.h>
[3949e8a0]40#include <byteorder.h>
[36bca8eb]41
42/**
43 * Return a magic number from ext2 superblock, this should be equal to
44 * EXT_SUPERBLOCK_MAGIC for valid ext2 superblock
[566c401]45 *
46 * @param sb pointer to superblock
[36bca8eb]47 */
[18626b3]48uint16_t ext2_superblock_get_magic(ext2_superblock_t *sb)
[566c401]49{
[36bca8eb]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)
[566c401]56 *
57 * @param sb pointer to superblock
[36bca8eb]58 */
[18626b3]59uint32_t ext2_superblock_get_first_block(ext2_superblock_t *sb)
[566c401]60{
[36bca8eb]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
[566c401]67 *
68 * @param sb pointer to superblock
[36bca8eb]69 */
[18626b3]70uint32_t ext2_superblock_get_block_size_log2(ext2_superblock_t *sb)
[566c401]71{
[36bca8eb]72 return uint32_t_le2host(sb->block_size_log2);
73}
74
75/**
76 * Get the size of a block, in bytes
[566c401]77 *
78 * @param sb pointer to superblock
[36bca8eb]79 */
[18626b3]80uint32_t ext2_superblock_get_block_size(ext2_superblock_t *sb)
[566c401]81{
[8bd5dad]82 return 1024 << ext2_superblock_get_block_size_log2(sb);
[36bca8eb]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)
[566c401]89 *
90 * @param sb pointer to superblock
[36bca8eb]91 */
[18626b3]92int32_t ext2_superblock_get_fragment_size_log2(ext2_superblock_t *sb)
[566c401]93{
[36bca8eb]94 return uint32_t_le2host(sb->fragment_size_log2);
95}
96
97/**
98 * Get the size of a fragment, in bytes
[566c401]99 *
100 * @param sb pointer to superblock
[36bca8eb]101 */
[18626b3]102uint32_t ext2_superblock_get_fragment_size(ext2_superblock_t *sb)
[566c401]103{
[36bca8eb]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
[566c401]115 *
116 * @param sb pointer to superblock
[36bca8eb]117 */
[18626b3]118uint32_t ext2_superblock_get_blocks_per_group(ext2_superblock_t *sb)
[566c401]119{
[36bca8eb]120 return uint32_t_le2host(sb->blocks_per_group);
121}
122
123/**
124 * Get number of fragments per block group
[566c401]125 *
126 * @param sb pointer to superblock
[36bca8eb]127 */
[18626b3]128uint32_t ext2_superblock_get_fragments_per_group(ext2_superblock_t *sb)
[566c401]129{
[36bca8eb]130 return uint32_t_le2host(sb->fragments_per_group);
131}
132
[c00e729]133/**
134 * Get filesystem state
135 *
136 * @param sb pointer to superblock
137 */
[18626b3]138uint16_t ext2_superblock_get_state(ext2_superblock_t *sb)
[c00e729]139{
140 return uint16_t_le2host(sb->state);
141}
142
143/**
144 * Get minor revision number
145 *
146 * @param sb pointer to superblock
147 */
[18626b3]148uint16_t ext2_superblock_get_rev_minor(ext2_superblock_t *sb)
[c00e729]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 */
[18626b3]158uint32_t ext2_superblock_get_rev_major(ext2_superblock_t *sb)
[c00e729]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 */
[18626b3]168uint32_t ext2_superblock_get_first_inode(ext2_superblock_t *sb)
[c00e729]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 */
[18626b3]181uint16_t ext2_superblock_get_inode_size(ext2_superblock_t *sb)
[c00e729]182{
183 if (ext2_superblock_get_rev_major(sb) == 0) {
184 return EXT2_REV0_INODE_SIZE;
185 }
[82a3b31f]186 return uint16_t_le2host(sb->inode_size);
[c00e729]187}
188
[f6fa2c2]189/**
190 * Get total inode count
191 *
192 * @param sb pointer to superblock
193 */
[18626b3]194uint32_t ext2_superblock_get_total_inode_count(ext2_superblock_t *sb)
[f6fa2c2]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 */
[18626b3]204uint32_t ext2_superblock_get_total_block_count(ext2_superblock_t *sb)
[f6fa2c2]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 */
[18626b3]214uint32_t ext2_superblock_get_reserved_block_count(ext2_superblock_t *sb)
[f6fa2c2]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 */
[18626b3]224uint32_t ext2_superblock_get_free_block_count(ext2_superblock_t *sb)
[f6fa2c2]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 */
[18626b3]234uint32_t ext2_superblock_get_free_inode_count(ext2_superblock_t *sb)
[f6fa2c2]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 */
[18626b3]244uint32_t ext2_superblock_get_os(ext2_superblock_t *sb)
[f6fa2c2]245{
246 return uint32_t_le2host(sb->os);
247}
[36bca8eb]248
[1d6f507]249/**
250 * Get count of inodes per block group
251 *
252 * @param sb pointer to superblock
253 */
[18626b3]254uint32_t ext2_superblock_get_inodes_per_group(ext2_superblock_t *sb)
[1d6f507]255{
256 return uint32_t_le2host(sb->inodes_per_group);
257}
258
[eef306c]259/**
260 * Get compatible features flags
261 *
262 * @param sb pointer to superblock
263 */
[18626b3]264uint32_t ext2_superblock_get_features_compatible(ext2_superblock_t *sb)
[eef306c]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 */
[18626b3]274uint32_t ext2_superblock_get_features_incompatible(ext2_superblock_t *sb)
[eef306c]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 */
[18626b3]284uint32_t ext2_superblock_get_features_read_only(ext2_superblock_t *sb)
[eef306c]285{
286 return uint32_t_le2host(sb->features_read_only);
287}
288
[1d6f507]289/**
290 * Compute count of block groups present in the filesystem
291 *
[d241aae]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 *
[1d6f507]305 * @param sb pointer to superblock
306 */
[18626b3]307uint32_t ext2_superblock_get_block_group_count(ext2_superblock_t *sb)
[1d6f507]308{
[d241aae]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;
[1d6f507]319}
320
[e272949]321/** Read a superblock directly from device (i.e. no libblock cache)
322 *
[15f3c3f]323 * @param service_id Service ID of the block device.
[e272949]324 * @param superblock Pointer where to store pointer to new superblock
325 *
326 * @return EOK on success or negative error code on failure.
327 */
[15f3c3f]328int ext2_superblock_read_direct(service_id_t service_id,
[e272949]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
[15f3c3f]339 rc = block_read_bytes_direct(service_id, EXT2_SUPERBLOCK_OFFSET,
[e272949]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
[1d6f507]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 */
356int 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
[9bd5746]382 /* We don't support fragments smaller than block */
[1d6f507]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
[e272949]407
[36bca8eb]408/** @}
409 */
Note: See TracBrowser for help on using the repository browser.