source: mainline/uspace/lib/ext2/libext2_superblock.c@ 18626b3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 18626b3 was 18626b3, checked in by Martin Sucha <sucha14@…>, 14 years ago

Fix usage of inline/extern in in libext2

  • Property mode set to 100644
File size: 9.5 KB
Line 
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 */
48uint16_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 */
59uint32_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 */
70uint32_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 */
80uint32_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 */
92int32_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 */
102uint32_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 */
118uint32_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 */
128uint32_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 */
138uint16_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 */
148uint16_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 */
158uint32_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 */
168uint32_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 */
181uint16_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 */
194uint32_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 */
204uint32_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 */
214uint32_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 */
224uint32_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 */
234uint32_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 */
244uint32_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 */
254uint32_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 */
264uint32_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 */
274uint32_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 */
284uint32_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 */
307uint32_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 */
328int 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 */
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
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 */
Note: See TracBrowser for help on using the repository browser.